| Index: components/viz/common/server_gpu_memory_buffer_manager_unittest.cc
 | 
| diff --git a/components/viz/common/server_gpu_memory_buffer_manager_unittest.cc b/components/viz/common/server_gpu_memory_buffer_manager_unittest.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..766852975f9059487ab968c0a6d023ed16969dc5
 | 
| --- /dev/null
 | 
| +++ b/components/viz/common/server_gpu_memory_buffer_manager_unittest.cc
 | 
| @@ -0,0 +1,211 @@
 | 
| +// Copyright 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 "components/viz/common/server_gpu_memory_buffer_manager.h"
 | 
| +
 | 
| +#include "base/test/scoped_task_environment.h"
 | 
| +#include "gpu/ipc/host/gpu_memory_buffer_support.h"
 | 
| +#include "services/ui/gpu/interfaces/gpu_service.mojom.h"
 | 
| +#include "testing/gtest/include/gtest/gtest.h"
 | 
| +#include "ui/gfx/client_native_pixmap_factory.h"
 | 
| +
 | 
| +namespace viz {
 | 
| +
 | 
| +namespace {
 | 
| +
 | 
| +class TestGpuService : public ui::mojom::GpuService {
 | 
| + public:
 | 
| +  TestGpuService() {}
 | 
| +  ~TestGpuService() override {}
 | 
| +
 | 
| +  bool HasAllocationRequest(gfx::GpuMemoryBufferId id, int client_id) const {
 | 
| +    for (const auto& req : allocation_requests_) {
 | 
| +      if (req.id == id && req.client_id == client_id)
 | 
| +        return true;
 | 
| +    }
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  bool HasDestructionRequest(gfx::GpuMemoryBufferId id, int client_id) const {
 | 
| +    for (const auto& req : destruction_requests_) {
 | 
| +      if (req.id == id && req.client_id == client_id)
 | 
| +        return true;
 | 
| +    }
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  void SatisfyAllocationRequest(gfx::GpuMemoryBufferId id, int client_id) {
 | 
| +    for (const auto& req : allocation_requests_) {
 | 
| +      if (req.id == id && req.client_id == client_id) {
 | 
| +        gfx::GpuMemoryBufferHandle handle;
 | 
| +        handle.id = id;
 | 
| +        handle.type = gfx::SHARED_MEMORY_BUFFER;
 | 
| +        req.callback.Run(handle);
 | 
| +        return;
 | 
| +      }
 | 
| +    }
 | 
| +    NOTREACHED();
 | 
| +  }
 | 
| +
 | 
| +  // ui::mojom::GpuService:
 | 
| +  void EstablishGpuChannel(
 | 
| +      int32_t client_id,
 | 
| +      uint64_t client_tracing_id,
 | 
| +      bool is_gpu_host,
 | 
| +      const EstablishGpuChannelCallback& callback) override {}
 | 
| +
 | 
| +  void CloseChannel(int32_t client_id) override {}
 | 
| +
 | 
| +  void CreateGpuMemoryBuffer(
 | 
| +      gfx::GpuMemoryBufferId id,
 | 
| +      const gfx::Size& size,
 | 
| +      gfx::BufferFormat format,
 | 
| +      gfx::BufferUsage usage,
 | 
| +      int client_id,
 | 
| +      gpu::SurfaceHandle surface_handle,
 | 
| +      const CreateGpuMemoryBufferCallback& callback) override {
 | 
| +    allocation_requests_.push_back(
 | 
| +        {id, size, format, usage, client_id, callback});
 | 
| +  }
 | 
| +
 | 
| +  void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
 | 
| +                              int client_id,
 | 
| +                              const gpu::SyncToken& sync_token) override {
 | 
| +    destruction_requests_.push_back({id, client_id});
 | 
| +  }
 | 
| +
 | 
| +  void GetVideoMemoryUsageStats(
 | 
| +      const GetVideoMemoryUsageStatsCallback& callback) override {}
 | 
| +
 | 
| +  void RequestCompleteGpuInfo(
 | 
| +      const RequestCompleteGpuInfoCallback& callback) override {}
 | 
| +
 | 
| +  void LoadedShader(const std::string& data) override {}
 | 
| +
 | 
| +  void DestroyingVideoSurface(
 | 
| +      int32_t surface_id,
 | 
| +      const DestroyingVideoSurfaceCallback& callback) override {}
 | 
| +
 | 
| +  void WakeUpGpu() override {}
 | 
| +
 | 
| +  void GpuSwitched() override {}
 | 
| +
 | 
| +  void DestroyAllChannels() override {}
 | 
| +
 | 
| +  void Crash() override {}
 | 
| +
 | 
| +  void Hang() override {}
 | 
| +
 | 
| +  void ThrowJavaException() override {}
 | 
| +
 | 
| +  void Stop(const StopCallback& callback) override {}
 | 
| +
 | 
| + private:
 | 
| +  struct AllocationRequest {
 | 
| +    const gfx::GpuMemoryBufferId id;
 | 
| +    const gfx::Size size;
 | 
| +    const gfx::BufferFormat format;
 | 
| +    const gfx::BufferUsage usage;
 | 
| +    const int client_id;
 | 
| +    const CreateGpuMemoryBufferCallback callback;
 | 
| +  };
 | 
| +  std::vector<AllocationRequest> allocation_requests_;
 | 
| +
 | 
| +  struct DestructionRequest {
 | 
| +    const gfx::GpuMemoryBufferId id;
 | 
| +    const int client_id;
 | 
| +  };
 | 
| +  std::vector<DestructionRequest> destruction_requests_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(TestGpuService);
 | 
| +};
 | 
| +
 | 
| +// It is necessary to install a custom pixmap factory which claims to support
 | 
| +// all native configurations, so that code that deals with this can be tested
 | 
| +// correctly.
 | 
| +class FakeClientNativePixmapFactory : public gfx::ClientNativePixmapFactory {
 | 
| + public:
 | 
| +  FakeClientNativePixmapFactory() {}
 | 
| +  ~FakeClientNativePixmapFactory() override {}
 | 
| +
 | 
| +  // gfx::ClientNativePixmapFactory:
 | 
| +  bool IsConfigurationSupported(gfx::BufferFormat format,
 | 
| +                                gfx::BufferUsage usage) const override {
 | 
| +    return true;
 | 
| +  }
 | 
| +  std::unique_ptr<gfx::ClientNativePixmap> ImportFromHandle(
 | 
| +      const gfx::NativePixmapHandle& handle,
 | 
| +      const gfx::Size& size,
 | 
| +      gfx::BufferUsage usage) override {
 | 
| +    NOTREACHED();
 | 
| +    return nullptr;
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  DISALLOW_COPY_AND_ASSIGN(FakeClientNativePixmapFactory);
 | 
| +};
 | 
| +
 | 
| +}  // namespace
 | 
| +
 | 
| +class ServerGpuMemoryBufferManagerTest : public ::testing::Test {
 | 
| + public:
 | 
| +  ServerGpuMemoryBufferManagerTest() = default;
 | 
| +  ~ServerGpuMemoryBufferManagerTest() override = default;
 | 
| +
 | 
| +  // ::testing::Test:
 | 
| +  void SetUp() override {
 | 
| +    gfx::ClientNativePixmapFactory::ResetInstance();
 | 
| +    gfx::ClientNativePixmapFactory::SetInstance(&pixmap_factory_);
 | 
| +  }
 | 
| +
 | 
| +  void TearDown() override { gfx::ClientNativePixmapFactory::ResetInstance(); }
 | 
| +
 | 
| + private:
 | 
| +  base::test::ScopedTaskEnvironment env_;
 | 
| +  FakeClientNativePixmapFactory pixmap_factory_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(ServerGpuMemoryBufferManagerTest);
 | 
| +};
 | 
| +
 | 
| +// Tests that allocation requests from a client that goes away before allocation
 | 
| +// completes are cleaned up correctly.
 | 
| +TEST_F(ServerGpuMemoryBufferManagerTest, AllocationRequestsForDestroyedClient) {
 | 
| +#if !defined(USE_OZONE) && !defined(OS_MACOSX)
 | 
| +  // Not all platforms support native configurations (currently only ozone and
 | 
| +  // mac support it). Abort the test in those platforms.
 | 
| +  DCHECK(gpu::GetNativeGpuMemoryBufferConfigurations().empty());
 | 
| +  return;
 | 
| +#else
 | 
| +  // Note: ServerGpuMemoryBufferManager normally operates on a mojom::GpuService
 | 
| +  // implementation over mojo. Which means the communication from SGMBManager to
 | 
| +  // GpuService is asynchronous. In this test, the mojom::GpuService is not
 | 
| +  // bound to a mojo pipe, which means those calls are all synchronous.
 | 
| +  TestGpuService gpu_service;
 | 
| +  ServerGpuMemoryBufferManager manager(&gpu_service, 1);
 | 
| +
 | 
| +  const auto buffer_id = static_cast<gfx::GpuMemoryBufferId>(1);
 | 
| +  const int client_id = 2;
 | 
| +  const gfx::Size size(10, 20);
 | 
| +  const gfx::BufferFormat format = gfx::BufferFormat::RGBA_8888;
 | 
| +  const gfx::BufferUsage usage = gfx::BufferUsage::GPU_READ;
 | 
| +  manager.AllocateGpuMemoryBuffer(
 | 
| +      buffer_id, client_id, size, format, usage, gpu::kNullSurfaceHandle,
 | 
| +      base::BindOnce([](const gfx::GpuMemoryBufferHandle& handle) {}));
 | 
| +  EXPECT_TRUE(gpu_service.HasAllocationRequest(buffer_id, client_id));
 | 
| +  EXPECT_FALSE(gpu_service.HasDestructionRequest(buffer_id, client_id));
 | 
| +
 | 
| +  // Destroy the client. Since no memory has been allocated yet, there will be
 | 
| +  // no request for freeing memory.
 | 
| +  manager.DestroyAllGpuMemoryBufferForClient(client_id);
 | 
| +  EXPECT_TRUE(gpu_service.HasAllocationRequest(buffer_id, client_id));
 | 
| +  EXPECT_FALSE(gpu_service.HasDestructionRequest(buffer_id, client_id));
 | 
| +
 | 
| +  // When the host receives the allocated memory for the destroyed client, it
 | 
| +  // should request the allocated memory to be freed.
 | 
| +  gpu_service.SatisfyAllocationRequest(buffer_id, client_id);
 | 
| +  EXPECT_TRUE(gpu_service.HasDestructionRequest(buffer_id, client_id));
 | 
| +#endif
 | 
| +}
 | 
| +
 | 
| +}  // namespace viz
 | 
| 
 |