|  | // Copyright 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "cc/test/test_web_graphics_context_3d.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <string> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/lazy_instance.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/message_loop/message_loop.h" | 
|  | #include "cc/test/test_context_support.h" | 
|  | #include "gpu/GLES2/gl2extchromium.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "third_party/khronos/GLES2/gl2ext.h" | 
|  |  | 
|  | namespace cc { | 
|  |  | 
|  | static const GLuint kFramebufferId = 1; | 
|  | static const GLuint kRenderbufferId = 2; | 
|  |  | 
|  | static unsigned s_context_id = 1; | 
|  |  | 
|  | const GLuint TestWebGraphicsContext3D::kExternalTextureId = 1337; | 
|  |  | 
|  | static base::LazyInstance<base::Lock>::Leaky | 
|  | g_shared_namespace_lock = LAZY_INSTANCE_INITIALIZER; | 
|  |  | 
|  | TestWebGraphicsContext3D::Namespace* | 
|  | TestWebGraphicsContext3D::shared_namespace_ = NULL; | 
|  |  | 
|  | TestWebGraphicsContext3D::Namespace::Namespace() | 
|  | : next_buffer_id(1), | 
|  | next_image_id(1), | 
|  | next_texture_id(1) { | 
|  | } | 
|  |  | 
|  | TestWebGraphicsContext3D::Namespace::~Namespace() { | 
|  | g_shared_namespace_lock.Get().AssertAcquired(); | 
|  | if (shared_namespace_ == this) | 
|  | shared_namespace_ = NULL; | 
|  | } | 
|  |  | 
|  | // static | 
|  | scoped_ptr<TestWebGraphicsContext3D> TestWebGraphicsContext3D::Create() { | 
|  | return make_scoped_ptr(new TestWebGraphicsContext3D()); | 
|  | } | 
|  |  | 
|  | TestWebGraphicsContext3D::TestWebGraphicsContext3D() | 
|  | : context_id_(s_context_id++), | 
|  | times_bind_texture_succeeds_(-1), | 
|  | times_end_query_succeeds_(-1), | 
|  | context_lost_(false), | 
|  | times_map_buffer_chromium_succeeds_(-1), | 
|  | current_used_transfer_buffer_usage_bytes_(0), | 
|  | max_used_transfer_buffer_usage_bytes_(0), | 
|  | next_program_id_(1000), | 
|  | next_shader_id_(2000), | 
|  | max_texture_size_(2048), | 
|  | reshape_called_(false), | 
|  | width_(0), | 
|  | height_(0), | 
|  | scale_factor_(-1.f), | 
|  | test_support_(NULL), | 
|  | last_update_type_(NoUpdate), | 
|  | next_insert_sync_point_(1), | 
|  | last_waited_sync_point_(0), | 
|  | unpack_alignment_(4), | 
|  | bound_buffer_(0), | 
|  | weak_ptr_factory_(this) { | 
|  | CreateNamespace(); | 
|  | } | 
|  |  | 
|  | TestWebGraphicsContext3D::~TestWebGraphicsContext3D() { | 
|  | base::AutoLock lock(g_shared_namespace_lock.Get()); | 
|  | namespace_ = NULL; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::CreateNamespace() { | 
|  | base::AutoLock lock(g_shared_namespace_lock.Get()); | 
|  | if (shared_namespace_) { | 
|  | namespace_ = shared_namespace_; | 
|  | } else { | 
|  | namespace_ = new Namespace; | 
|  | shared_namespace_ = namespace_.get(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::reshapeWithScaleFactor( | 
|  | int width, int height, float scale_factor) { | 
|  | reshape_called_ = true; | 
|  | width_ = width; | 
|  | height_ = height; | 
|  | scale_factor_ = scale_factor; | 
|  | } | 
|  |  | 
|  | bool TestWebGraphicsContext3D::isContextLost() { | 
|  | return context_lost_; | 
|  | } | 
|  |  | 
|  | GLenum TestWebGraphicsContext3D::checkFramebufferStatus( | 
|  | GLenum target) { | 
|  | if (context_lost_) | 
|  | return GL_FRAMEBUFFER_UNDEFINED_OES; | 
|  | return GL_FRAMEBUFFER_COMPLETE; | 
|  | } | 
|  |  | 
|  | GLint TestWebGraphicsContext3D::getUniformLocation( | 
|  | GLuint program, | 
|  | const GLchar* name) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | GLsizeiptr TestWebGraphicsContext3D::getVertexAttribOffset( | 
|  | GLuint index, | 
|  | GLenum pname) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | GLboolean TestWebGraphicsContext3D::isBuffer( | 
|  | GLuint buffer) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | GLboolean TestWebGraphicsContext3D::isEnabled( | 
|  | GLenum cap) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | GLboolean TestWebGraphicsContext3D::isFramebuffer( | 
|  | GLuint framebuffer) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | GLboolean TestWebGraphicsContext3D::isProgram( | 
|  | GLuint program) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | GLboolean TestWebGraphicsContext3D::isRenderbuffer( | 
|  | GLuint renderbuffer) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | GLboolean TestWebGraphicsContext3D::isShader( | 
|  | GLuint shader) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | GLboolean TestWebGraphicsContext3D::isTexture( | 
|  | GLuint texture) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::genBuffers(GLsizei count, GLuint* ids) { | 
|  | for (int i = 0; i < count; ++i) | 
|  | ids[i] = NextBufferId(); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::genFramebuffers( | 
|  | GLsizei count, GLuint* ids) { | 
|  | for (int i = 0; i < count; ++i) | 
|  | ids[i] = kFramebufferId | context_id_ << 16; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::genRenderbuffers( | 
|  | GLsizei count, GLuint* ids) { | 
|  | for (int i = 0; i < count; ++i) | 
|  | ids[i] = kRenderbufferId | context_id_ << 16; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::genTextures(GLsizei count, GLuint* ids) { | 
|  | for (int i = 0; i < count; ++i) { | 
|  | ids[i] = NextTextureId(); | 
|  | DCHECK_NE(ids[i], kExternalTextureId); | 
|  | } | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | for (int i = 0; i < count; ++i) | 
|  | namespace_->textures.Append(ids[i], new TestTexture()); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::deleteBuffers(GLsizei count, GLuint* ids) { | 
|  | for (int i = 0; i < count; ++i) | 
|  | RetireBufferId(ids[i]); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::deleteFramebuffers( | 
|  | GLsizei count, GLuint* ids) { | 
|  | for (int i = 0; i < count; ++i) | 
|  | DCHECK_EQ(kFramebufferId | context_id_ << 16, ids[i]); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::deleteRenderbuffers( | 
|  | GLsizei count, GLuint* ids) { | 
|  | for (int i = 0; i < count; ++i) | 
|  | DCHECK_EQ(kRenderbufferId | context_id_ << 16, ids[i]); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::deleteTextures(GLsizei count, GLuint* ids) { | 
|  | for (int i = 0; i < count; ++i) | 
|  | RetireTextureId(ids[i]); | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | for (int i = 0; i < count; ++i) { | 
|  | namespace_->textures.Remove(ids[i]); | 
|  | texture_targets_.UnbindTexture(ids[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::createBuffer() { | 
|  | GLuint id; | 
|  | genBuffers(1, &id); | 
|  | return id; | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::createFramebuffer() { | 
|  | GLuint id; | 
|  | genFramebuffers(1, &id); | 
|  | return id; | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::createRenderbuffer() { | 
|  | GLuint id; | 
|  | genRenderbuffers(1, &id); | 
|  | return id; | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::createTexture() { | 
|  | GLuint id; | 
|  | genTextures(1, &id); | 
|  | return id; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::deleteBuffer(GLuint id) { | 
|  | deleteBuffers(1, &id); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::deleteFramebuffer(GLuint id) { | 
|  | deleteFramebuffers(1, &id); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::deleteRenderbuffer(GLuint id) { | 
|  | deleteRenderbuffers(1, &id); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::deleteTexture(GLuint id) { | 
|  | deleteTextures(1, &id); | 
|  | } | 
|  |  | 
|  | unsigned TestWebGraphicsContext3D::createProgram() { | 
|  | unsigned program = next_program_id_++ | context_id_ << 16; | 
|  | program_set_.insert(program); | 
|  | return program; | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::createShader(GLenum) { | 
|  | unsigned shader = next_shader_id_++ | context_id_ << 16; | 
|  | shader_set_.insert(shader); | 
|  | return shader; | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::createExternalTexture() { | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | namespace_->textures.Append(kExternalTextureId, new TestTexture()); | 
|  | return kExternalTextureId; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::deleteProgram(GLuint id) { | 
|  | if (!program_set_.count(id)) | 
|  | ADD_FAILURE() << "deleteProgram called on unknown program " << id; | 
|  | program_set_.erase(id); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::deleteShader(GLuint id) { | 
|  | if (!shader_set_.count(id)) | 
|  | ADD_FAILURE() << "deleteShader called on unknown shader " << id; | 
|  | shader_set_.erase(id); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::attachShader(GLuint program, GLuint shader) { | 
|  | if (!program_set_.count(program)) | 
|  | ADD_FAILURE() << "attachShader called with unknown program " << program; | 
|  | if (!shader_set_.count(shader)) | 
|  | ADD_FAILURE() << "attachShader called with unknown shader " << shader; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::useProgram(GLuint program) { | 
|  | if (!program) | 
|  | return; | 
|  | if (!program_set_.count(program)) | 
|  | ADD_FAILURE() << "useProgram called on unknown program " << program; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::bindFramebuffer( | 
|  | GLenum target, GLuint framebuffer) { | 
|  | if (!framebuffer) | 
|  | return; | 
|  | DCHECK_EQ(kFramebufferId | context_id_ << 16, framebuffer); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::bindRenderbuffer( | 
|  | GLenum target, GLuint renderbuffer) { | 
|  | if (!renderbuffer) | 
|  | return; | 
|  | DCHECK_EQ(kRenderbufferId | context_id_ << 16, renderbuffer); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::bindTexture( | 
|  | GLenum target, GLuint texture_id) { | 
|  | if (times_bind_texture_succeeds_ >= 0) { | 
|  | if (!times_bind_texture_succeeds_) { | 
|  | loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, | 
|  | GL_INNOCENT_CONTEXT_RESET_ARB); | 
|  | } | 
|  | --times_bind_texture_succeeds_; | 
|  | } | 
|  |  | 
|  | if (!texture_id) | 
|  | return; | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | DCHECK(namespace_->textures.ContainsId(texture_id)); | 
|  | texture_targets_.BindTexture(target, texture_id); | 
|  | used_textures_.insert(texture_id); | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::BoundTextureId( | 
|  | GLenum target) { | 
|  | return texture_targets_.BoundTexture(target); | 
|  | } | 
|  |  | 
|  | scoped_refptr<TestTexture> TestWebGraphicsContext3D::BoundTexture( | 
|  | GLenum target) { | 
|  | // The caller is expected to lock the namespace for texture access. | 
|  | namespace_->lock.AssertAcquired(); | 
|  | return namespace_->textures.TextureForId(BoundTextureId(target)); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::CheckTextureIsBound(GLenum target) { | 
|  | DCHECK(BoundTextureId(target)); | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::createQueryEXT() { return 1u; } | 
|  |  | 
|  | void TestWebGraphicsContext3D::endQueryEXT(GLenum target) { | 
|  | if (times_end_query_succeeds_ >= 0) { | 
|  | if (!times_end_query_succeeds_) { | 
|  | loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, | 
|  | GL_INNOCENT_CONTEXT_RESET_ARB); | 
|  | } | 
|  | --times_end_query_succeeds_; | 
|  | } | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::getQueryObjectuivEXT( | 
|  | GLuint query, | 
|  | GLenum pname, | 
|  | GLuint* params) { | 
|  | // If the context is lost, behave as if result is available. | 
|  | if (pname == GL_QUERY_RESULT_AVAILABLE_EXT) | 
|  | *params = 1; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::getIntegerv( | 
|  | GLenum pname, | 
|  | GLint* value) { | 
|  | if (pname == GL_MAX_TEXTURE_SIZE) | 
|  | *value = max_texture_size_; | 
|  | else if (pname == GL_ACTIVE_TEXTURE) | 
|  | *value = GL_TEXTURE0; | 
|  | else if (pname == GL_UNPACK_ALIGNMENT) | 
|  | *value = unpack_alignment_; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::getProgramiv(GLuint program, | 
|  | GLenum pname, | 
|  | GLint* value) { | 
|  | if (pname == GL_LINK_STATUS) | 
|  | *value = 1; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::getShaderiv(GLuint shader, | 
|  | GLenum pname, | 
|  | GLint* value) { | 
|  | if (pname == GL_COMPILE_STATUS) | 
|  | *value = 1; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::getShaderPrecisionFormat(GLenum shadertype, | 
|  | GLenum precisiontype, | 
|  | GLint* range, | 
|  | GLint* precision) { | 
|  | // Return the minimum precision requirements of the GLES2 | 
|  | // specification. | 
|  | switch (precisiontype) { | 
|  | case GL_LOW_INT: | 
|  | range[0] = 8; | 
|  | range[1] = 8; | 
|  | *precision = 0; | 
|  | break; | 
|  | case GL_MEDIUM_INT: | 
|  | range[0] = 10; | 
|  | range[1] = 10; | 
|  | *precision = 0; | 
|  | break; | 
|  | case GL_HIGH_INT: | 
|  | range[0] = 16; | 
|  | range[1] = 16; | 
|  | *precision = 0; | 
|  | break; | 
|  | case GL_LOW_FLOAT: | 
|  | range[0] = 8; | 
|  | range[1] = 8; | 
|  | *precision = 8; | 
|  | break; | 
|  | case GL_MEDIUM_FLOAT: | 
|  | range[0] = 14; | 
|  | range[1] = 14; | 
|  | *precision = 10; | 
|  | break; | 
|  | case GL_HIGH_FLOAT: | 
|  | range[0] = 62; | 
|  | range[1] = 62; | 
|  | *precision = 16; | 
|  | break; | 
|  | default: | 
|  | NOTREACHED(); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::genMailboxCHROMIUM(GLbyte* mailbox) { | 
|  | static char mailbox_name1 = '1'; | 
|  | static char mailbox_name2 = '1'; | 
|  | mailbox[0] = mailbox_name1; | 
|  | mailbox[1] = mailbox_name2; | 
|  | mailbox[2] = '\0'; | 
|  | if (++mailbox_name1 == 0) { | 
|  | mailbox_name1 = '1'; | 
|  | ++mailbox_name2; | 
|  | } | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::createAndConsumeTextureCHROMIUM( | 
|  | GLenum target, | 
|  | const GLbyte* mailbox) { | 
|  | return createTexture(); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::loseContextCHROMIUM(GLenum current, | 
|  | GLenum other) { | 
|  | if (context_lost_) | 
|  | return; | 
|  | context_lost_ = true; | 
|  | if (!context_lost_callback_.is_null()) | 
|  | context_lost_callback_.Run(); | 
|  |  | 
|  | for (size_t i = 0; i < shared_contexts_.size(); ++i) | 
|  | shared_contexts_[i]->loseContextCHROMIUM(current, other); | 
|  | shared_contexts_.clear(); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::finish() { | 
|  | test_support_->CallAllSyncPointCallbacks(); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::flush() { | 
|  | test_support_->CallAllSyncPointCallbacks(); | 
|  | } | 
|  |  | 
|  | GLint TestWebGraphicsContext3D::getAttribLocation(GLuint program, | 
|  | const GLchar* name) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | GLenum TestWebGraphicsContext3D::getError() { return GL_NO_ERROR; } | 
|  |  | 
|  | void TestWebGraphicsContext3D::bindBuffer(GLenum target, | 
|  | GLuint buffer) { | 
|  | bound_buffer_ = buffer; | 
|  | if (!bound_buffer_) | 
|  | return; | 
|  | unsigned context_id = buffer >> 16; | 
|  | unsigned buffer_id = buffer & 0xffff; | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | DCHECK(buffer_id); | 
|  | DCHECK_LT(buffer_id, namespace_->next_buffer_id); | 
|  | DCHECK_EQ(context_id, context_id_); | 
|  |  | 
|  | base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers; | 
|  | if (buffers.count(bound_buffer_) == 0) | 
|  | buffers.set(bound_buffer_, make_scoped_ptr(new Buffer).Pass()); | 
|  |  | 
|  | buffers.get(bound_buffer_)->target = target; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::bufferData(GLenum target, | 
|  | GLsizeiptr size, | 
|  | const void* data, | 
|  | GLenum usage) { | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers; | 
|  | DCHECK_GT(buffers.count(bound_buffer_), 0u); | 
|  | DCHECK_EQ(target, buffers.get(bound_buffer_)->target); | 
|  | Buffer* buffer = buffers.get(bound_buffer_); | 
|  | if (context_lost_) { | 
|  | buffer->pixels = nullptr; | 
|  | return; | 
|  | } | 
|  |  | 
|  | size_t old_size = buffer->size; | 
|  |  | 
|  | buffer->pixels.reset(new uint8[size]); | 
|  | buffer->size = size; | 
|  | if (data != NULL) | 
|  | memcpy(buffer->pixels.get(), data, size); | 
|  | if (buffer->target == GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM) | 
|  | current_used_transfer_buffer_usage_bytes_ += buffer->size - old_size; | 
|  | max_used_transfer_buffer_usage_bytes_ = | 
|  | std::max(max_used_transfer_buffer_usage_bytes_, | 
|  | current_used_transfer_buffer_usage_bytes_); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::pixelStorei(GLenum pname, GLint param) { | 
|  | switch (pname) { | 
|  | case GL_UNPACK_ALIGNMENT: | 
|  | // Param should be a power of two <= 8. | 
|  | EXPECT_EQ(0, param & (param - 1)); | 
|  | EXPECT_GE(8, param); | 
|  | switch (param) { | 
|  | case 1: | 
|  | case 2: | 
|  | case 4: | 
|  | case 8: | 
|  | unpack_alignment_ = param; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void* TestWebGraphicsContext3D::mapBufferCHROMIUM(GLenum target, | 
|  | GLenum access) { | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers; | 
|  | DCHECK_GT(buffers.count(bound_buffer_), 0u); | 
|  | DCHECK_EQ(target, buffers.get(bound_buffer_)->target); | 
|  | if (times_map_buffer_chromium_succeeds_ >= 0) { | 
|  | if (!times_map_buffer_chromium_succeeds_) { | 
|  | return NULL; | 
|  | } | 
|  | --times_map_buffer_chromium_succeeds_; | 
|  | } | 
|  |  | 
|  | return buffers.get(bound_buffer_)->pixels.get(); | 
|  | } | 
|  |  | 
|  | GLboolean TestWebGraphicsContext3D::unmapBufferCHROMIUM( | 
|  | GLenum target) { | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers; | 
|  | DCHECK_GT(buffers.count(bound_buffer_), 0u); | 
|  | DCHECK_EQ(target, buffers.get(bound_buffer_)->target); | 
|  | buffers.get(bound_buffer_)->pixels = nullptr; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::createImageCHROMIUM(ClientBuffer buffer, | 
|  | GLsizei width, | 
|  | GLsizei height, | 
|  | GLenum internalformat) { | 
|  | DCHECK_EQ(GL_RGBA, static_cast<int>(internalformat)); | 
|  | GLuint image_id = NextImageId(); | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | base::hash_set<unsigned>& images = namespace_->images; | 
|  | images.insert(image_id); | 
|  | return image_id; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::destroyImageCHROMIUM( | 
|  | GLuint id) { | 
|  | RetireImageId(id); | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | base::hash_set<unsigned>& images = namespace_->images; | 
|  | if (!images.count(id)) | 
|  | ADD_FAILURE() << "destroyImageCHROMIUM called on unknown image " << id; | 
|  | images.erase(id); | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::createGpuMemoryBufferImageCHROMIUM( | 
|  | GLsizei width, | 
|  | GLsizei height, | 
|  | GLenum internalformat, | 
|  | GLenum usage) { | 
|  | DCHECK_EQ(GL_RGBA, static_cast<int>(internalformat)); | 
|  | GLuint image_id = NextImageId(); | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | base::hash_set<unsigned>& images = namespace_->images; | 
|  | images.insert(image_id); | 
|  | return image_id; | 
|  | } | 
|  |  | 
|  | unsigned TestWebGraphicsContext3D::insertSyncPoint() { | 
|  | return next_insert_sync_point_++; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::waitSyncPoint(unsigned sync_point) { | 
|  | if (sync_point) | 
|  | last_waited_sync_point_ = sync_point; | 
|  | } | 
|  |  | 
|  | size_t TestWebGraphicsContext3D::NumTextures() const { | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | return namespace_->textures.Size(); | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::TextureAt(int i) const { | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | return namespace_->textures.IdAt(i); | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::NextTextureId() { | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | GLuint texture_id = namespace_->next_texture_id++; | 
|  | DCHECK(texture_id < (1 << 16)); | 
|  | texture_id |= context_id_ << 16; | 
|  | return texture_id; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::RetireTextureId(GLuint id) { | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | unsigned context_id = id >> 16; | 
|  | unsigned texture_id = id & 0xffff; | 
|  | DCHECK(texture_id); | 
|  | DCHECK_LT(texture_id, namespace_->next_texture_id); | 
|  | DCHECK_EQ(context_id, context_id_); | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::NextBufferId() { | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | GLuint buffer_id = namespace_->next_buffer_id++; | 
|  | DCHECK(buffer_id < (1 << 16)); | 
|  | buffer_id |= context_id_ << 16; | 
|  | return buffer_id; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::RetireBufferId(GLuint id) { | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | unsigned context_id = id >> 16; | 
|  | unsigned buffer_id = id & 0xffff; | 
|  | DCHECK(buffer_id); | 
|  | DCHECK_LT(buffer_id, namespace_->next_buffer_id); | 
|  | DCHECK_EQ(context_id, context_id_); | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::NextImageId() { | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | GLuint image_id = namespace_->next_image_id++; | 
|  | DCHECK(image_id < (1 << 16)); | 
|  | image_id |= context_id_ << 16; | 
|  | return image_id; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::RetireImageId(GLuint id) { | 
|  | base::AutoLock lock(namespace_->lock); | 
|  | unsigned context_id = id >> 16; | 
|  | unsigned image_id = id & 0xffff; | 
|  | DCHECK(image_id); | 
|  | DCHECK_LT(image_id, namespace_->next_image_id); | 
|  | DCHECK_EQ(context_id, context_id_); | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::SetMaxTransferBufferUsageBytes( | 
|  | size_t max_transfer_buffer_usage_bytes) { | 
|  | test_capabilities_.max_transfer_buffer_usage_bytes = | 
|  | max_transfer_buffer_usage_bytes; | 
|  | } | 
|  |  | 
|  | TestWebGraphicsContext3D::TextureTargets::TextureTargets() { | 
|  | // Initialize default bindings. | 
|  | bound_textures_[GL_TEXTURE_2D] = 0; | 
|  | bound_textures_[GL_TEXTURE_EXTERNAL_OES] = 0; | 
|  | bound_textures_[GL_TEXTURE_RECTANGLE_ARB] = 0; | 
|  | } | 
|  |  | 
|  | TestWebGraphicsContext3D::TextureTargets::~TextureTargets() {} | 
|  |  | 
|  | void TestWebGraphicsContext3D::TextureTargets::BindTexture( | 
|  | GLenum target, | 
|  | GLuint id) { | 
|  | // Make sure this is a supported target by seeing if it was bound to before. | 
|  | DCHECK(bound_textures_.find(target) != bound_textures_.end()); | 
|  | bound_textures_[target] = id; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::texParameteri(GLenum target, | 
|  | GLenum pname, | 
|  | GLint param) { | 
|  | CheckTextureIsBound(target); | 
|  | base::AutoLock lock_for_texture_access(namespace_->lock); | 
|  | scoped_refptr<TestTexture> texture = BoundTexture(target); | 
|  | DCHECK(texture->IsValidParameter(pname)); | 
|  | texture->params[pname] = param; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::getTexParameteriv(GLenum target, | 
|  | GLenum pname, | 
|  | GLint* value) { | 
|  | CheckTextureIsBound(target); | 
|  | base::AutoLock lock_for_texture_access(namespace_->lock); | 
|  | scoped_refptr<TestTexture> texture = BoundTexture(target); | 
|  | DCHECK(texture->IsValidParameter(pname)); | 
|  | TestTexture::TextureParametersMap::iterator it = texture->params.find(pname); | 
|  | if (it != texture->params.end()) | 
|  | *value = it->second; | 
|  | } | 
|  |  | 
|  | void TestWebGraphicsContext3D::TextureTargets::UnbindTexture( | 
|  | GLuint id) { | 
|  | // Bind zero to any targets that the id is bound to. | 
|  | for (TargetTextureMap::iterator it = bound_textures_.begin(); | 
|  | it != bound_textures_.end(); | 
|  | it++) { | 
|  | if (it->second == id) | 
|  | it->second = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | GLuint TestWebGraphicsContext3D::TextureTargets::BoundTexture( | 
|  | GLenum target) { | 
|  | DCHECK(bound_textures_.find(target) != bound_textures_.end()); | 
|  | return bound_textures_[target]; | 
|  | } | 
|  |  | 
|  | TestWebGraphicsContext3D::Buffer::Buffer() : target(0), size(0) {} | 
|  |  | 
|  | TestWebGraphicsContext3D::Buffer::~Buffer() {} | 
|  |  | 
|  | TestWebGraphicsContext3D::Image::Image() {} | 
|  |  | 
|  | TestWebGraphicsContext3D::Image::~Image() {} | 
|  |  | 
|  | }  // namespace cc |