diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-04-23 10:34:49 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-05-04 20:05:08 +0000 |
commit | 830c9e163d31a9180fadca926b3e1d7dfffb5021 (patch) | |
tree | 1b96d45c67492b297e725932935d96d6efc91f37 /chromium/gpu | |
parent | 818d9aed569afd192f6d4f6d9b28b72912df8b93 (diff) | |
download | qtwebengine-chromium-830c9e163d31a9180fadca926b3e1d7dfffb5021.tar.gz |
BASELINE: Update Chromium to 65.0.3325.230
Change-Id: Ied18ccfc9872b6a5c441218dec17debf93732ea1
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'chromium/gpu')
4 files changed, 175 insertions, 61 deletions
diff --git a/chromium/gpu/command_buffer/service/sync_point_manager.cc b/chromium/gpu/command_buffer/service/sync_point_manager.cc index a3c4bf152e0..7fdf99e7e13 100644 --- a/chromium/gpu/command_buffer/service/sync_point_manager.cc +++ b/chromium/gpu/command_buffer/service/sync_point_manager.cc @@ -72,8 +72,9 @@ void SyncPointOrderData::Destroy() { uint32_t SyncPointOrderData::GenerateUnprocessedOrderNumber() { base::AutoLock auto_lock(lock_); DCHECK(!destroyed_); - unprocessed_order_num_ = sync_point_manager_->GenerateOrderNumber(); - return unprocessed_order_num_; + last_unprocessed_order_num_ = sync_point_manager_->GenerateOrderNumber(); + unprocessed_order_nums_.push(last_unprocessed_order_num_); + return last_unprocessed_order_num_; } void SyncPointOrderData::BeginProcessingOrderNumber(uint32_t order_num) { @@ -85,29 +86,6 @@ void SyncPointOrderData::BeginProcessingOrderNumber(uint32_t order_num) { DCHECK_LE(order_num, unprocessed_order_num()); current_order_num_ = order_num; paused_ = false; - - // Catch invalid waits which were waiting on fence syncs that do not exist. - // When we begin processing an order number, we should release any fence - // syncs which were enqueued but the order number never existed. - // Release without the lock to avoid possible deadlocks. - std::vector<OrderFence> ensure_releases; - { - base::AutoLock auto_lock(lock_); - while (!order_fence_queue_.empty()) { - const OrderFence& order_fence = order_fence_queue_.top(); - if (order_fence_queue_.top().order_num < order_num) { - ensure_releases.push_back(order_fence); - order_fence_queue_.pop(); - continue; - } - break; - } - } - - for (OrderFence& order_fence : ensure_releases) { - order_fence.client_state->EnsureWaitReleased(order_fence.fence_release, - order_fence.release_callback); - } } void SyncPointOrderData::PauseProcessingOrderNumber(uint32_t order_num) { @@ -132,9 +110,20 @@ void SyncPointOrderData::FinishProcessingOrderNumber(uint32_t order_num) { DCHECK_GT(order_num, processed_order_num_); processed_order_num_ = order_num; + DCHECK(!unprocessed_order_nums_.empty()); + DCHECK_EQ(order_num, unprocessed_order_nums_.front()); + unprocessed_order_nums_.pop(); + + uint32_t next_order_num = 0; + if (!unprocessed_order_nums_.empty()) + next_order_num = unprocessed_order_nums_.front(); + while (!order_fence_queue_.empty()) { const OrderFence& order_fence = order_fence_queue_.top(); - if (order_fence_queue_.top().order_num <= order_num) { + // It's possible for the fence's order number to equal next order number. + // This happens when the wait was enqueued with an order number greater + // than the last unprocessed order number. So don't release the fence yet. + if (!next_order_num || order_fence.order_num < next_order_num) { ensure_releases.push_back(order_fence); order_fence_queue_.pop(); continue; @@ -144,6 +133,7 @@ void SyncPointOrderData::FinishProcessingOrderNumber(uint32_t order_num) { } for (OrderFence& order_fence : ensure_releases) { + DLOG(ERROR) << "Client did not release sync token as expected"; order_fence.client_state->EnsureWaitReleased(order_fence.fence_release, order_fence.release_callback); } @@ -158,19 +148,22 @@ bool SyncPointOrderData::ValidateReleaseOrderNumber( if (destroyed_) return false; - // Release should have a possible unprocessed order number lower than the wait - // order number. - if ((processed_order_num_ + 1) >= wait_order_num) + // We should have unprocessed order numbers which could potentially release + // this fence. + if (unprocessed_order_nums_.empty()) return false; - // Release should have more unprocessed numbers if we are waiting. - if (unprocessed_order_num_ <= processed_order_num_) + // We should have an unprocessed order number lower than the wait order + // number for the wait to be valid. It's not possible for wait order number to + // equal next unprocessed order number, but we handle that defensively. + DCHECK_NE(wait_order_num, unprocessed_order_nums_.front()); + if (wait_order_num <= unprocessed_order_nums_.front()) return false; // So far it could be valid, but add an order fence guard to be sure it // gets released eventually. uint32_t expected_order_num = - std::min(unprocessed_order_num_, wait_order_num); + std::min(unprocessed_order_nums_.back(), wait_order_num); order_fence_queue_.push(OrderFence(expected_order_num, fence_release, release_callback, std::move(client_state))); @@ -237,17 +230,20 @@ bool SyncPointClientState::WaitForRelease(uint64_t release, const base::Closure& callback) { // Lock must be held the whole time while we validate otherwise it could be // released while we are checking. - { - base::AutoLock auto_lock(fence_sync_lock_); - if (release > fence_sync_release_ && - order_data_->ValidateReleaseOrderNumber(this, wait_order_num, release, - callback)) { - // Add the callback which will be called upon release. - release_callback_queue_.push(ReleaseCallback(release, callback)); - return true; - } - } + base::AutoLock auto_lock(fence_sync_lock_); + // Already released, do not run the callback. + if (release <= fence_sync_release_) + return false; + + if (order_data_->ValidateReleaseOrderNumber(this, wait_order_num, release, + callback)) { + // Add the callback which will be called upon release. + release_callback_queue_.push(ReleaseCallback(release, callback)); + return true; + } + + DLOG(ERROR) << "Client waiting on non-existent sync token"; return false; } diff --git a/chromium/gpu/command_buffer/service/sync_point_manager.h b/chromium/gpu/command_buffer/service/sync_point_manager.h index be8e510d30f..ca5c4c95583 100644 --- a/chromium/gpu/command_buffer/service/sync_point_manager.h +++ b/chromium/gpu/command_buffer/service/sync_point_manager.h @@ -51,7 +51,7 @@ class GPU_EXPORT SyncPointOrderData uint32_t unprocessed_order_num() const { base::AutoLock auto_lock(lock_); - return unprocessed_order_num_; + return last_unprocessed_order_num_; } uint32_t current_order_num() const { @@ -122,9 +122,7 @@ class GPU_EXPORT SyncPointOrderData bool paused_ = false; // This lock protects destroyed_, processed_order_num_, - // unprocessed_order_num_, and order_fence_queue_. All order numbers (n) in - // order_fence_queue_ must follow the invariant: - // processed_order_num_ < n <= unprocessed_order_num_. + // unprocessed_order_nums_, and order_fence_queue_. mutable base::Lock lock_; bool destroyed_ = false; @@ -132,8 +130,13 @@ class GPU_EXPORT SyncPointOrderData // Last finished IPC order number. uint32_t processed_order_num_ = 0; - // Unprocessed order number expected to be processed under normal execution. - uint32_t unprocessed_order_num_ = 0; + // Last unprocessed order number. Updated in GenerateUnprocessedOrderNumber. + uint32_t last_unprocessed_order_num_ = 0; + + // Queue of unprocessed order numbers. Order numbers are enqueued in + // GenerateUnprocessedOrderNumber, and dequeued in + // FinishProcessingOrderNumber. + std::queue<uint32_t> unprocessed_order_nums_; // In situations where we are waiting on fence syncs that do not exist, we // validate by making sure the order number does not pass the order number @@ -141,7 +144,9 @@ class GPU_EXPORT SyncPointOrderData // wait command's, we should automatically release up to the expected // release count. Note that this also releases other lower release counts, // so a single misbehaved fence sync is enough to invalidate/signal all - // previous fence syncs. + // previous fence syncs. All order numbers (n) in order_fence_queue_ must + // follow the invariant: + // unprocessed_order_nums_.front() < n <= unprocessed_order_nums_.back(). OrderFenceQueue order_fence_queue_; DISALLOW_COPY_AND_ASSIGN(SyncPointOrderData); diff --git a/chromium/gpu/command_buffer/service/sync_point_manager_unittest.cc b/chromium/gpu/command_buffer/service/sync_point_manager_unittest.cc index a72c48a504b..f926a747baf 100644 --- a/chromium/gpu/command_buffer/service/sync_point_manager_unittest.cc +++ b/chromium/gpu/command_buffer/service/sync_point_manager_unittest.cc @@ -431,26 +431,20 @@ TEST_F(SyncPointManagerTest, NonExistentOrderNumRelease) { EXPECT_TRUE(valid_wait); EXPECT_EQ(10, test_num); - // Release stream should know it should release fence sync by order [3], - // so going through order [1] should not release it yet. + // Release stream should know it should release fence sync by order [3], but + // it has no unprocessed order numbers less than 3, so it runs the callback. release_stream.BeginProcessing(); EXPECT_EQ(1u, release_stream.order_data->current_order_num()); release_stream.EndProcessing(); EXPECT_FALSE(sync_point_manager_->IsSyncTokenReleased(sync_token)); - EXPECT_EQ(10, test_num); - - // Beginning order [4] should immediately trigger the wait although the fence - // sync is still not released yet. - release_stream.BeginProcessing(); - EXPECT_EQ(4u, release_stream.order_data->current_order_num()); EXPECT_EQ(123, test_num); - EXPECT_FALSE(sync_point_manager_->IsSyncTokenReleased(sync_token)); // Ensure that the wait callback does not get triggered again when it is // actually released. - test_num = 1; + release_stream.BeginProcessing(); + test_num = 10; release_stream.client_state->ReleaseFenceSync(1); - EXPECT_EQ(1, test_num); + EXPECT_EQ(10, test_num); EXPECT_TRUE(sync_point_manager_->IsSyncTokenReleased(sync_token)); } @@ -480,4 +474,123 @@ TEST_F(SyncPointManagerTest, WaitOnSameSequenceFails) { EXPECT_FALSE(sync_point_manager_->IsSyncTokenReleased(sync_token)); } +TEST_F(SyncPointManagerTest, HandleInvalidWaitOrderNumber) { + CommandBufferNamespace kNamespaceId = gpu::CommandBufferNamespace::GPU_IO; + CommandBufferId kCmdBufferId1 = CommandBufferId::FromUnsafeValue(0x123); + CommandBufferId kCmdBufferId2 = CommandBufferId::FromUnsafeValue(0x234); + + SyncPointStream stream1(sync_point_manager_.get(), kNamespaceId, + kCmdBufferId1); + SyncPointStream stream2(sync_point_manager_.get(), kNamespaceId, + kCmdBufferId2); + + stream1.AllocateOrderNum(); // stream 1, order num 1 + stream2.AllocateOrderNum(); // stream 2, order num 2 + stream2.AllocateOrderNum(); // stream 2, order num 3 + stream1.AllocateOrderNum(); // stream 1, order num 4 + + // Run stream 1, order num 1. + stream1.BeginProcessing(); + stream1.EndProcessing(); + + // Stream 2 waits on stream 1 with order num 3. This wait is invalid because + // there's no unprocessed order num less than 3 on stream 1. + int test_num = 10; + bool valid_wait = sync_point_manager_->Wait( + SyncToken(kNamespaceId, kCmdBufferId1, 1), + stream2.order_data->sequence_id(), 3, + base::Bind(&SyncPointManagerTest::SetIntegerFunction, &test_num, 123)); + EXPECT_FALSE(valid_wait); + EXPECT_EQ(10, test_num); +} + +TEST_F(SyncPointManagerTest, RetireInvalidWaitAfterOrderNumberPasses) { + CommandBufferNamespace kNamespaceId = gpu::CommandBufferNamespace::GPU_IO; + CommandBufferId kCmdBufferId1 = CommandBufferId::FromUnsafeValue(0x123); + CommandBufferId kCmdBufferId2 = CommandBufferId::FromUnsafeValue(0x234); + + SyncPointStream stream1(sync_point_manager_.get(), kNamespaceId, + kCmdBufferId1); + SyncPointStream stream2(sync_point_manager_.get(), kNamespaceId, + kCmdBufferId2); + + stream1.AllocateOrderNum(); // stream 1, order num 1 + stream1.AllocateOrderNum(); // stream 1, order num 2 + stream2.AllocateOrderNum(); // stream 2, order num 3 + + // Stream 2 waits on stream 1 with order num 3. + int test_num = 10; + bool valid_wait = sync_point_manager_->Wait( + SyncToken(kNamespaceId, kCmdBufferId1, 1), + stream2.order_data->sequence_id(), 3, + base::Bind(&SyncPointManagerTest::SetIntegerFunction, &test_num, 123)); + EXPECT_TRUE(valid_wait); + EXPECT_EQ(10, test_num); + + stream1.AllocateOrderNum(); // stream 1, order num 4 + + // Run stream 1, order num 1. The wait isn't retired. + stream1.BeginProcessing(); + stream1.EndProcessing(); + EXPECT_EQ(10, test_num); + + // Run stream 1, order num 2. Wait is retired because we reach the last order + // number that was unprocessed at the time the wait was enqueued. + stream1.BeginProcessing(); + stream1.EndProcessing(); + EXPECT_EQ(123, test_num); +} + +TEST_F(SyncPointManagerTest, HandleInvalidCyclicWaits) { + CommandBufferNamespace kNamespaceId = gpu::CommandBufferNamespace::GPU_IO; + CommandBufferId kCmdBufferId1 = CommandBufferId::FromUnsafeValue(0x123); + CommandBufferId kCmdBufferId2 = CommandBufferId::FromUnsafeValue(0x234); + + SyncPointStream stream1(sync_point_manager_.get(), kNamespaceId, + kCmdBufferId1); + SyncPointStream stream2(sync_point_manager_.get(), kNamespaceId, + kCmdBufferId2); + + stream1.AllocateOrderNum(); // stream 1, order num 1 + stream2.AllocateOrderNum(); // stream 2, order num 2 + stream1.AllocateOrderNum(); // stream 1, order num 3 + stream2.AllocateOrderNum(); // stream 2, order num 4 + + // Stream 2 waits on stream 1 with order num 2. + int test_num1 = 10; + bool valid_wait = sync_point_manager_->Wait( + SyncToken(kNamespaceId, kCmdBufferId1, 1), + stream2.order_data->sequence_id(), 2, + base::Bind(&SyncPointManagerTest::SetIntegerFunction, &test_num1, 123)); + EXPECT_TRUE(valid_wait); + EXPECT_EQ(10, test_num1); + + // Stream 1 waits on stream 2 with order num 3. + int test_num2 = 10; + valid_wait = sync_point_manager_->Wait( + SyncToken(kNamespaceId, kCmdBufferId2, 1), + stream1.order_data->sequence_id(), 3, + base::Bind(&SyncPointManagerTest::SetIntegerFunction, &test_num2, 123)); + EXPECT_TRUE(valid_wait); + EXPECT_EQ(10, test_num2); + + // Run stream 1, order num 1. + stream1.BeginProcessing(); + stream1.EndProcessing(); + + // Since there's no unprocessed order num less than 2 on stream 1, the wait is + // released. + EXPECT_EQ(123, test_num1); + EXPECT_EQ(10, test_num2); + + // Run stream 2, order num 2. + stream2.BeginProcessing(); + stream2.EndProcessing(); + + // Since there's no unprocessed order num less than 3 on stream 2, the wait is + // released. + EXPECT_EQ(123, test_num1); + EXPECT_EQ(123, test_num2); +} + } // namespace gpu diff --git a/chromium/gpu/config/gpu_lists_version.h b/chromium/gpu/config/gpu_lists_version.h index 3d89bf18a19..2cc6499bd40 100644 --- a/chromium/gpu/config/gpu_lists_version.h +++ b/chromium/gpu/config/gpu_lists_version.h @@ -3,6 +3,6 @@ #ifndef GPU_CONFIG_GPU_LISTS_VERSION_H_ #define GPU_CONFIG_GPU_LISTS_VERSION_H_ -#define GPU_LISTS_VERSION "2b81d816997306dfdd0c2168d67028502f1cdee2" +#define GPU_LISTS_VERSION "926d27280b919a1aeb0091392d56f63a38d2bc0b" #endif // GPU_CONFIG_GPU_LISTS_VERSION_H_ |