| // Copyright (c) 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "gpu/command_buffer/client/client_discardable_manager.h" |
| #include "gpu/command_buffer/client/client_discardable_texture_manager.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace gpu { |
| namespace { |
| class FakeCommandBuffer : public CommandBuffer { |
| public: |
| FakeCommandBuffer() = default; |
| ~FakeCommandBuffer() override { EXPECT_TRUE(active_ids_.empty()); } |
| // Overridden from CommandBuffer: |
| State GetLastState() override { |
| NOTREACHED(); |
| return State(); |
| } |
| void Flush(int32_t put_offset) override { NOTREACHED(); } |
| void OrderingBarrier(int32_t put_offset) override { NOTREACHED(); } |
| State WaitForTokenInRange(int32_t start, int32_t end) override { |
| NOTREACHED(); |
| |
| return State(); |
| } |
| State WaitForGetOffsetInRange(uint32_t set_get_buffer_count, |
| int32_t start, |
| int32_t end) override { |
| NOTREACHED(); |
| return State(); |
| } |
| void SetGetBuffer(int32_t transfer_buffer_id) override { NOTREACHED(); } |
| scoped_refptr<gpu::Buffer> CreateTransferBuffer(uint32_t size, |
| int32_t* id) override { |
| *id = next_id_++; |
| active_ids_.insert(*id); |
| return MakeMemoryBuffer(size); |
| } |
| void DestroyTransferBuffer(int32_t id) override { |
| auto found = active_ids_.find(id); |
| EXPECT_TRUE(found != active_ids_.end()); |
| active_ids_.erase(found); |
| } |
| |
| private: |
| int32_t next_id_ = 1; |
| std::set<int32_t> active_ids_; |
| }; |
| |
| void UnlockClientHandleForTesting( |
| const ClientDiscardableHandle& client_handle) { |
| ServiceDiscardableHandle service_handle(client_handle.BufferForTesting(), |
| client_handle.byte_offset(), |
| client_handle.shm_id()); |
| service_handle.Unlock(); |
| } |
| |
| bool DeleteClientHandleForTesting( |
| const ClientDiscardableHandle& client_handle) { |
| ServiceDiscardableHandle service_handle(client_handle.BufferForTesting(), |
| client_handle.byte_offset(), |
| client_handle.shm_id()); |
| return service_handle.Delete(); |
| } |
| |
| void UnlockAndDeleteClientHandleForTesting( |
| const ClientDiscardableHandle& client_handle) { |
| UnlockClientHandleForTesting(client_handle); |
| EXPECT_TRUE(DeleteClientHandleForTesting(client_handle)); |
| } |
| |
| } // namespace |
| |
| TEST(ClientDiscardableManagerTest, BasicUsage) { |
| FakeCommandBuffer command_buffer; |
| ClientDiscardableManager manager; |
| ClientDiscardableHandle::Id handle_id = manager.CreateHandle(&command_buffer); |
| ClientDiscardableHandle handle = manager.GetHandle(handle_id); |
| EXPECT_TRUE(handle.IsLockedForTesting()); |
| EXPECT_EQ(handle.shm_id(), 1); |
| EXPECT_FALSE(DeleteClientHandleForTesting(handle)); |
| UnlockClientHandleForTesting(handle); |
| manager.LockHandle(handle_id); |
| EXPECT_FALSE(DeleteClientHandleForTesting(handle)); |
| UnlockAndDeleteClientHandleForTesting(handle); |
| manager.FreeHandle(handle_id); |
| manager.CheckPendingForTesting(&command_buffer); |
| } |
| |
| TEST(ClientDiscardableManagerTest, Reuse) { |
| FakeCommandBuffer command_buffer; |
| ClientDiscardableManager manager; |
| manager.SetElementCountForTesting(1024); |
| std::vector<ClientDiscardableHandle::Id> handle_ids; |
| for (int i = 0; i < 1024; ++i) { |
| ClientDiscardableHandle::Id handle_id = |
| manager.CreateHandle(&command_buffer); |
| ClientDiscardableHandle handle = manager.GetHandle(handle_id); |
| EXPECT_TRUE(handle.IsLockedForTesting()); |
| EXPECT_EQ(handle.shm_id(), 1); |
| UnlockClientHandleForTesting(handle); |
| handle_ids.push_back(handle_id); |
| } |
| // Delete every other entry. |
| for (auto it = handle_ids.begin(); it != handle_ids.end();) { |
| DeleteClientHandleForTesting(manager.GetHandle(*it)); |
| manager.FreeHandle(*it); |
| it = handle_ids.erase(it); |
| ++it; |
| } |
| // Allocate 512 more entries, ensure we re-use the original buffer. |
| for (int i = 0; i < 512; ++i) { |
| ClientDiscardableHandle::Id handle_id = |
| manager.CreateHandle(&command_buffer); |
| ClientDiscardableHandle handle = manager.GetHandle(handle_id); |
| EXPECT_TRUE(handle.IsLockedForTesting()); |
| EXPECT_EQ(handle.shm_id(), 1); |
| UnlockClientHandleForTesting(handle); |
| handle_ids.push_back(handle_id); |
| } |
| // Delete all outstanding allocations |
| for (const auto& handle_id : handle_ids) { |
| DeleteClientHandleForTesting(manager.GetHandle(handle_id)); |
| manager.FreeHandle(handle_id); |
| } |
| manager.CheckPendingForTesting(&command_buffer); |
| } |
| |
| TEST(ClientDiscardableManagerTest, MultipleAllocations) { |
| FakeCommandBuffer command_buffer; |
| ClientDiscardableManager manager; |
| manager.SetElementCountForTesting(1024); |
| std::vector<ClientDiscardableHandle::Id> handle_ids; |
| for (int i = 1; i <= 1024; ++i) { |
| ClientDiscardableHandle::Id handle_id = |
| manager.CreateHandle(&command_buffer); |
| ClientDiscardableHandle handle = manager.GetHandle(handle_id); |
| EXPECT_TRUE(handle.IsLockedForTesting()); |
| EXPECT_EQ(handle.shm_id(), 1); |
| UnlockClientHandleForTesting(handle); |
| handle_ids.push_back(handle_id); |
| } |
| // Allocate and free one entry multiple times, this should cause the |
| // allocation and release of a new shm_id each time. |
| for (int i = 1; i < 10; ++i) { |
| ClientDiscardableHandle::Id handle_id = |
| manager.CreateHandle(&command_buffer); |
| ClientDiscardableHandle handle = manager.GetHandle(handle_id); |
| EXPECT_TRUE(handle.IsLockedForTesting()); |
| EXPECT_EQ(handle.shm_id(), i + 1); |
| UnlockAndDeleteClientHandleForTesting(handle); |
| manager.FreeHandle(handle_id); |
| } |
| // Delete all outstanding allocations |
| for (const auto& handle_id : handle_ids) { |
| DeleteClientHandleForTesting(manager.GetHandle(handle_id)); |
| manager.FreeHandle(handle_id); |
| } |
| manager.CheckPendingForTesting(&command_buffer); |
| } |
| |
| TEST(ClientDiscardableManagerTest, FreeDeleted) { |
| FakeCommandBuffer command_buffer; |
| ClientDiscardableManager manager; |
| manager.SetElementCountForTesting(4); |
| |
| // Track seen IDs, we should never see an ID again, even when re-using a |
| // handle. |
| std::set<ClientDiscardableHandle::Id> seen_ids; |
| |
| // Fill our allocation with unlocked handles. |
| std::vector<ClientDiscardableHandle::Id> handle_ids; |
| for (int i = 0; i < 4; ++i) { |
| ClientDiscardableHandle::Id handle_id = |
| manager.CreateHandle(&command_buffer); |
| EXPECT_EQ(0u, seen_ids.count(handle_id)); |
| seen_ids.insert(handle_id); |
| |
| ClientDiscardableHandle handle = manager.GetHandle(handle_id); |
| EXPECT_TRUE(handle.IsLockedForTesting()); |
| EXPECT_EQ(handle.shm_id(), 1); |
| UnlockClientHandleForTesting(handle); |
| handle_ids.push_back(handle_id); |
| } |
| // Allocate and free a new entry. It should get a new allocation. |
| { |
| ClientDiscardableHandle::Id handle_id = |
| manager.CreateHandle(&command_buffer); |
| EXPECT_EQ(0u, seen_ids.count(handle_id)); |
| seen_ids.insert(handle_id); |
| |
| ClientDiscardableHandle handle = manager.GetHandle(handle_id); |
| EXPECT_TRUE(handle.IsLockedForTesting()); |
| EXPECT_EQ(handle.shm_id(), 2); |
| UnlockAndDeleteClientHandleForTesting(handle); |
| manager.FreeHandle(handle_id); |
| } |
| // Delete (but don't free) one of the above entries. |
| DeleteClientHandleForTesting(manager.GetHandle(handle_ids[0])); |
| // Allocate and free a new entry, it should re-use the first allocation. |
| { |
| ClientDiscardableHandle::Id handle_id = |
| manager.CreateHandle(&command_buffer); |
| EXPECT_EQ(0u, seen_ids.count(handle_id)); |
| seen_ids.insert(handle_id); |
| |
| ClientDiscardableHandle handle = manager.GetHandle(handle_id); |
| EXPECT_TRUE(handle.IsLockedForTesting()); |
| EXPECT_EQ(handle.shm_id(), 1); |
| UnlockAndDeleteClientHandleForTesting(handle); |
| manager.FreeHandle(handle_id); |
| } |
| // Delete and free the remaining handles. |
| for (int i = 1; i < 4; ++i) { |
| DeleteClientHandleForTesting(manager.GetHandle(handle_ids[i])); |
| manager.FreeHandle(handle_ids[i]); |
| } |
| manager.CheckPendingForTesting(&command_buffer); |
| } |
| |
| TEST(ClientDiscardableTextureManagerTest, BasicUsage) { |
| FakeCommandBuffer command_buffer; |
| ClientDiscardableTextureManager manager; |
| { |
| ClientDiscardableHandle handle = |
| manager.InitializeTexture(&command_buffer, 1); |
| EXPECT_TRUE(handle.IsLockedForTesting()); |
| EXPECT_EQ(handle.shm_id(), 1); |
| EXPECT_FALSE(DeleteClientHandleForTesting(handle)); |
| UnlockClientHandleForTesting(handle); |
| manager.LockTexture(1); |
| EXPECT_FALSE(DeleteClientHandleForTesting(handle)); |
| UnlockAndDeleteClientHandleForTesting(handle); |
| } |
| manager.FreeTexture(1); |
| manager.DiscardableManagerForTesting()->CheckPendingForTesting( |
| &command_buffer); |
| } |
| |
| } // namespace gpu |