blob: 36dc9309b554401d79a220b1ea746587312a02c9 [file] [log] [blame]
// 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