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 18 namespace gpu { 19 20 namespace { 21 uint32 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 54 class 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 72 TEST_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 116 TEST_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 145 TEST_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 174 TEST_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, ¶meter); 233 EXPECT_EQ(GL_REPEAT, parameter); 234 parameter = 0; 235 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ¶meter); 236 EXPECT_EQ(GL_LINEAR, parameter); 237 parameter = 0; 238 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ¶meter); 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 272 TEST_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 TEST_F(GLTextureMailboxTest, ProduceFrontBufferMultipleContexts) { 322 gl1_.MakeCurrent(); 323 Mailbox mailbox[2]; 324 glGenMailboxCHROMIUM(mailbox[0].name); 325 glGenMailboxCHROMIUM(mailbox[1].name); 326 GLuint tex[2]; 327 glGenTextures(2, tex); 328 329 GLManager::Options options; 330 options.share_mailbox_manager = &gl1_; 331 GLManager other_gl[2]; 332 for (size_t i = 0; i < 2; ++i) { 333 other_gl[i].Initialize(options); 334 other_gl[i].MakeCurrent(); 335 other_gl[i].decoder()->ProduceFrontBuffer(mailbox[i]); 336 // Make sure both "other gl" are in the same share group. 337 if (!options.share_group_manager) 338 options.share_group_manager = other_gl+i; 339 } 340 341 342 gl1_.MakeCurrent(); 343 for (size_t i = 0; i < 2; ++i) { 344 glBindTexture(GL_TEXTURE_2D, tex[i]); 345 glConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox[i].name); 346 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); 347 } 348 349 for (size_t i = 0; i < 2; ++i) { 350 other_gl[i].MakeCurrent(); 351 glResizeCHROMIUM(10, 10, 1); 352 glClearColor(1-i%2, i%2, 0, 1); 353 glClear(GL_COLOR_BUFFER_BIT); 354 ::gles2::GetGLContext()->SwapBuffers(); 355 } 356 357 gl1_.MakeCurrent(); 358 EXPECT_EQ(0xFF0000FFu, ReadTexel(tex[0], 0, 0)); 359 EXPECT_EQ(0xFF00FF00u, ReadTexel(tex[1], 9, 9)); 360 361 for (size_t i = 0; i < 2; ++i) { 362 other_gl[i].MakeCurrent(); 363 other_gl[i].Destroy(); 364 } 365 366 gl1_.MakeCurrent(); 367 glDeleteTextures(2, tex); 368 } 369 370 } // namespace gpu 371 372