1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <GLES2/gl2.h>
6#include <GLES2/gl2chromium.h>
7#include <GLES2/gl2ext.h>
8#include <GLES2/gl2extchromium.h>
9
10#include "base/bind.h"
11#include "base/memory/ref_counted.h"
12#include "base/process/process_handle.h"
13#include "gpu/command_buffer/client/gles2_implementation.h"
14#include "gpu/command_buffer/client/gpu_memory_buffer_factory.h"
15#include "gpu/command_buffer/service/command_buffer_service.h"
16#include "gpu/command_buffer/service/image_manager.h"
17#include "gpu/command_buffer/tests/gl_manager.h"
18#include "gpu/command_buffer/tests/gl_test_utils.h"
19#include "testing/gmock/include/gmock/gmock.h"
20#include "testing/gtest/include/gtest/gtest.h"
21#include "ui/gl/gl_image.h"
22
23using testing::_;
24using testing::IgnoreResult;
25using testing::InvokeWithoutArgs;
26using testing::Invoke;
27using testing::Return;
28using testing::SetArgPointee;
29using testing::StrictMock;
30
31namespace gpu {
32namespace gles2 {
33
34static const int kImageWidth = 32;
35static const int kImageHeight = 32;
36static const int kImageBytesPerPixel = 4;
37
38class MockGpuMemoryBuffer : public gfx::GpuMemoryBuffer {
39 public:
40  MockGpuMemoryBuffer(int width, int height) {}
41  virtual ~MockGpuMemoryBuffer() {
42    Die();
43  }
44
45  MOCK_METHOD0(Map, void*());
46  MOCK_METHOD0(Unmap, void());
47  MOCK_CONST_METHOD0(IsMapped, bool());
48  MOCK_CONST_METHOD0(GetStride, uint32());
49  MOCK_CONST_METHOD0(GetHandle, gfx::GpuMemoryBufferHandle());
50  MOCK_METHOD0(Die, void());
51
52 private:
53  DISALLOW_COPY_AND_ASSIGN(MockGpuMemoryBuffer);
54};
55
56class MockGpuMemoryBufferFactory : public GpuMemoryBufferFactory {
57 public:
58  MockGpuMemoryBufferFactory() {}
59  virtual ~MockGpuMemoryBufferFactory() {}
60
61  MOCK_METHOD4(CreateGpuMemoryBuffer,
62               gfx::GpuMemoryBuffer*(size_t, size_t, unsigned, unsigned));
63
64 private:
65  DISALLOW_COPY_AND_ASSIGN(MockGpuMemoryBufferFactory);
66};
67
68class MockGpuMemoryBufferTest : public testing::Test {
69 protected:
70  virtual void SetUp() {
71    GLManager::Options options;
72    image_manager_ = new ImageManager;
73    gpu_memory_buffer_factory_.reset(new MockGpuMemoryBufferFactory);
74    options.image_manager = image_manager_.get();
75    options.gpu_memory_buffer_factory = gpu_memory_buffer_factory_.get();
76
77    gl_.Initialize(options);
78    gl_.MakeCurrent();
79
80    glGenTextures(2, texture_ids_);
81    glBindTexture(GL_TEXTURE_2D, texture_ids_[1]);
82
83    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
84    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
85    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
86    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
87
88    glGenFramebuffers(1, &framebuffer_id_);
89    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id_);
90    glFramebufferTexture2D(GL_FRAMEBUFFER,
91                           GL_COLOR_ATTACHMENT0,
92                           GL_TEXTURE_2D,
93                           texture_ids_[1],
94                           0);
95  }
96
97  virtual void TearDown() {
98    glDeleteTextures(2, texture_ids_);
99    glDeleteFramebuffers(1, &framebuffer_id_);
100
101    gl_.Destroy();
102  }
103
104  scoped_refptr<ImageManager> image_manager_;
105  scoped_ptr<MockGpuMemoryBufferFactory> gpu_memory_buffer_factory_;
106  GLManager gl_;
107  GLuint texture_ids_[2];
108  GLuint framebuffer_id_;
109};
110
111// An end to end test that tests the whole GpuMemoryBuffer lifecycle.
112TEST_F(MockGpuMemoryBufferTest, Lifecycle) {
113  size_t bytes = kImageWidth * kImageHeight * kImageBytesPerPixel;
114  uint8 pixels[1 * 4] = { 255u, 0u, 0u, 255u };
115
116  // Buffer is owned and freed by GpuMemoryBufferTracker.
117  StrictMock<MockGpuMemoryBuffer>* gpu_memory_buffer =
118      new StrictMock<MockGpuMemoryBuffer>(kImageWidth, kImageHeight);
119  base::SharedMemory shared_memory;
120  shared_memory.CreateAnonymous(bytes);
121
122  base::SharedMemoryHandle duped_shared_memory_handle;
123  shared_memory.ShareToProcess(base::GetCurrentProcessHandle(),
124                               &duped_shared_memory_handle);
125  gfx::GpuMemoryBufferHandle handle;
126  handle.type = gfx::SHARED_MEMORY_BUFFER;
127  handle.handle = duped_shared_memory_handle;
128
129  EXPECT_CALL(
130      *gpu_memory_buffer_factory_.get(),
131      CreateGpuMemoryBuffer(
132          kImageWidth, kImageHeight, GL_RGBA8_OES, GL_IMAGE_MAP_CHROMIUM))
133      .Times(1)
134      .WillOnce(Return(gpu_memory_buffer))
135      .RetiresOnSaturation();
136  EXPECT_CALL(*gpu_memory_buffer, GetHandle())
137      .Times(1)
138      .WillOnce(Return(handle))
139      .RetiresOnSaturation();
140
141  // Create the image. This should add the image ID to the ImageManager.
142  GLuint image_id = glCreateImageCHROMIUM(
143      kImageWidth, kImageHeight, GL_RGBA8_OES, GL_IMAGE_MAP_CHROMIUM);
144  EXPECT_NE(0u, image_id);
145  EXPECT_TRUE(image_manager_->LookupImage(image_id) != NULL);
146
147  EXPECT_CALL(*gpu_memory_buffer, IsMapped())
148      .WillOnce(Return(false))
149      .RetiresOnSaturation();
150
151  shared_memory.Map(bytes);
152  EXPECT_TRUE(shared_memory.memory());
153
154  EXPECT_CALL(*gpu_memory_buffer, Map())
155      .Times(1)
156      .WillOnce(Return(shared_memory.memory()))
157      .RetiresOnSaturation();
158  uint8* mapped_buffer = static_cast<uint8*>(glMapImageCHROMIUM(image_id));
159  ASSERT_TRUE(mapped_buffer != NULL);
160
161  // Assign a value to each pixel.
162  int stride = kImageWidth * kImageBytesPerPixel;
163  for (int x = 0; x < kImageWidth; ++x) {
164    for (int y = 0; y < kImageHeight; ++y) {
165      mapped_buffer[y * stride + x * kImageBytesPerPixel + 0] = pixels[0];
166      mapped_buffer[y * stride + x * kImageBytesPerPixel + 1] = pixels[1];
167      mapped_buffer[y * stride + x * kImageBytesPerPixel + 2] = pixels[2];
168      mapped_buffer[y * stride + x * kImageBytesPerPixel + 3] = pixels[3];
169    }
170  }
171
172  EXPECT_CALL(*gpu_memory_buffer, IsMapped())
173      .WillOnce(Return(true))
174      .RetiresOnSaturation();
175
176  // Unmap the image.
177  EXPECT_CALL(*gpu_memory_buffer, Unmap())
178      .Times(1)
179      .RetiresOnSaturation();
180  glUnmapImageCHROMIUM(image_id);
181
182  // Bind the texture and the image.
183  glBindTexture(GL_TEXTURE_2D, texture_ids_[0]);
184  glBindTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id);
185
186  // Copy texture so we can verify result using CheckPixels.
187  glCopyTextureCHROMIUM(GL_TEXTURE_2D,
188                        texture_ids_[0],
189                        texture_ids_[1],
190                        0,
191                        GL_RGBA,
192                        GL_UNSIGNED_BYTE);
193  EXPECT_TRUE(glGetError() == GL_NO_ERROR);
194
195  // Check if pixels match the values that were assigned to the mapped buffer.
196  GLTestHelper::CheckPixels(0, 0, kImageWidth, kImageHeight, 0, pixels);
197  EXPECT_TRUE(GL_NO_ERROR == glGetError());
198
199  // Release the image.
200  glReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id);
201
202  // Destroy the image.
203  EXPECT_CALL(*gpu_memory_buffer, Die())
204      .Times(1)
205      .RetiresOnSaturation();
206  glDestroyImageCHROMIUM(image_id);
207}
208
209}  // namespace gles2
210}  // namespace gpu
211