gl_texture_mailbox_unittests.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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, ProduceTextureValidatesKey) {
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  glProduceTextureCHROMIUM(GL_TEXTURE_2D, invalid_mailbox);
137  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
138
139  // Ensure level 0 is still intact after glProduceTextureCHROMIUM 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, ConsumeTextureValidatesKey) {
146  GLuint tex;
147  glGenTextures(1, &tex);
148
149  glBindTexture(GL_TEXTURE_2D, tex);
150  uint32 source_pixel = 0xFF0000FF;
151  glTexImage2D(GL_TEXTURE_2D,
152               0,
153               GL_RGBA,
154               1, 1,
155               0,
156               GL_RGBA,
157               GL_UNSIGNED_BYTE,
158               &source_pixel);
159
160  GLbyte invalid_mailbox[GL_MAILBOX_SIZE_CHROMIUM];
161  glGenMailboxCHROMIUM(invalid_mailbox);
162  ++invalid_mailbox[GL_MAILBOX_SIZE_CHROMIUM - 1];
163
164  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
165  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, invalid_mailbox);
166  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
167
168  // Ensure level 0 is still intact after glConsumeTextureCHROMIUM fails.
169  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
170  EXPECT_EQ(source_pixel, ReadTexel(tex, 0, 0));
171  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
172}
173
174TEST_F(GLTextureMailboxTest, SharedTextures) {
175  gl1_.MakeCurrent();
176  GLuint tex1;
177  glGenTextures(1, &tex1);
178
179  glBindTexture(GL_TEXTURE_2D, tex1);
180  uint32 source_pixel = 0xFF0000FF;
181  glTexImage2D(GL_TEXTURE_2D,
182               0,
183               GL_RGBA,
184               1, 1,
185               0,
186               GL_RGBA,
187               GL_UNSIGNED_BYTE,
188               &source_pixel);
189  GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM];
190  glGenMailboxCHROMIUM(mailbox);
191
192  glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
193  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
194  glFlush();
195
196  gl2_.MakeCurrent();
197  GLuint tex2;
198  glGenTextures(1, &tex2);
199
200  glBindTexture(GL_TEXTURE_2D, tex2);
201  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
202  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
203
204  // Change texture in context 2.
205  source_pixel = 0xFF00FF00;
206  glTexSubImage2D(GL_TEXTURE_2D,
207                  0,
208                  0, 0,
209                  1, 1,
210                  GL_RGBA,
211                  GL_UNSIGNED_BYTE,
212                  &source_pixel);
213  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
214  glFlush();
215
216  // Check it in context 1.
217  gl1_.MakeCurrent();
218  EXPECT_EQ(source_pixel, ReadTexel(tex1, 0, 0));
219  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
220
221  // Change parameters (note: ReadTexel will reset those).
222  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
223  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
224  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
225                  GL_LINEAR_MIPMAP_NEAREST);
226  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
227  glFlush();
228
229  // Check in context 2.
230  gl2_.MakeCurrent();
231  GLint parameter = 0;
232  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &parameter);
233  EXPECT_EQ(GL_REPEAT, parameter);
234  parameter = 0;
235  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &parameter);
236  EXPECT_EQ(GL_LINEAR, parameter);
237  parameter = 0;
238  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &parameter);
239  EXPECT_EQ(GL_LINEAR_MIPMAP_NEAREST, parameter);
240
241  // Delete texture in context 1.
242  gl1_.MakeCurrent();
243  glDeleteTextures(1, &tex1);
244  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
245
246  // Check texture still exists in context 2.
247  gl2_.MakeCurrent();
248  EXPECT_EQ(source_pixel, ReadTexel(tex2, 0, 0));
249  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
250
251  // The mailbox should still exist too.
252  GLuint tex3;
253  glGenTextures(1, &tex3);
254  glBindTexture(GL_TEXTURE_2D, tex3);
255  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
256  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
257
258  // Delete both textures.
259  glDeleteTextures(1, &tex2);
260  glDeleteTextures(1, &tex3);
261  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
262
263  // Mailbox should be gone now.
264  glGenTextures(1, &tex2);
265  glBindTexture(GL_TEXTURE_2D, tex2);
266  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
267  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
268  glDeleteTextures(1, &tex2);
269  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
270}
271
272TEST_F(GLTextureMailboxTest, ProduceFrontBuffer) {
273  gl1_.MakeCurrent();
274  Mailbox mailbox;
275  glGenMailboxCHROMIUM(mailbox.name);
276
277  gl2_.MakeCurrent();
278  gl2_.decoder()->ProduceFrontBuffer(mailbox);
279
280  gl1_.MakeCurrent();
281  GLuint tex1;
282  glGenTextures(1, &tex1);
283  glBindTexture(GL_TEXTURE_2D, tex1);
284  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
285  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
286
287  gl2_.MakeCurrent();
288  glResizeCHROMIUM(10, 10, 1);
289  glClearColor(1, 0, 0, 1);
290  glClear(GL_COLOR_BUFFER_BIT);
291  ::gles2::GetGLContext()->SwapBuffers();
292
293  gl1_.MakeCurrent();
294  EXPECT_EQ(0xFF0000FFu, ReadTexel(tex1, 0, 0));
295  EXPECT_EQ(0xFF0000FFu, ReadTexel(tex1, 9, 9));
296  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
297
298  gl2_.MakeCurrent();
299  glClearColor(0, 1, 0, 1);
300  glClear(GL_COLOR_BUFFER_BIT);
301  glFlush();
302
303  gl1_.MakeCurrent();
304  EXPECT_EQ(0xFF0000FFu, ReadTexel(tex1, 0, 0));
305
306  gl2_.MakeCurrent();
307  ::gles2::GetGLContext()->SwapBuffers();
308
309  gl1_.MakeCurrent();
310  EXPECT_EQ(0xFF00FF00u, ReadTexel(tex1, 0, 0));
311
312  gl2_.MakeCurrent();
313  gl2_.Destroy();
314
315  gl1_.MakeCurrent();
316  EXPECT_EQ(0xFF00FF00u, ReadTexel(tex1, 0, 0));
317  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
318  glDeleteTextures(1, &tex1);
319}
320
321// http://crbug.com/281565
322#if !defined(OS_ANDROID)
323TEST_F(GLTextureMailboxTest, ProduceFrontBufferMultipleContexts) {
324  gl1_.MakeCurrent();
325  Mailbox mailbox[2];
326  glGenMailboxCHROMIUM(mailbox[0].name);
327  glGenMailboxCHROMIUM(mailbox[1].name);
328  GLuint tex[2];
329  glGenTextures(2, tex);
330
331  GLManager::Options options;
332  options.share_mailbox_manager = &gl1_;
333  GLManager other_gl[2];
334  for (size_t i = 0; i < 2; ++i) {
335    other_gl[i].Initialize(options);
336    other_gl[i].MakeCurrent();
337    other_gl[i].decoder()->ProduceFrontBuffer(mailbox[i]);
338    // Make sure both "other gl" are in the same share group.
339    if (!options.share_group_manager)
340      options.share_group_manager = other_gl+i;
341  }
342
343
344  gl1_.MakeCurrent();
345  for (size_t i = 0; i < 2; ++i) {
346    glBindTexture(GL_TEXTURE_2D, tex[i]);
347    glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox[i].name);
348    EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
349  }
350
351  for (size_t i = 0; i < 2; ++i) {
352    other_gl[i].MakeCurrent();
353    glResizeCHROMIUM(10, 10, 1);
354    glClearColor(1-i%2, i%2, 0, 1);
355    glClear(GL_COLOR_BUFFER_BIT);
356    ::gles2::GetGLContext()->SwapBuffers();
357  }
358
359  gl1_.MakeCurrent();
360  EXPECT_EQ(0xFF0000FFu, ReadTexel(tex[0], 0, 0));
361  EXPECT_EQ(0xFF00FF00u, ReadTexel(tex[1], 9, 9));
362
363  for (size_t i = 0; i < 2; ++i) {
364    other_gl[i].MakeCurrent();
365    other_gl[i].Destroy();
366  }
367
368  gl1_.MakeCurrent();
369  glDeleteTextures(2, tex);
370}
371#endif
372
373}  // namespace gpu
374
375