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, ¶meter); 204 EXPECT_EQ(GL_REPEAT, parameter); 205 parameter = 0; 206 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ¶meter); 207 EXPECT_EQ(GL_LINEAR, parameter); 208 parameter = 0; 209 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ¶meter); 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