test_helper.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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 "gpu/command_buffer/service/test_helper.h" 6 7#include <algorithm> 8#include <string> 9 10#include "base/strings/string_number_conversions.h" 11#include "base/strings/string_tokenizer.h" 12#include "gpu/command_buffer/common/types.h" 13#include "gpu/command_buffer/service/buffer_manager.h" 14#include "gpu/command_buffer/service/error_state_mock.h" 15#include "gpu/command_buffer/service/gl_utils.h" 16#include "gpu/command_buffer/service/gpu_switches.h" 17#include "gpu/command_buffer/service/program_manager.h" 18#include "gpu/command_buffer/service/texture_manager.h" 19#include "testing/gtest/include/gtest/gtest.h" 20#include "ui/gl/gl_mock.h" 21 22using ::testing::_; 23using ::testing::DoAll; 24using ::testing::InSequence; 25using ::testing::MatcherCast; 26using ::testing::Pointee; 27using ::testing::Return; 28using ::testing::SetArrayArgument; 29using ::testing::SetArgumentPointee; 30using ::testing::StrEq; 31using ::testing::StrictMock; 32 33namespace gpu { 34namespace gles2 { 35 36// GCC requires these declarations, but MSVC requires they not be present 37#ifndef COMPILER_MSVC 38const GLuint TestHelper::kServiceBlackTexture2dId; 39const GLuint TestHelper::kServiceDefaultTexture2dId; 40const GLuint TestHelper::kServiceBlackTextureCubemapId; 41const GLuint TestHelper::kServiceDefaultTextureCubemapId; 42const GLuint TestHelper::kServiceBlackExternalTextureId; 43const GLuint TestHelper::kServiceDefaultExternalTextureId; 44const GLuint TestHelper::kServiceBlackRectangleTextureId; 45const GLuint TestHelper::kServiceDefaultRectangleTextureId; 46 47const GLint TestHelper::kMaxSamples; 48const GLint TestHelper::kMaxRenderbufferSize; 49const GLint TestHelper::kMaxTextureSize; 50const GLint TestHelper::kMaxCubeMapTextureSize; 51const GLint TestHelper::kNumVertexAttribs; 52const GLint TestHelper::kNumTextureUnits; 53const GLint TestHelper::kMaxTextureImageUnits; 54const GLint TestHelper::kMaxVertexTextureImageUnits; 55const GLint TestHelper::kMaxFragmentUniformVectors; 56const GLint TestHelper::kMaxFragmentUniformComponents; 57const GLint TestHelper::kMaxVaryingVectors; 58const GLint TestHelper::kMaxVaryingFloats; 59const GLint TestHelper::kMaxVertexUniformVectors; 60const GLint TestHelper::kMaxVertexUniformComponents; 61#endif 62 63void TestHelper::SetupTextureInitializationExpectations( 64 ::gfx::MockGLInterface* gl, GLenum target) { 65 InSequence sequence; 66 67 bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES); 68 bool needs_faces = (target == GL_TEXTURE_CUBE_MAP); 69 70 static GLuint texture_2d_ids[] = { 71 kServiceBlackTexture2dId, 72 kServiceDefaultTexture2dId }; 73 static GLuint texture_cube_map_ids[] = { 74 kServiceBlackTextureCubemapId, 75 kServiceDefaultTextureCubemapId }; 76 static GLuint texture_external_oes_ids[] = { 77 kServiceBlackExternalTextureId, 78 kServiceDefaultExternalTextureId }; 79 static GLuint texture_rectangle_arb_ids[] = { 80 kServiceBlackRectangleTextureId, 81 kServiceDefaultRectangleTextureId }; 82 83 const GLuint* texture_ids = NULL; 84 switch (target) { 85 case GL_TEXTURE_2D: 86 texture_ids = &texture_2d_ids[0]; 87 break; 88 case GL_TEXTURE_CUBE_MAP: 89 texture_ids = &texture_cube_map_ids[0]; 90 break; 91 case GL_TEXTURE_EXTERNAL_OES: 92 texture_ids = &texture_external_oes_ids[0]; 93 break; 94 case GL_TEXTURE_RECTANGLE_ARB: 95 texture_ids = &texture_rectangle_arb_ids[0]; 96 break; 97 default: 98 NOTREACHED(); 99 } 100 101 int array_size = 2; 102 103 EXPECT_CALL(*gl, GenTextures(array_size, _)) 104 .WillOnce(SetArrayArgument<1>(texture_ids, 105 texture_ids + array_size)) 106 .RetiresOnSaturation(); 107 for (int ii = 0; ii < array_size; ++ii) { 108 EXPECT_CALL(*gl, BindTexture(target, texture_ids[ii])) 109 .Times(1) 110 .RetiresOnSaturation(); 111 if (needs_initialization) { 112 if (needs_faces) { 113 static GLenum faces[] = { 114 GL_TEXTURE_CUBE_MAP_POSITIVE_X, 115 GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 116 GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 117 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 118 GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 119 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 120 }; 121 for (size_t ii = 0; ii < arraysize(faces); ++ii) { 122 EXPECT_CALL(*gl, TexImage2D(faces[ii], 0, GL_RGBA, 1, 1, 0, GL_RGBA, 123 GL_UNSIGNED_BYTE, _)) 124 .Times(1) 125 .RetiresOnSaturation(); 126 } 127 } else { 128 EXPECT_CALL(*gl, TexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA, 129 GL_UNSIGNED_BYTE, _)) 130 .Times(1) 131 .RetiresOnSaturation(); 132 } 133 } 134 } 135 EXPECT_CALL(*gl, BindTexture(target, 0)) 136 .Times(1) 137 .RetiresOnSaturation(); 138} 139 140void TestHelper::SetupTextureManagerInitExpectations( 141 ::gfx::MockGLInterface* gl, 142 const char* extensions) { 143 InSequence sequence; 144 145 SetupTextureInitializationExpectations(gl, GL_TEXTURE_2D); 146 SetupTextureInitializationExpectations(gl, GL_TEXTURE_CUBE_MAP); 147 148 bool ext_image_external = false; 149 bool arb_texture_rectangle = false; 150 base::CStringTokenizer t(extensions, extensions + strlen(extensions), " "); 151 while (t.GetNext()) { 152 if (t.token() == "GL_OES_EGL_image_external") { 153 ext_image_external = true; 154 break; 155 } 156 if (t.token() == "GL_ARB_texture_rectangle") { 157 arb_texture_rectangle = true; 158 break; 159 } 160 } 161 162 if (ext_image_external) { 163 SetupTextureInitializationExpectations(gl, GL_TEXTURE_EXTERNAL_OES); 164 } 165 if (arb_texture_rectangle) { 166 SetupTextureInitializationExpectations(gl, GL_TEXTURE_RECTANGLE_ARB); 167 } 168} 169 170void TestHelper::SetupTextureDestructionExpectations( 171 ::gfx::MockGLInterface* gl, GLenum target) { 172 GLuint texture_id = 0; 173 switch (target) { 174 case GL_TEXTURE_2D: 175 texture_id = kServiceDefaultTexture2dId; 176 break; 177 case GL_TEXTURE_CUBE_MAP: 178 texture_id = kServiceDefaultTextureCubemapId; 179 break; 180 case GL_TEXTURE_EXTERNAL_OES: 181 texture_id = kServiceDefaultExternalTextureId; 182 break; 183 case GL_TEXTURE_RECTANGLE_ARB: 184 texture_id = kServiceDefaultRectangleTextureId; 185 break; 186 default: 187 NOTREACHED(); 188 } 189 190 EXPECT_CALL(*gl, DeleteTextures(1, Pointee(texture_id))) 191 .Times(1) 192 .RetiresOnSaturation(); 193} 194 195void TestHelper::SetupTextureManagerDestructionExpectations( 196 ::gfx::MockGLInterface* gl, 197 const char* extensions) { 198 SetupTextureDestructionExpectations(gl, GL_TEXTURE_2D); 199 SetupTextureDestructionExpectations(gl, GL_TEXTURE_CUBE_MAP); 200 201 bool ext_image_external = false; 202 bool arb_texture_rectangle = false; 203 base::CStringTokenizer t(extensions, extensions + strlen(extensions), " "); 204 while (t.GetNext()) { 205 if (t.token() == "GL_OES_EGL_image_external") { 206 ext_image_external = true; 207 break; 208 } 209 if (t.token() == "GL_ARB_texture_rectangle") { 210 arb_texture_rectangle = true; 211 break; 212 } 213 } 214 215 if (ext_image_external) { 216 SetupTextureDestructionExpectations(gl, GL_TEXTURE_EXTERNAL_OES); 217 } 218 if (arb_texture_rectangle) { 219 SetupTextureDestructionExpectations(gl, GL_TEXTURE_RECTANGLE_ARB); 220 } 221 222 EXPECT_CALL(*gl, DeleteTextures(4, _)) 223 .Times(1) 224 .RetiresOnSaturation(); 225} 226 227void TestHelper::SetupContextGroupInitExpectations( 228 ::gfx::MockGLInterface* gl, 229 const DisallowedFeatures& disallowed_features, 230 const char* extensions) { 231 InSequence sequence; 232 233 SetupFeatureInfoInitExpectations(gl, extensions); 234 235 EXPECT_CALL(*gl, GetIntegerv(GL_MAX_RENDERBUFFER_SIZE, _)) 236 .WillOnce(SetArgumentPointee<1>(kMaxRenderbufferSize)) 237 .RetiresOnSaturation(); 238 if (strstr(extensions, "GL_EXT_framebuffer_multisample")) { 239 EXPECT_CALL(*gl, GetIntegerv(GL_MAX_SAMPLES, _)) 240 .WillOnce(SetArgumentPointee<1>(kMaxSamples)) 241 .RetiresOnSaturation(); 242 } 243 EXPECT_CALL(*gl, GetIntegerv(GL_MAX_VERTEX_ATTRIBS, _)) 244 .WillOnce(SetArgumentPointee<1>(kNumVertexAttribs)) 245 .RetiresOnSaturation(); 246 EXPECT_CALL(*gl, GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, _)) 247 .WillOnce(SetArgumentPointee<1>(kNumTextureUnits)) 248 .RetiresOnSaturation(); 249 EXPECT_CALL(*gl, GetIntegerv(GL_MAX_TEXTURE_SIZE, _)) 250 .WillOnce(SetArgumentPointee<1>(kMaxTextureSize)) 251 .RetiresOnSaturation(); 252 EXPECT_CALL(*gl, GetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, _)) 253 .WillOnce(SetArgumentPointee<1>(kMaxCubeMapTextureSize)) 254 .RetiresOnSaturation(); 255 EXPECT_CALL(*gl, GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, _)) 256 .WillOnce(SetArgumentPointee<1>(kMaxTextureImageUnits)) 257 .RetiresOnSaturation(); 258 EXPECT_CALL(*gl, GetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, _)) 259 .WillOnce(SetArgumentPointee<1>(kMaxVertexTextureImageUnits)) 260 .RetiresOnSaturation(); 261 EXPECT_CALL(*gl, GetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, _)) 262 .WillOnce(SetArgumentPointee<1>(kMaxFragmentUniformComponents)) 263 .RetiresOnSaturation(); 264 EXPECT_CALL(*gl, GetIntegerv(GL_MAX_VARYING_FLOATS, _)) 265 .WillOnce(SetArgumentPointee<1>(kMaxVaryingFloats)) 266 .RetiresOnSaturation(); 267 EXPECT_CALL(*gl, GetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, _)) 268 .WillOnce(SetArgumentPointee<1>(kMaxVertexUniformComponents)) 269 .RetiresOnSaturation(); 270 271 SetupTextureManagerInitExpectations(gl, extensions); 272} 273 274void TestHelper::SetupFeatureInfoInitExpectations( 275 ::gfx::MockGLInterface* gl, const char* extensions) { 276 SetupFeatureInfoInitExpectationsWithGLVersion(gl, extensions, ""); 277} 278 279void TestHelper::SetupFeatureInfoInitExpectationsWithGLVersion( 280 ::gfx::MockGLInterface* gl, 281 const char* extensions, 282 const char* version) { 283 InSequence sequence; 284 285 EXPECT_CALL(*gl, GetString(GL_EXTENSIONS)) 286 .WillOnce(Return(reinterpret_cast<const uint8*>(extensions))) 287 .RetiresOnSaturation(); 288 EXPECT_CALL(*gl, GetString(GL_VENDOR)) 289 .WillOnce(Return(reinterpret_cast<const uint8*>(""))) 290 .RetiresOnSaturation(); 291 EXPECT_CALL(*gl, GetString(GL_RENDERER)) 292 .WillOnce(Return(reinterpret_cast<const uint8*>(""))) 293 .RetiresOnSaturation(); 294 EXPECT_CALL(*gl, GetString(GL_VERSION)) 295 .WillOnce(Return(reinterpret_cast<const uint8*>(version))) 296 .RetiresOnSaturation(); 297} 298 299void TestHelper::SetupExpectationsForClearingUniforms( 300 ::gfx::MockGLInterface* gl, UniformInfo* uniforms, size_t num_uniforms) { 301 for (size_t ii = 0; ii < num_uniforms; ++ii) { 302 const UniformInfo& info = uniforms[ii]; 303 switch (info.type) { 304 case GL_FLOAT: 305 EXPECT_CALL(*gl, Uniform1fv(info.real_location, info.size, _)) 306 .Times(1) 307 .RetiresOnSaturation(); 308 break; 309 case GL_FLOAT_VEC2: 310 EXPECT_CALL(*gl, Uniform2fv(info.real_location, info.size, _)) 311 .Times(1) 312 .RetiresOnSaturation(); 313 break; 314 case GL_FLOAT_VEC3: 315 EXPECT_CALL(*gl, Uniform3fv(info.real_location, info.size, _)) 316 .Times(1) 317 .RetiresOnSaturation(); 318 break; 319 case GL_FLOAT_VEC4: 320 EXPECT_CALL(*gl, Uniform4fv(info.real_location, info.size, _)) 321 .Times(1) 322 .RetiresOnSaturation(); 323 break; 324 case GL_INT: 325 case GL_BOOL: 326 case GL_SAMPLER_2D: 327 case GL_SAMPLER_CUBE: 328 case GL_SAMPLER_EXTERNAL_OES: 329 case GL_SAMPLER_3D_OES: 330 case GL_SAMPLER_2D_RECT_ARB: 331 EXPECT_CALL(*gl, Uniform1iv(info.real_location, info.size, _)) 332 .Times(1) 333 .RetiresOnSaturation(); 334 break; 335 case GL_INT_VEC2: 336 case GL_BOOL_VEC2: 337 EXPECT_CALL(*gl, Uniform2iv(info.real_location, info.size, _)) 338 .Times(1) 339 .RetiresOnSaturation(); 340 break; 341 case GL_INT_VEC3: 342 case GL_BOOL_VEC3: 343 EXPECT_CALL(*gl, Uniform3iv(info.real_location, info.size, _)) 344 .Times(1) 345 .RetiresOnSaturation(); 346 break; 347 case GL_INT_VEC4: 348 case GL_BOOL_VEC4: 349 EXPECT_CALL(*gl, Uniform4iv(info.real_location, info.size, _)) 350 .Times(1) 351 .RetiresOnSaturation(); 352 break; 353 case GL_FLOAT_MAT2: 354 EXPECT_CALL(*gl, UniformMatrix2fv( 355 info.real_location, info.size, false, _)) 356 .Times(1) 357 .RetiresOnSaturation(); 358 break; 359 case GL_FLOAT_MAT3: 360 EXPECT_CALL(*gl, UniformMatrix3fv( 361 info.real_location, info.size, false, _)) 362 .Times(1) 363 .RetiresOnSaturation(); 364 break; 365 case GL_FLOAT_MAT4: 366 EXPECT_CALL(*gl, UniformMatrix4fv( 367 info.real_location, info.size, false, _)) 368 .Times(1) 369 .RetiresOnSaturation(); 370 break; 371 default: 372 NOTREACHED(); 373 break; 374 } 375 } 376} 377 378void TestHelper::SetupProgramSuccessExpectations( 379 ::gfx::MockGLInterface* gl, 380 AttribInfo* attribs, size_t num_attribs, 381 UniformInfo* uniforms, size_t num_uniforms, 382 GLuint service_id) { 383 EXPECT_CALL(*gl, 384 GetProgramiv(service_id, GL_LINK_STATUS, _)) 385 .WillOnce(SetArgumentPointee<2>(1)) 386 .RetiresOnSaturation(); 387 EXPECT_CALL(*gl, 388 GetProgramiv(service_id, GL_INFO_LOG_LENGTH, _)) 389 .WillOnce(SetArgumentPointee<2>(0)) 390 .RetiresOnSaturation(); 391 EXPECT_CALL(*gl, 392 GetProgramiv(service_id, GL_ACTIVE_ATTRIBUTES, _)) 393 .WillOnce(SetArgumentPointee<2>(num_attribs)) 394 .RetiresOnSaturation(); 395 size_t max_attrib_len = 0; 396 for (size_t ii = 0; ii < num_attribs; ++ii) { 397 size_t len = strlen(attribs[ii].name) + 1; 398 max_attrib_len = std::max(max_attrib_len, len); 399 } 400 EXPECT_CALL(*gl, 401 GetProgramiv(service_id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, _)) 402 .WillOnce(SetArgumentPointee<2>(max_attrib_len)) 403 .RetiresOnSaturation(); 404 405 for (size_t ii = 0; ii < num_attribs; ++ii) { 406 const AttribInfo& info = attribs[ii]; 407 EXPECT_CALL(*gl, 408 GetActiveAttrib(service_id, ii, 409 max_attrib_len, _, _, _, _)) 410 .WillOnce(DoAll( 411 SetArgumentPointee<3>(strlen(info.name)), 412 SetArgumentPointee<4>(info.size), 413 SetArgumentPointee<5>(info.type), 414 SetArrayArgument<6>(info.name, 415 info.name + strlen(info.name) + 1))) 416 .RetiresOnSaturation(); 417 if (!ProgramManager::IsInvalidPrefix(info.name, strlen(info.name))) { 418 EXPECT_CALL(*gl, GetAttribLocation(service_id, StrEq(info.name))) 419 .WillOnce(Return(info.location)) 420 .RetiresOnSaturation(); 421 } 422 } 423 EXPECT_CALL(*gl, 424 GetProgramiv(service_id, GL_ACTIVE_UNIFORMS, _)) 425 .WillOnce(SetArgumentPointee<2>(num_uniforms)) 426 .RetiresOnSaturation(); 427 428 size_t max_uniform_len = 0; 429 for (size_t ii = 0; ii < num_uniforms; ++ii) { 430 size_t len = strlen(uniforms[ii].name) + 1; 431 max_uniform_len = std::max(max_uniform_len, len); 432 } 433 EXPECT_CALL(*gl, 434 GetProgramiv(service_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, _)) 435 .WillOnce(SetArgumentPointee<2>(max_uniform_len)) 436 .RetiresOnSaturation(); 437 for (size_t ii = 0; ii < num_uniforms; ++ii) { 438 const UniformInfo& info = uniforms[ii]; 439 EXPECT_CALL(*gl, 440 GetActiveUniform(service_id, ii, 441 max_uniform_len, _, _, _, _)) 442 .WillOnce(DoAll( 443 SetArgumentPointee<3>(strlen(info.name)), 444 SetArgumentPointee<4>(info.size), 445 SetArgumentPointee<5>(info.type), 446 SetArrayArgument<6>(info.name, 447 info.name + strlen(info.name) + 1))) 448 .RetiresOnSaturation(); 449 } 450 451 for (int pass = 0; pass < 2; ++pass) { 452 for (size_t ii = 0; ii < num_uniforms; ++ii) { 453 const UniformInfo& info = uniforms[ii]; 454 if (ProgramManager::IsInvalidPrefix(info.name, strlen(info.name))) { 455 continue; 456 } 457 if (pass == 0) { 458 EXPECT_CALL(*gl, GetUniformLocation(service_id, StrEq(info.name))) 459 .WillOnce(Return(info.real_location)) 460 .RetiresOnSaturation(); 461 } 462 if ((pass == 0 && info.desired_location >= 0) || 463 (pass == 1 && info.desired_location < 0)) { 464 if (info.size > 1) { 465 std::string base_name = info.name; 466 size_t array_pos = base_name.rfind("[0]"); 467 if (base_name.size() > 3 && array_pos == base_name.size() - 3) { 468 base_name = base_name.substr(0, base_name.size() - 3); 469 } 470 for (GLsizei jj = 1; jj < info.size; ++jj) { 471 std::string element_name( 472 std::string(base_name) + "[" + base::IntToString(jj) + "]"); 473 EXPECT_CALL(*gl, GetUniformLocation( 474 service_id, StrEq(element_name))) 475 .WillOnce(Return(info.real_location + jj * 2)) 476 .RetiresOnSaturation(); 477 } 478 } 479 } 480 } 481 } 482} 483 484void TestHelper::SetupShader( 485 ::gfx::MockGLInterface* gl, 486 AttribInfo* attribs, size_t num_attribs, 487 UniformInfo* uniforms, size_t num_uniforms, 488 GLuint service_id) { 489 InSequence s; 490 491 EXPECT_CALL(*gl, 492 LinkProgram(service_id)) 493 .Times(1) 494 .RetiresOnSaturation(); 495 496 SetupProgramSuccessExpectations( 497 gl, attribs, num_attribs, uniforms, num_uniforms, service_id); 498} 499 500void TestHelper::DoBufferData( 501 ::gfx::MockGLInterface* gl, MockErrorState* error_state, 502 BufferManager* manager, Buffer* buffer, GLsizeiptr size, GLenum usage, 503 const GLvoid* data, GLenum error) { 504 EXPECT_CALL(*error_state, CopyRealGLErrorsToWrapper(_, _, _)) 505 .Times(1) 506 .RetiresOnSaturation(); 507 if (manager->IsUsageClientSideArray(usage)) { 508 EXPECT_CALL(*gl, BufferData( 509 buffer->target(), 0, _, usage)) 510 .Times(1) 511 .RetiresOnSaturation(); 512 } else { 513 EXPECT_CALL(*gl, BufferData( 514 buffer->target(), size, _, usage)) 515 .Times(1) 516 .RetiresOnSaturation(); 517 } 518 EXPECT_CALL(*error_state, PeekGLError(_, _, _)) 519 .WillOnce(Return(error)) 520 .RetiresOnSaturation(); 521 manager->DoBufferData(error_state, buffer, size, usage, data); 522} 523 524void TestHelper::SetTexParameterWithExpectations( 525 ::gfx::MockGLInterface* gl, MockErrorState* error_state, 526 TextureManager* manager, Texture* texture, 527 GLenum pname, GLint value, GLenum error) { 528 if (error == GL_NO_ERROR) { 529 if (pname != GL_TEXTURE_POOL_CHROMIUM) { 530 EXPECT_CALL(*gl, TexParameteri(texture->target(), pname, value)) 531 .Times(1) 532 .RetiresOnSaturation(); 533 } 534 } else if (error == GL_INVALID_ENUM) { 535 EXPECT_CALL(*error_state, SetGLErrorInvalidEnum(_, _, _, value, _)) 536 .Times(1) 537 .RetiresOnSaturation(); 538 } else { 539 EXPECT_CALL(*error_state, SetGLErrorInvalidParam(_, _, error, _, _, _)) 540 .Times(1) 541 .RetiresOnSaturation(); 542 } 543 manager->SetParameter("", error_state, texture, pname, value); 544} 545 546ScopedGLImplementationSetter::ScopedGLImplementationSetter( 547 gfx::GLImplementation implementation) 548 : old_implementation_(gfx::GetGLImplementation()) { 549 gfx::SetGLImplementation(implementation); 550} 551 552ScopedGLImplementationSetter::~ScopedGLImplementationSetter() { 553 gfx::SetGLImplementation(old_implementation_); 554} 555 556} // namespace gles2 557} // namespace gpu 558 559