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/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  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
46
47  glBindFramebuffer(GL_FRAMEBUFFER, old_fbo);
48
49  glDeleteFramebuffers(1, &fbo);
50
51  return texel;
52}
53}
54
55class GLTextureMailboxTest : public testing::Test {
56 protected:
57  virtual void SetUp() {
58    gl1_.Initialize(GLManager::Options());
59    GLManager::Options options;
60    options.share_mailbox_manager = &gl1_;
61    gl2_.Initialize(options);
62  }
63
64  virtual void TearDown() {
65    gl1_.Destroy();
66    gl2_.Destroy();
67  }
68
69  GLManager gl1_;
70  GLManager gl2_;
71};
72
73TEST_F(GLTextureMailboxTest, ProduceAndConsumeTexture) {
74  gl1_.MakeCurrent();
75
76  GLbyte mailbox1[GL_MAILBOX_SIZE_CHROMIUM];
77  glGenMailboxCHROMIUM(mailbox1);
78
79  GLbyte mailbox2[GL_MAILBOX_SIZE_CHROMIUM];
80  glGenMailboxCHROMIUM(mailbox2);
81
82  GLuint tex1;
83  glGenTextures(1, &tex1);
84
85  glBindTexture(GL_TEXTURE_2D, tex1);
86  uint32 source_pixel = 0xFF0000FF;
87  glTexImage2D(GL_TEXTURE_2D,
88               0,
89               GL_RGBA,
90               1, 1,
91               0,
92               GL_RGBA,
93               GL_UNSIGNED_BYTE,
94               &source_pixel);
95
96  glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox1);
97  glFlush();
98
99  gl2_.MakeCurrent();
100
101  GLuint tex2;
102  glGenTextures(1, &tex2);
103
104  glBindTexture(GL_TEXTURE_2D, tex2);
105  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox1);
106  EXPECT_EQ(source_pixel, ReadTexel(tex2, 0, 0));
107  glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox2);
108  glFlush();
109
110  gl1_.MakeCurrent();
111
112  glBindTexture(GL_TEXTURE_2D, tex1);
113  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox2);
114  EXPECT_EQ(source_pixel, ReadTexel(tex1, 0, 0));
115}
116
117TEST_F(GLTextureMailboxTest, ProduceAndConsumeTextureRGB) {
118  gl1_.MakeCurrent();
119
120  GLbyte mailbox1[GL_MAILBOX_SIZE_CHROMIUM];
121  glGenMailboxCHROMIUM(mailbox1);
122
123  GLbyte mailbox2[GL_MAILBOX_SIZE_CHROMIUM];
124  glGenMailboxCHROMIUM(mailbox2);
125
126  GLuint tex1;
127  glGenTextures(1, &tex1);
128
129  glBindTexture(GL_TEXTURE_2D, tex1);
130  uint32 source_pixel = 0xFF000000;
131  glTexImage2D(GL_TEXTURE_2D,
132               0,
133               GL_RGB,
134               1, 1,
135               0,
136               GL_RGB,
137               GL_UNSIGNED_BYTE,
138               &source_pixel);
139
140  glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox1);
141  glFlush();
142
143  gl2_.MakeCurrent();
144
145  GLuint tex2;
146  glGenTextures(1, &tex2);
147
148  glBindTexture(GL_TEXTURE_2D, tex2);
149  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox1);
150  EXPECT_EQ(source_pixel, ReadTexel(tex2, 0, 0));
151  glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox2);
152  glFlush();
153
154  gl1_.MakeCurrent();
155
156  glBindTexture(GL_TEXTURE_2D, tex1);
157  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox2);
158  EXPECT_EQ(source_pixel, ReadTexel(tex1, 0, 0));
159}
160
161TEST_F(GLTextureMailboxTest, ProduceAndConsumeTextureDirect) {
162  gl1_.MakeCurrent();
163
164  GLbyte mailbox1[GL_MAILBOX_SIZE_CHROMIUM];
165  glGenMailboxCHROMIUM(mailbox1);
166
167  GLbyte mailbox2[GL_MAILBOX_SIZE_CHROMIUM];
168  glGenMailboxCHROMIUM(mailbox2);
169
170  GLuint tex1;
171  glGenTextures(1, &tex1);
172
173  glBindTexture(GL_TEXTURE_2D, tex1);
174  uint32 source_pixel = 0xFF0000FF;
175  glTexImage2D(GL_TEXTURE_2D,
176               0,
177               GL_RGBA,
178               1, 1,
179               0,
180               GL_RGBA,
181               GL_UNSIGNED_BYTE,
182               &source_pixel);
183
184  glProduceTextureDirectCHROMIUM(tex1, GL_TEXTURE_2D, mailbox1);
185  glFlush();
186
187  gl2_.MakeCurrent();
188
189  GLuint tex2 = glCreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox1);
190  glBindTexture(GL_TEXTURE_2D, tex2);
191  EXPECT_EQ(source_pixel, ReadTexel(tex2, 0, 0));
192  glProduceTextureDirectCHROMIUM(tex2, GL_TEXTURE_2D, mailbox2);
193  glFlush();
194
195  gl1_.MakeCurrent();
196
197  GLuint tex3 = glCreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox2);
198  glBindTexture(GL_TEXTURE_2D, tex3);
199  EXPECT_EQ(source_pixel, ReadTexel(tex3, 0, 0));
200}
201
202TEST_F(GLTextureMailboxTest, ConsumeTextureValidatesKey) {
203  GLuint tex;
204  glGenTextures(1, &tex);
205
206  glBindTexture(GL_TEXTURE_2D, tex);
207  uint32 source_pixel = 0xFF0000FF;
208  glTexImage2D(GL_TEXTURE_2D,
209               0,
210               GL_RGBA,
211               1, 1,
212               0,
213               GL_RGBA,
214               GL_UNSIGNED_BYTE,
215               &source_pixel);
216
217  GLbyte invalid_mailbox[GL_MAILBOX_SIZE_CHROMIUM];
218  glGenMailboxCHROMIUM(invalid_mailbox);
219
220  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
221  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, invalid_mailbox);
222  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
223
224  // Ensure level 0 is still intact after glConsumeTextureCHROMIUM fails.
225  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
226  EXPECT_EQ(source_pixel, ReadTexel(tex, 0, 0));
227  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
228}
229
230TEST_F(GLTextureMailboxTest, SharedTextures) {
231  gl1_.MakeCurrent();
232  GLuint tex1;
233  glGenTextures(1, &tex1);
234
235  glBindTexture(GL_TEXTURE_2D, tex1);
236  uint32 source_pixel = 0xFF0000FF;
237  glTexImage2D(GL_TEXTURE_2D,
238               0,
239               GL_RGBA,
240               1, 1,
241               0,
242               GL_RGBA,
243               GL_UNSIGNED_BYTE,
244               &source_pixel);
245  GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM];
246  glGenMailboxCHROMIUM(mailbox);
247
248  glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
249  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
250  glFlush();
251
252  gl2_.MakeCurrent();
253  GLuint tex2;
254  glGenTextures(1, &tex2);
255
256  glBindTexture(GL_TEXTURE_2D, tex2);
257  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
258  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
259
260  // Change texture in context 2.
261  source_pixel = 0xFF00FF00;
262  glTexSubImage2D(GL_TEXTURE_2D,
263                  0,
264                  0, 0,
265                  1, 1,
266                  GL_RGBA,
267                  GL_UNSIGNED_BYTE,
268                  &source_pixel);
269  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
270  glFlush();
271
272  // Check it in context 1.
273  gl1_.MakeCurrent();
274  EXPECT_EQ(source_pixel, ReadTexel(tex1, 0, 0));
275  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
276
277  // Change parameters (note: ReadTexel will reset those).
278  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
279  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
280  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
281                  GL_LINEAR_MIPMAP_NEAREST);
282  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
283  glFlush();
284
285  // Check in context 2.
286  gl2_.MakeCurrent();
287  GLint parameter = 0;
288  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &parameter);
289  EXPECT_EQ(GL_REPEAT, parameter);
290  parameter = 0;
291  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &parameter);
292  EXPECT_EQ(GL_LINEAR, parameter);
293  parameter = 0;
294  glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &parameter);
295  EXPECT_EQ(GL_LINEAR_MIPMAP_NEAREST, parameter);
296
297  // Delete texture in context 1.
298  gl1_.MakeCurrent();
299  glDeleteTextures(1, &tex1);
300  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
301
302  // Check texture still exists in context 2.
303  gl2_.MakeCurrent();
304  EXPECT_EQ(source_pixel, ReadTexel(tex2, 0, 0));
305  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
306
307  // The mailbox should still exist too.
308  GLuint tex3;
309  glGenTextures(1, &tex3);
310  glBindTexture(GL_TEXTURE_2D, tex3);
311  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
312  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
313
314  // Delete both textures.
315  glDeleteTextures(1, &tex2);
316  glDeleteTextures(1, &tex3);
317  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
318
319  // Mailbox should be gone now.
320  glGenTextures(1, &tex2);
321  glBindTexture(GL_TEXTURE_2D, tex2);
322  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
323  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
324  glDeleteTextures(1, &tex2);
325  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
326}
327
328TEST_F(GLTextureMailboxTest, ProduceFrontBuffer) {
329  gl1_.MakeCurrent();
330  Mailbox mailbox;
331  glGenMailboxCHROMIUM(mailbox.name);
332
333  gl2_.MakeCurrent();
334  gl2_.decoder()->ProduceFrontBuffer(mailbox);
335
336  gl1_.MakeCurrent();
337  GLuint tex1;
338  glGenTextures(1, &tex1);
339  glBindTexture(GL_TEXTURE_2D, tex1);
340  glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
341  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
342
343  gl2_.MakeCurrent();
344  glResizeCHROMIUM(10, 10, 1);
345  glClearColor(1, 0, 0, 1);
346  glClear(GL_COLOR_BUFFER_BIT);
347  ::gles2::GetGLContext()->SwapBuffers();
348
349  gl1_.MakeCurrent();
350  EXPECT_EQ(0xFF0000FFu, ReadTexel(tex1, 0, 0));
351  EXPECT_EQ(0xFF0000FFu, ReadTexel(tex1, 9, 9));
352  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
353
354  gl2_.MakeCurrent();
355  glClearColor(0, 1, 0, 1);
356  glClear(GL_COLOR_BUFFER_BIT);
357  glFlush();
358
359  gl1_.MakeCurrent();
360  EXPECT_EQ(0xFF0000FFu, ReadTexel(tex1, 0, 0));
361
362  gl2_.MakeCurrent();
363  ::gles2::GetGLContext()->SwapBuffers();
364
365  gl1_.MakeCurrent();
366  EXPECT_EQ(0xFF00FF00u, ReadTexel(tex1, 0, 0));
367
368  gl2_.MakeCurrent();
369  gl2_.Destroy();
370
371  gl1_.MakeCurrent();
372  EXPECT_EQ(0xFF00FF00u, ReadTexel(tex1, 0, 0));
373  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
374  glDeleteTextures(1, &tex1);
375}
376
377TEST_F(GLTextureMailboxTest, ProduceTextureDirectInvalidTarget) {
378  gl1_.MakeCurrent();
379
380  GLbyte mailbox1[GL_MAILBOX_SIZE_CHROMIUM];
381  glGenMailboxCHROMIUM(mailbox1);
382
383  GLuint tex1;
384  glGenTextures(1, &tex1);
385
386  glBindTexture(GL_TEXTURE_CUBE_MAP, tex1);
387  uint32 source_pixel = 0xFF0000FF;
388  glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X,
389               0,
390               GL_RGBA,
391               1, 1,
392               0,
393               GL_RGBA,
394               GL_UNSIGNED_BYTE,
395               &source_pixel);
396
397  glProduceTextureDirectCHROMIUM(tex1, GL_TEXTURE_2D, mailbox1);
398  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
399}
400
401// http://crbug.com/281565
402#if !defined(OS_ANDROID)
403TEST_F(GLTextureMailboxTest, ProduceFrontBufferMultipleContexts) {
404  gl1_.MakeCurrent();
405  Mailbox mailbox[2];
406  glGenMailboxCHROMIUM(mailbox[0].name);
407  glGenMailboxCHROMIUM(mailbox[1].name);
408  GLuint tex[2];
409  glGenTextures(2, tex);
410
411  GLManager::Options options;
412  options.share_mailbox_manager = &gl1_;
413  GLManager other_gl[2];
414  for (size_t i = 0; i < 2; ++i) {
415    other_gl[i].Initialize(options);
416    other_gl[i].MakeCurrent();
417    other_gl[i].decoder()->ProduceFrontBuffer(mailbox[i]);
418    // Make sure both "other gl" are in the same share group.
419    if (!options.share_group_manager)
420      options.share_group_manager = other_gl+i;
421  }
422
423
424  gl1_.MakeCurrent();
425  for (size_t i = 0; i < 2; ++i) {
426    glBindTexture(GL_TEXTURE_2D, tex[i]);
427    glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox[i].name);
428    EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
429  }
430
431  for (size_t i = 0; i < 2; ++i) {
432    other_gl[i].MakeCurrent();
433    glResizeCHROMIUM(10, 10, 1);
434    glClearColor(1-i%2, i%2, 0, 1);
435    glClear(GL_COLOR_BUFFER_BIT);
436    ::gles2::GetGLContext()->SwapBuffers();
437  }
438
439  gl1_.MakeCurrent();
440  EXPECT_EQ(0xFF0000FFu, ReadTexel(tex[0], 0, 0));
441  EXPECT_EQ(0xFF00FF00u, ReadTexel(tex[1], 9, 9));
442
443  for (size_t i = 0; i < 2; ++i) {
444    other_gl[i].MakeCurrent();
445    other_gl[i].Destroy();
446  }
447
448  gl1_.MakeCurrent();
449  glDeleteTextures(2, tex);
450}
451#endif
452
453}  // namespace gpu
454
455