1// Copyright (c) 2012 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/gl2ext.h>
7#include <GLES2/gl2extchromium.h>
8
9#include "gpu/command_buffer/client/gles2_lib.h"
10#include "gpu/command_buffer/common/mailbox.h"
11#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
12#include "gpu/command_buffer/service/mailbox_manager.h"
13#include "gpu/command_buffer/tests/gl_manager.h"
14#include "testing/gmock/include/gmock/gmock.h"
15#include "testing/gtest/include/gtest/gtest.h"
16#include "ui/gl/gl_share_group.h"
17
18namespace gpu {
19
20namespace {
21uint32 ReadTexel(GLuint id, GLint x, GLint y) {
22  GLint old_fbo = 0;
23  glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo);
24
25  GLuint fbo;
26  glGenFramebuffers(1, &fbo);
27  glBindFramebuffer(GL_FRAMEBUFFER, fbo);
28  glFramebufferTexture2D(GL_FRAMEBUFFER,
29                         GL_COLOR_ATTACHMENT0,
30                         GL_TEXTURE_2D,
31                         id,
32                         0);
33  // Some drivers (NVidia/SGX) require texture settings to be a certain way or
34  // they won't report FRAMEBUFFER_COMPLETE.
35  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
36  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
37  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
38  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
39
40  EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
41            glCheckFramebufferStatus(GL_FRAMEBUFFER));
42
43  uint32 texel = 0;
44  glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &texel);
45
46  glBindFramebuffer(GL_FRAMEBUFFER, old_fbo);
47
48  glDeleteFramebuffers(1, &fbo);
49
50  return texel;
51}
52}
53
54class GLTextureMailboxTest : public testing::Test {
55 protected:
56  virtual void SetUp() {
57    gl1_.Initialize(GLManager::Options());
58    GLManager::Options options;
59    options.share_mailbox_manager = &gl1_;
60    gl2_.Initialize(options);
61  }
62
63  virtual void TearDown() {
64    gl1_.Destroy();
65    gl2_.Destroy();
66  }
67
68  GLManager gl1_;
69  GLManager gl2_;
70};
71
72TEST_F(GLTextureMailboxTest, ProduceAndConsumeTexture) {
73  gl1_.MakeCurrent();
74
75  GLbyte mailbox1[GL_MAILBOX_SIZE_CHROMIUM];
76  glGenMailboxCHROMIUM(mailbox1);
77
78  GLbyte mailbox2[GL_MAILBOX_SIZE_CHROMIUM];
79  glGenMailboxCHROMIUM(mailbox2);
80
81  GLuint tex1;
82  glGenTextures(1, &tex1);
83
84  glBindTexture(GL_TEXTURE_2D, tex1);
85  uint32 source_pixel = 0xFF0000FF;
86  glTexImage2D(GL_TEXTURE_2D,
87               0,
88               GL_RGBA,
89               1, 1,
90               0,
91               GL_RGBA,
92               GL_UNSIGNED_BYTE,
93               &source_pixel);
94
95  glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox1);
96  glFlush();
97
98  gl2_.MakeCurrent();
99
100  GLuint tex2;
101  glGenTextures(1, &tex2);
102
103  glBindTexture(GL_TEXTURE_2D, tex2);
104  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox1);
105  EXPECT_EQ(source_pixel, ReadTexel(tex2, 0, 0));
106  glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox2);
107  glFlush();
108
109  gl1_.MakeCurrent();
110
111  glBindTexture(GL_TEXTURE_2D, tex1);
112  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox2);
113  EXPECT_EQ(source_pixel, ReadTexel(tex1, 0, 0));
114}
115
116TEST_F(GLTextureMailboxTest, ConsumeTextureValidatesKey) {
117  GLuint tex;
118  glGenTextures(1, &tex);
119
120  glBindTexture(GL_TEXTURE_2D, tex);
121  uint32 source_pixel = 0xFF0000FF;
122  glTexImage2D(GL_TEXTURE_2D,
123               0,
124               GL_RGBA,
125               1, 1,
126               0,
127               GL_RGBA,
128               GL_UNSIGNED_BYTE,
129               &source_pixel);
130
131  GLbyte invalid_mailbox[GL_MAILBOX_SIZE_CHROMIUM];
132  glGenMailboxCHROMIUM(invalid_mailbox);
133  ++invalid_mailbox[GL_MAILBOX_SIZE_CHROMIUM - 1];
134
135  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
136  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, invalid_mailbox);
137  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
138
139  // Ensure level 0 is still intact after glConsumeTextureCHROMIUM fails.
140  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
141  EXPECT_EQ(source_pixel, ReadTexel(tex, 0, 0));
142  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
143}
144
145TEST_F(GLTextureMailboxTest, SharedTextures) {
146  gl1_.MakeCurrent();
147  GLuint tex1;
148  glGenTextures(1, &tex1);
149
150  glBindTexture(GL_TEXTURE_2D, tex1);
151  uint32 source_pixel = 0xFF0000FF;
152  glTexImage2D(GL_TEXTURE_2D,
153               0,
154               GL_RGBA,
155               1, 1,
156               0,
157               GL_RGBA,
158               GL_UNSIGNED_BYTE,
159               &source_pixel);
160  GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM];
161  glGenMailboxCHROMIUM(mailbox);
162
163  glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
164  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
165  glFlush();
166
167  gl2_.MakeCurrent();
168  GLuint tex2;
169  glGenTextures(1, &tex2);
170
171  glBindTexture(GL_TEXTURE_2D, tex2);
172  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
173  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
174
175  // Change texture in context 2.
176  source_pixel = 0xFF00FF00;
177  glTexSubImage2D(GL_TEXTURE_2D,
178                  0,
179                  0, 0,
180                  1, 1,
181                  GL_RGBA,
182                  GL_UNSIGNED_BYTE,
183                  &source_pixel);
184  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
185  glFlush();
186
187  // Check it in context 1.
188  gl1_.MakeCurrent();
189  EXPECT_EQ(source_pixel, ReadTexel(tex1, 0, 0));
190  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
191
192  // Change parameters (note: ReadTexel will reset those).
193  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
194  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
195  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
196                  GL_LINEAR_MIPMAP_NEAREST);
197  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
198  glFlush();
199
200  // Check in context 2.
201  gl2_.MakeCurrent();
202  GLint parameter = 0;
203  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &parameter);
204  EXPECT_EQ(GL_REPEAT, parameter);
205  parameter = 0;
206  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &parameter);
207  EXPECT_EQ(GL_LINEAR, parameter);
208  parameter = 0;
209  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &parameter);
210  EXPECT_EQ(GL_LINEAR_MIPMAP_NEAREST, parameter);
211
212  // Delete texture in context 1.
213  gl1_.MakeCurrent();
214  glDeleteTextures(1, &tex1);
215  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
216
217  // Check texture still exists in context 2.
218  gl2_.MakeCurrent();
219  EXPECT_EQ(source_pixel, ReadTexel(tex2, 0, 0));
220  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
221
222  // The mailbox should still exist too.
223  GLuint tex3;
224  glGenTextures(1, &tex3);
225  glBindTexture(GL_TEXTURE_2D, tex3);
226  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
227  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
228
229  // Delete both textures.
230  glDeleteTextures(1, &tex2);
231  glDeleteTextures(1, &tex3);
232  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
233
234  // Mailbox should be gone now.
235  glGenTextures(1, &tex2);
236  glBindTexture(GL_TEXTURE_2D, tex2);
237  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
238  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
239  glDeleteTextures(1, &tex2);
240  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
241}
242
243TEST_F(GLTextureMailboxTest, ProduceFrontBuffer) {
244  gl1_.MakeCurrent();
245  Mailbox mailbox;
246  glGenMailboxCHROMIUM(mailbox.name);
247
248  gl2_.MakeCurrent();
249  gl2_.decoder()->ProduceFrontBuffer(mailbox);
250
251  gl1_.MakeCurrent();
252  GLuint tex1;
253  glGenTextures(1, &tex1);
254  glBindTexture(GL_TEXTURE_2D, tex1);
255  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
256  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
257
258  gl2_.MakeCurrent();
259  glResizeCHROMIUM(10, 10, 1);
260  glClearColor(1, 0, 0, 1);
261  glClear(GL_COLOR_BUFFER_BIT);
262  ::gles2::GetGLContext()->SwapBuffers();
263
264  gl1_.MakeCurrent();
265  EXPECT_EQ(0xFF0000FFu, ReadTexel(tex1, 0, 0));
266  EXPECT_EQ(0xFF0000FFu, ReadTexel(tex1, 9, 9));
267  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
268
269  gl2_.MakeCurrent();
270  glClearColor(0, 1, 0, 1);
271  glClear(GL_COLOR_BUFFER_BIT);
272  glFlush();
273
274  gl1_.MakeCurrent();
275  EXPECT_EQ(0xFF0000FFu, ReadTexel(tex1, 0, 0));
276
277  gl2_.MakeCurrent();
278  ::gles2::GetGLContext()->SwapBuffers();
279
280  gl1_.MakeCurrent();
281  EXPECT_EQ(0xFF00FF00u, ReadTexel(tex1, 0, 0));
282
283  gl2_.MakeCurrent();
284  gl2_.Destroy();
285
286  gl1_.MakeCurrent();
287  EXPECT_EQ(0xFF00FF00u, ReadTexel(tex1, 0, 0));
288  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
289  glDeleteTextures(1, &tex1);
290}
291
292// http://crbug.com/281565
293#if !defined(OS_ANDROID)
294TEST_F(GLTextureMailboxTest, ProduceFrontBufferMultipleContexts) {
295  gl1_.MakeCurrent();
296  Mailbox mailbox[2];
297  glGenMailboxCHROMIUM(mailbox[0].name);
298  glGenMailboxCHROMIUM(mailbox[1].name);
299  GLuint tex[2];
300  glGenTextures(2, tex);
301
302  GLManager::Options options;
303  options.share_mailbox_manager = &gl1_;
304  GLManager other_gl[2];
305  for (size_t i = 0; i < 2; ++i) {
306    other_gl[i].Initialize(options);
307    other_gl[i].MakeCurrent();
308    other_gl[i].decoder()->ProduceFrontBuffer(mailbox[i]);
309    // Make sure both "other gl" are in the same share group.
310    if (!options.share_group_manager)
311      options.share_group_manager = other_gl+i;
312  }
313
314
315  gl1_.MakeCurrent();
316  for (size_t i = 0; i < 2; ++i) {
317    glBindTexture(GL_TEXTURE_2D, tex[i]);
318    glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox[i].name);
319    EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
320  }
321
322  for (size_t i = 0; i < 2; ++i) {
323    other_gl[i].MakeCurrent();
324    glResizeCHROMIUM(10, 10, 1);
325    glClearColor(1-i%2, i%2, 0, 1);
326    glClear(GL_COLOR_BUFFER_BIT);
327    ::gles2::GetGLContext()->SwapBuffers();
328  }
329
330  gl1_.MakeCurrent();
331  EXPECT_EQ(0xFF0000FFu, ReadTexel(tex[0], 0, 0));
332  EXPECT_EQ(0xFF00FF00u, ReadTexel(tex[1], 9, 9));
333
334  for (size_t i = 0; i < 2; ++i) {
335    other_gl[i].MakeCurrent();
336    other_gl[i].Destroy();
337  }
338
339  gl1_.MakeCurrent();
340  glDeleteTextures(2, tex);
341}
342#endif
343
344}  // namespace gpu
345
346