| // 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 "components/viz/test/test_gles2_interface.h" |
| |
| #include "base/bind.h" |
| #include "base/lazy_instance.h" |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "components/viz/test/test_context_support.h" |
| #include "gpu/GLES2/gl2extchromium.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace viz { |
| |
| static unsigned NextContextId() { |
| static uint16_t s_context_id = 1; |
| // We need to ensure that the context_id fits in 16 bits since it is placed on |
| // the top 16 bits of the 32 bit identifiers (program_id, framebuffer_id, |
| // shader_id, etc.) generated by the context. |
| if (s_context_id == std::numeric_limits<uint16_t>::max()) { |
| LOG(ERROR) << "Exceeded max context id count; wrapping around"; |
| s_context_id = 1; |
| } |
| return s_context_id++; |
| } |
| |
| const GLuint TestGLES2Interface::kExternalTextureId = 1337; |
| |
| static base::LazyInstance<base::Lock>::Leaky g_shared_namespace_lock = |
| LAZY_INSTANCE_INITIALIZER; |
| |
| TestGLES2Interface::Namespace* TestGLES2Interface::shared_namespace_ = nullptr; |
| TestGLES2Interface::Namespace::Namespace() |
| : next_buffer_id(1), |
| next_image_id(1), |
| next_texture_id(1), |
| next_renderbuffer_id(1) {} |
| |
| TestGLES2Interface::Namespace::~Namespace() { |
| g_shared_namespace_lock.Get().AssertAcquired(); |
| if (shared_namespace_ == this) |
| shared_namespace_ = nullptr; |
| } |
| |
| TestGLES2Interface::TestGLES2Interface() |
| : context_id_(NextContextId()), |
| times_bind_texture_succeeds_(-1), |
| times_end_query_succeeds_(-1), |
| context_lost_(false), |
| times_map_buffer_chromium_succeeds_(-1), |
| next_program_id_(1000), |
| next_shader_id_(2000), |
| next_framebuffer_id_(1), |
| current_framebuffer_(0), |
| reshape_called_(false), |
| width_(0), |
| height_(0), |
| scale_factor_(-1.f), |
| test_support_(nullptr), |
| last_update_type_(NO_UPDATE), |
| next_insert_fence_sync_(1), |
| unpack_alignment_(4), |
| weak_ptr_factory_(this) { |
| // For stream textures. |
| set_have_extension_egl_image(true); |
| set_max_texture_size(2048); |
| |
| CreateNamespace(); |
| } |
| |
| TestGLES2Interface::~TestGLES2Interface() { |
| base::AutoLock lock(g_shared_namespace_lock.Get()); |
| namespace_ = nullptr; |
| } |
| |
| void TestGLES2Interface::CreateNamespace() { |
| base::AutoLock lock(g_shared_namespace_lock.Get()); |
| if (shared_namespace_) { |
| namespace_ = shared_namespace_; |
| } else { |
| namespace_ = base::MakeRefCounted<Namespace>(); |
| shared_namespace_ = namespace_.get(); |
| } |
| } |
| |
| void TestGLES2Interface::GenTextures(GLsizei n, GLuint* textures) { |
| for (int i = 0; i < n; ++i) { |
| textures[i] = NextTextureId(); |
| DCHECK_NE(textures[i], kExternalTextureId); |
| } |
| base::AutoLock lock(namespace_->lock); |
| |
| for (int i = 0; i < n; ++i) |
| namespace_->textures.Append(textures[i], |
| base::MakeRefCounted<TestTexture>()); |
| } |
| |
| void TestGLES2Interface::GenBuffers(GLsizei n, GLuint* buffers) { |
| for (int i = 0; i < n; ++i) |
| buffers[i] = NextBufferId(); |
| } |
| |
| void TestGLES2Interface::GenFramebuffers(GLsizei n, GLuint* framebuffers) { |
| for (int i = 0; i < n; ++i) |
| framebuffers[i] = NextFramebufferId(); |
| } |
| |
| void TestGLES2Interface::GenRenderbuffers(GLsizei n, GLuint* renderbuffers) { |
| for (int i = 0; i < n; ++i) |
| renderbuffers[i] = NextRenderbufferId(); |
| } |
| |
| void TestGLES2Interface::GenQueriesEXT(GLsizei n, GLuint* queries) { |
| for (GLsizei i = 0; i < n; ++i) { |
| queries[i] = 1u; |
| } |
| } |
| |
| void TestGLES2Interface::DeleteTextures(GLsizei n, const GLuint* textures) { |
| for (int i = 0; i < n; ++i) |
| RetireTextureId(textures[i]); |
| base::AutoLock lock(namespace_->lock); |
| for (int i = 0; i < n; ++i) { |
| namespace_->textures.Remove(textures[i]); |
| texture_targets_.UnbindTexture(textures[i]); |
| } |
| } |
| |
| void TestGLES2Interface::DeleteBuffers(GLsizei n, const GLuint* buffers) { |
| for (int i = 0; i < n; ++i) |
| RetireBufferId(buffers[i]); |
| } |
| |
| void TestGLES2Interface::DeleteFramebuffers(GLsizei n, |
| const GLuint* framebuffers) { |
| for (int i = 0; i < n; ++i) { |
| if (framebuffers[i]) { |
| RetireFramebufferId(framebuffers[i]); |
| if (framebuffers[i] == current_framebuffer_) |
| current_framebuffer_ = 0; |
| } |
| } |
| } |
| |
| void TestGLES2Interface::DeleteQueriesEXT(GLsizei n, const GLuint* queries) { |
| } |
| |
| GLuint TestGLES2Interface::CreateShader(GLenum type) { |
| unsigned shader = next_shader_id_++ | context_id_ << 16; |
| shader_set_.insert(shader); |
| return shader; |
| } |
| |
| GLuint TestGLES2Interface::CreateProgram() { |
| unsigned program = next_program_id_++ | context_id_ << 16; |
| program_set_.insert(program); |
| return program; |
| } |
| |
| void TestGLES2Interface::BindTexture(GLenum target, GLuint texture) { |
| 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) |
| return; |
| base::AutoLock lock(namespace_->lock); |
| DCHECK(namespace_->textures.ContainsId(texture)); |
| texture_targets_.BindTexture(target, texture); |
| used_textures_.insert(texture); |
| } |
| |
| void TestGLES2Interface::GetIntegerv(GLenum pname, GLint* params) { |
| if (pname == GL_MAX_TEXTURE_SIZE) |
| *params = test_capabilities_.max_texture_size; |
| else if (pname == GL_ACTIVE_TEXTURE) |
| *params = GL_TEXTURE0; |
| else if (pname == GL_UNPACK_ALIGNMENT) |
| *params = unpack_alignment_; |
| else if (pname == GL_FRAMEBUFFER_BINDING) |
| *params = current_framebuffer_; |
| else if (pname == GL_MAX_SAMPLES) |
| *params = test_capabilities_.max_samples; |
| } |
| |
| void TestGLES2Interface::GetShaderiv(GLuint shader, |
| GLenum pname, |
| GLint* params) { |
| if (pname == GL_COMPILE_STATUS) |
| *params = 1; |
| } |
| |
| void TestGLES2Interface::GetProgramiv(GLuint program, |
| GLenum pname, |
| GLint* params) { |
| if (pname == GL_LINK_STATUS) |
| *params = 1; |
| } |
| |
| void TestGLES2Interface::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 TestGLES2Interface::Viewport(GLint x, |
| GLint y, |
| GLsizei width, |
| GLsizei height) {} |
| |
| void TestGLES2Interface::ActiveTexture(GLenum target) {} |
| |
| void TestGLES2Interface::UseProgram(GLuint program) { |
| if (!program) |
| return; |
| if (!program_set_.count(program)) |
| ADD_FAILURE() << "useProgram called on unknown program " << program; |
| } |
| |
| GLenum TestGLES2Interface::CheckFramebufferStatus(GLenum target) { |
| if (context_lost_) |
| return GL_FRAMEBUFFER_UNDEFINED_OES; |
| return GL_FRAMEBUFFER_COMPLETE; |
| } |
| |
| void TestGLES2Interface::Scissor(GLint x, |
| GLint y, |
| GLsizei width, |
| GLsizei height) {} |
| |
| void TestGLES2Interface::DrawElements(GLenum mode, |
| GLsizei count, |
| GLenum type, |
| const void* indices) {} |
| |
| void TestGLES2Interface::ClearColor(GLclampf red, |
| GLclampf green, |
| GLclampf blue, |
| GLclampf alpha) {} |
| |
| void TestGLES2Interface::ClearStencil(GLint s) {} |
| |
| void TestGLES2Interface::Clear(GLbitfield mask) {} |
| |
| void TestGLES2Interface::Flush() { |
| test_support_->CallAllSyncPointCallbacks(); |
| } |
| |
| void TestGLES2Interface::Finish() { |
| test_support_->CallAllSyncPointCallbacks(); |
| } |
| |
| void TestGLES2Interface::ShallowFinishCHROMIUM() { |
| test_support_->CallAllSyncPointCallbacks(); |
| } |
| |
| void TestGLES2Interface::ShallowFlushCHROMIUM() { |
| } |
| |
| void TestGLES2Interface::Enable(GLenum cap) {} |
| |
| void TestGLES2Interface::Disable(GLenum cap) {} |
| |
| void TestGLES2Interface::BindRenderbuffer(GLenum target, GLuint renderbuffer) { |
| if (!renderbuffer) |
| return; |
| base::AutoLock lock_for_renderbuffer_access(namespace_->lock); |
| if (renderbuffer != 0 && namespace_->renderbuffer_set.find(renderbuffer) == |
| namespace_->renderbuffer_set.end()) { |
| ADD_FAILURE() << "bindRenderbuffer called with unknown renderbuffer"; |
| } else if ((renderbuffer >> 16) != context_id_) { |
| ADD_FAILURE() |
| << "bindRenderbuffer called with renderbuffer from other context"; |
| } |
| } |
| |
| void TestGLES2Interface::BindFramebuffer(GLenum target, GLuint framebuffer) { |
| base::AutoLock lock_for_framebuffer_access(namespace_->lock); |
| if (framebuffer != 0 && |
| framebuffer_set_.find(framebuffer) == framebuffer_set_.end()) { |
| ADD_FAILURE() << "bindFramebuffer called with unknown framebuffer"; |
| } else if (framebuffer != 0 && (framebuffer >> 16) != context_id_) { |
| ADD_FAILURE() |
| << "bindFramebuffer called with framebuffer from other context"; |
| } else { |
| current_framebuffer_ = framebuffer; |
| } |
| } |
| |
| void TestGLES2Interface::BindBuffer(GLenum target, GLuint buffer) { |
| bound_buffer_[target] = buffer; |
| if (!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_); |
| |
| std::unordered_map<unsigned, std::unique_ptr<Buffer>>& buffers = |
| namespace_->buffers; |
| if (buffers.count(bound_buffer_[target]) == 0) |
| buffers[bound_buffer_[target]] = base::WrapUnique(new Buffer); |
| |
| buffers[bound_buffer_[target]]->target = target; |
| } |
| |
| void TestGLES2Interface::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 TestGLES2Interface::TexImage2D(GLenum target, |
| GLint level, |
| GLint internalformat, |
| GLsizei width, |
| GLsizei height, |
| GLint border, |
| GLenum format, |
| GLenum type, |
| const void* pixels) {} |
| |
| void TestGLES2Interface::TexSubImage2D(GLenum target, |
| GLint level, |
| GLint xoffset, |
| GLint yoffset, |
| GLsizei width, |
| GLsizei height, |
| GLenum format, |
| GLenum type, |
| const void* pixels) {} |
| |
| void TestGLES2Interface::TexStorage2DEXT(GLenum target, |
| GLsizei levels, |
| GLenum internalformat, |
| GLsizei width, |
| GLsizei height) {} |
| |
| void TestGLES2Interface::TexStorage2DImageCHROMIUM(GLenum target, |
| GLenum internalformat, |
| GLenum bufferusage, |
| GLsizei width, |
| GLsizei height) {} |
| |
| void TestGLES2Interface::FramebufferRenderbuffer(GLenum target, |
| GLenum attachment, |
| GLenum renderbuffertarget, |
| GLuint renderbuffer) {} |
| |
| void TestGLES2Interface::FramebufferTexture2D(GLenum target, |
| GLenum attachment, |
| GLenum textarget, |
| GLuint texture, |
| GLint level) {} |
| |
| void TestGLES2Interface::RenderbufferStorage(GLenum target, |
| GLenum internalformat, |
| GLsizei width, |
| GLsizei height) {} |
| |
| void TestGLES2Interface::CompressedTexImage2D(GLenum target, |
| GLint level, |
| GLenum internalformat, |
| GLsizei width, |
| GLsizei height, |
| GLint border, |
| GLsizei image_size, |
| const void* data) {} |
| |
| GLuint TestGLES2Interface::CreateImageCHROMIUM(ClientBuffer buffer, |
| GLsizei width, |
| GLsizei height, |
| GLenum internalformat) { |
| DCHECK(internalformat == GL_RGB || internalformat == GL_RGBA || |
| (test_capabilities_.texture_format_bgra8888 && |
| internalformat == GL_BGRA_EXT)); |
| GLuint image_id = NextImageId(); |
| base::AutoLock lock(namespace_->lock); |
| std::unordered_set<unsigned>& images = namespace_->images; |
| images.insert(image_id); |
| return image_id; |
| } |
| |
| void TestGLES2Interface::DestroyImageCHROMIUM(GLuint image_id) { |
| RetireImageId(image_id); |
| base::AutoLock lock(namespace_->lock); |
| std::unordered_set<unsigned>& images = namespace_->images; |
| if (!images.count(image_id)) |
| ADD_FAILURE() << "destroyImageCHROMIUM called on unknown image " |
| << image_id; |
| images.erase(image_id); |
| } |
| |
| void TestGLES2Interface::BindTexImage2DCHROMIUM(GLenum target, GLint image_id) { |
| } |
| |
| void TestGLES2Interface::ReleaseTexImage2DCHROMIUM(GLenum target, |
| GLint image_id) {} |
| |
| void* TestGLES2Interface::MapBufferCHROMIUM(GLuint target, GLenum access) { |
| base::AutoLock lock(namespace_->lock); |
| std::unordered_map<unsigned, std::unique_ptr<Buffer>>& buffers = |
| namespace_->buffers; |
| DCHECK_GT(bound_buffer_.count(target), 0u); |
| DCHECK_GT(buffers.count(bound_buffer_[target]), 0u); |
| DCHECK_EQ(target, buffers[bound_buffer_[target]]->target); |
| if (times_map_buffer_chromium_succeeds_ >= 0) { |
| if (!times_map_buffer_chromium_succeeds_) { |
| return nullptr; |
| } |
| --times_map_buffer_chromium_succeeds_; |
| } |
| |
| return buffers[bound_buffer_[target]]->pixels.get(); |
| } |
| |
| GLboolean TestGLES2Interface::UnmapBufferCHROMIUM(GLuint target) { |
| base::AutoLock lock(namespace_->lock); |
| std::unordered_map<unsigned, std::unique_ptr<Buffer>>& buffers = |
| namespace_->buffers; |
| DCHECK_GT(bound_buffer_.count(target), 0u); |
| DCHECK_GT(buffers.count(bound_buffer_[target]), 0u); |
| DCHECK_EQ(target, buffers[bound_buffer_[target]]->target); |
| buffers[bound_buffer_[target]]->pixels = nullptr; |
| return true; |
| } |
| |
| void TestGLES2Interface::BufferData(GLenum target, |
| GLsizeiptr size, |
| const void* data, |
| GLenum usage) { |
| base::AutoLock lock(namespace_->lock); |
| std::unordered_map<unsigned, std::unique_ptr<Buffer>>& buffers = |
| namespace_->buffers; |
| DCHECK_GT(bound_buffer_.count(target), 0u); |
| DCHECK_GT(buffers.count(bound_buffer_[target]), 0u); |
| DCHECK_EQ(target, buffers[bound_buffer_[target]]->target); |
| Buffer* buffer = buffers[bound_buffer_[target]].get(); |
| if (context_lost_) { |
| buffer->pixels = nullptr; |
| return; |
| } |
| |
| buffer->pixels.reset(new uint8_t[size]); |
| buffer->size = size; |
| if (data != nullptr) |
| memcpy(buffer->pixels.get(), data, size); |
| } |
| |
| void TestGLES2Interface::GenSyncTokenCHROMIUM(GLbyte* sync_token) { |
| // Don't return a valid sync token if context is lost. This matches behavior |
| // of CommandBufferProxyImpl. |
| if (context_lost_) |
| return; |
| gpu::SyncToken sync_token_data(gpu::CommandBufferNamespace::GPU_IO, |
| gpu::CommandBufferId(), |
| next_insert_fence_sync_++); |
| sync_token_data.SetVerifyFlush(); |
| memcpy(sync_token, &sync_token_data, sizeof(sync_token_data)); |
| } |
| |
| void TestGLES2Interface::GenUnverifiedSyncTokenCHROMIUM(GLbyte* sync_token) { |
| // Don't return a valid sync token if context is lost. This matches behavior |
| // of CommandBufferProxyImpl. |
| if (context_lost_) |
| return; |
| gpu::SyncToken sync_token_data(gpu::CommandBufferNamespace::GPU_IO, |
| gpu::CommandBufferId(), |
| next_insert_fence_sync_++); |
| memcpy(sync_token, &sync_token_data, sizeof(sync_token_data)); |
| } |
| |
| void TestGLES2Interface::VerifySyncTokensCHROMIUM(GLbyte** sync_tokens, |
| GLsizei count) { |
| for (GLsizei i = 0; i < count; ++i) { |
| gpu::SyncToken sync_token_data; |
| memcpy(sync_token_data.GetData(), sync_tokens[i], sizeof(sync_token_data)); |
| sync_token_data.SetVerifyFlush(); |
| memcpy(sync_tokens[i], &sync_token_data, sizeof(sync_token_data)); |
| } |
| } |
| |
| void TestGLES2Interface::WaitSyncTokenCHROMIUM(const GLbyte* sync_token) { |
| gpu::SyncToken sync_token_data; |
| if (sync_token) |
| memcpy(&sync_token_data, sync_token, sizeof(sync_token_data)); |
| |
| if (sync_token_data.release_count() > |
| last_waited_sync_token_.release_count()) { |
| last_waited_sync_token_ = sync_token_data; |
| } |
| } |
| |
| void TestGLES2Interface::BeginQueryEXT(GLenum target, GLuint id) {} |
| |
| void TestGLES2Interface::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 TestGLES2Interface::GetQueryObjectuivEXT(GLuint id, |
| 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 TestGLES2Interface::DiscardFramebufferEXT(GLenum target, |
| GLsizei count, |
| const GLenum* attachments) {} |
| |
| void TestGLES2Interface::ProduceTextureDirectCHROMIUM(GLuint texture, |
| 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 TestGLES2Interface::CreateAndConsumeTextureCHROMIUM( |
| const GLbyte* mailbox) { |
| GLuint texture_id; |
| GenTextures(1, &texture_id); |
| return texture_id; |
| } |
| |
| void TestGLES2Interface::ResizeCHROMIUM(GLuint width, |
| GLuint height, |
| float device_scale, |
| GLenum color_space, |
| GLboolean has_alpha) { |
| reshape_called_ = true; |
| width_ = width; |
| height_ = height; |
| scale_factor_ = device_scale; |
| } |
| |
| void TestGLES2Interface::LoseContextCHROMIUM(GLenum current, GLenum other) { |
| if (context_lost_) |
| return; |
| context_lost_ = true; |
| if (!context_lost_callback_.is_null()) |
| std::move(context_lost_callback_).Run(); |
| |
| for (size_t i = 0; i < shared_contexts_.size(); ++i) |
| shared_contexts_[i]->LoseContextCHROMIUM(current, other); |
| shared_contexts_.clear(); |
| } |
| |
| GLenum TestGLES2Interface::GetGraphicsResetStatusKHR() { |
| if (IsContextLost()) |
| return GL_UNKNOWN_CONTEXT_RESET_KHR; |
| return GL_NO_ERROR; |
| } |
| |
| scoped_refptr<TestTexture> TestGLES2Interface::BoundTexture(GLenum target) { |
| // The caller is expected to lock the namespace for texture access. |
| namespace_->lock.AssertAcquired(); |
| return namespace_->textures.TextureForId(BoundTextureId(target)); |
| } |
| |
| scoped_refptr<TestTexture> TestGLES2Interface::UnboundTexture(GLuint texture) { |
| // The caller is expected to lock the namespace for texture access. |
| namespace_->lock.AssertAcquired(); |
| return namespace_->textures.TextureForId(texture); |
| } |
| |
| GLuint TestGLES2Interface::CreateExternalTexture() { |
| base::AutoLock lock(namespace_->lock); |
| namespace_->textures.Append(kExternalTextureId, new TestTexture()); |
| return kExternalTextureId; |
| } |
| |
| void TestGLES2Interface::set_times_bind_texture_succeeds(int times) { |
| times_bind_texture_succeeds_ = times; |
| } |
| |
| void TestGLES2Interface::set_have_extension_io_surface(bool have) { |
| test_capabilities_.iosurface = have; |
| test_capabilities_.texture_rectangle = have; |
| } |
| |
| void TestGLES2Interface::set_have_extension_egl_image(bool have) { |
| test_capabilities_.egl_image_external = have; |
| } |
| |
| void TestGLES2Interface::set_have_post_sub_buffer(bool have) { |
| test_capabilities_.post_sub_buffer = have; |
| } |
| |
| void TestGLES2Interface::set_have_swap_buffers_with_bounds(bool have) { |
| test_capabilities_.swap_buffers_with_bounds = have; |
| } |
| |
| void TestGLES2Interface::set_have_commit_overlay_planes(bool have) { |
| test_capabilities_.commit_overlay_planes = have; |
| } |
| |
| void TestGLES2Interface::set_have_discard_framebuffer(bool have) { |
| test_capabilities_.discard_framebuffer = have; |
| } |
| |
| void TestGLES2Interface::set_support_compressed_texture_etc1(bool support) { |
| test_capabilities_.texture_format_etc1 = support; |
| } |
| |
| void TestGLES2Interface::set_support_texture_format_bgra8888(bool support) { |
| test_capabilities_.texture_format_bgra8888 = support; |
| } |
| |
| void TestGLES2Interface::set_support_texture_storage(bool support) { |
| test_capabilities_.texture_storage = support; |
| } |
| |
| void TestGLES2Interface::set_support_texture_usage(bool support) { |
| test_capabilities_.texture_usage = support; |
| } |
| |
| void TestGLES2Interface::set_support_sync_query(bool support) { |
| test_capabilities_.sync_query = support; |
| } |
| |
| void TestGLES2Interface::set_support_texture_rectangle(bool support) { |
| test_capabilities_.texture_rectangle = support; |
| } |
| |
| void TestGLES2Interface::set_support_texture_half_float_linear(bool support) { |
| test_capabilities_.texture_half_float_linear = support; |
| } |
| |
| void TestGLES2Interface::set_support_texture_norm16(bool support) { |
| test_capabilities_.texture_norm16 = support; |
| } |
| |
| void TestGLES2Interface::set_msaa_is_slow(bool msaa_is_slow) { |
| test_capabilities_.msaa_is_slow = msaa_is_slow; |
| } |
| |
| void TestGLES2Interface::set_gpu_rasterization(bool gpu_rasterization) { |
| test_capabilities_.gpu_rasterization = gpu_rasterization; |
| } |
| |
| void TestGLES2Interface::set_avoid_stencil_buffers(bool avoid_stencil_buffers) { |
| test_capabilities_.avoid_stencil_buffers = avoid_stencil_buffers; |
| } |
| |
| void TestGLES2Interface::set_enable_dc_layers(bool support) { |
| test_capabilities_.dc_layers = support; |
| } |
| |
| void TestGLES2Interface::set_support_multisample_compatibility(bool support) { |
| test_capabilities_.multisample_compatibility = support; |
| } |
| |
| void TestGLES2Interface::set_support_texture_storage_image(bool support) { |
| test_capabilities_.texture_storage_image = support; |
| } |
| |
| void TestGLES2Interface::set_support_texture_npot(bool support) { |
| test_capabilities_.texture_npot = support; |
| } |
| |
| void TestGLES2Interface::set_max_texture_size(int size) { |
| test_capabilities_.max_texture_size = size; |
| } |
| |
| size_t TestGLES2Interface::NumTextures() const { |
| base::AutoLock lock(namespace_->lock); |
| return namespace_->textures.Size(); |
| } |
| |
| GLuint TestGLES2Interface::TextureAt(int i) const { |
| base::AutoLock lock(namespace_->lock); |
| return namespace_->textures.IdAt(i); |
| } |
| |
| GLuint TestGLES2Interface::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 TestGLES2Interface::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 TestGLES2Interface::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 TestGLES2Interface::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 TestGLES2Interface::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 TestGLES2Interface::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_); |
| } |
| |
| GLuint TestGLES2Interface::NextFramebufferId() { |
| base::AutoLock lock_for_framebuffer_access(namespace_->lock); |
| GLuint id = next_framebuffer_id_++; |
| DCHECK(id < (1 << 16)); |
| id |= context_id_ << 16; |
| framebuffer_set_.insert(id); |
| return id; |
| } |
| |
| void TestGLES2Interface::RetireFramebufferId(GLuint id) { |
| base::AutoLock lock_for_framebuffer_access(namespace_->lock); |
| DCHECK(framebuffer_set_.find(id) != framebuffer_set_.end()); |
| framebuffer_set_.erase(id); |
| } |
| |
| GLuint TestGLES2Interface::NextRenderbufferId() { |
| base::AutoLock lock_for_renderbuffer_access(namespace_->lock); |
| GLuint id = namespace_->next_renderbuffer_id++; |
| DCHECK(id < (1 << 16)); |
| id |= context_id_ << 16; |
| namespace_->renderbuffer_set.insert(id); |
| return id; |
| } |
| |
| void TestGLES2Interface::RetireRenderbufferId(GLuint id) { |
| base::AutoLock lock_for_renderbuffer_access(namespace_->lock); |
| DCHECK(namespace_->renderbuffer_set.find(id) != |
| namespace_->renderbuffer_set.end()); |
| namespace_->renderbuffer_set.erase(id); |
| } |
| |
| void TestGLES2Interface::SetMaxSamples(int max_samples) { |
| test_capabilities_.max_samples = max_samples; |
| } |
| |
| size_t TestGLES2Interface::NumFramebuffers() const { |
| base::AutoLock lock_for_framebuffer_access(namespace_->lock); |
| return framebuffer_set_.size(); |
| } |
| |
| size_t TestGLES2Interface::NumRenderbuffers() const { |
| base::AutoLock lock_for_renderbuffer_access(namespace_->lock); |
| return namespace_->renderbuffer_set.size(); |
| } |
| |
| void TestGLES2Interface::CheckTextureIsBound(GLenum target) { |
| DCHECK(BoundTextureId(target)); |
| } |
| GLuint TestGLES2Interface::BoundTextureId(GLenum target) { |
| return texture_targets_.BoundTexture(target); |
| } |
| |
| TestGLES2Interface::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; |
| } |
| |
| TestGLES2Interface::TextureTargets::~TextureTargets() = default; |
| |
| void TestGLES2Interface::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 TestGLES2Interface::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 TestGLES2Interface::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 TestGLES2Interface::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 TestGLES2Interface::TextureTargets::BoundTexture(GLenum target) { |
| DCHECK(bound_textures_.find(target) != bound_textures_.end()); |
| return bound_textures_[target]; |
| } |
| |
| TestGLES2Interface::Buffer::Buffer() : target(0), size(0) {} |
| |
| TestGLES2Interface::Buffer::~Buffer() = default; |
| |
| TestGLES2Interface::Image::Image() = default; |
| |
| TestGLES2Interface::Image::~Image() = default; |
| |
| } // namespace viz |