#include "gpu/command_buffer/client/gles2_implementation.h"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES2/gl2extchromium.h>
#include <GLES3/gl3.h>
#include <GLES3/gl32.h>
#include <stddef.h>
#include <stdint.h>
#include <array>
#include <memory>
#include "base/compiler_specific.h"
#include "base/containers/heap_array.h"
#include "base/containers/span.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "gpu/command_buffer/client/client_test_helper.h"
#include "gpu/command_buffer/client/gles2_cmd_helper.h"
#include "gpu/command_buffer/client/mock_transfer_buffer.h"
#include "gpu/command_buffer/client/program_info_manager.h"
#include "gpu/command_buffer/client/query_tracker.h"
#include "gpu/command_buffer/client/ring_buffer.h"
#include "gpu/command_buffer/client/shared_memory_limits.h"
#include "gpu/command_buffer/common/command_buffer.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::AtLeast;
using testing::AnyNumber;
using testing::DoAll;
using testing::InSequence;
using testing::Mock;
using testing::Pointee;
using testing::SaveArg;
using testing::Sequence;
using testing::StrictMock;
using testing::Truly;
using testing::Return;
using testing::ReturnRef;
namespace gpu {
namespace gles2 {
ACTION_P2(SetMemory, dst, obj) {
UNSAFE_TODO(memcpy(dst, &obj, sizeof(obj)));
}
ACTION_P3(SetMemoryFromArray, dst_span, src_span, size) {
const_cast<decltype(dst_span)*>(&dst_span)->copy_prefix_from(
src_span.first(size));
}
template <typename T>
class SizedResultHelper {
public:
explicit SizedResultHelper(T result)
: size_(sizeof(result)) {
UNSAFE_TODO(memcpy(result_, &result, sizeof(T)));
}
private:
uint32_t size_;
char result_[sizeof(T)];
};
struct FourFloats {
FourFloats(float _x, float _y, float _z, float _w)
: x(_x),
y(_y),
z(_z),
w(_w) {
}
float x;
float y;
float z;
float w;
};
#pragma pack(push, 1)
struct Str7 {
char str[7];
};
#pragma pack(pop)
class GenBuffersAPI {
public:
static void Gen(GLES2Implementation* gl_impl, GLsizei n, GLuint* ids) {
gl_impl->GenBuffers(n, ids);
}
static void Delete(GLES2Implementation* gl_impl,
GLsizei n,
const GLuint* ids) {
gl_impl->DeleteBuffers(n, ids);
}
};
class GenRenderbuffersAPI {
public:
static void Gen(GLES2Implementation* gl_impl, GLsizei n, GLuint* ids) {
gl_impl->GenRenderbuffers(n, ids);
}
static void Delete(GLES2Implementation* gl_impl,
GLsizei n,
const GLuint* ids) {
gl_impl->DeleteRenderbuffers(n, ids);
}
};
class GenTexturesAPI {
public:
static void Gen(GLES2Implementation* gl_impl, GLsizei n, GLuint* ids) {
gl_impl->GenTextures(n, ids);
}
static void Delete(GLES2Implementation* gl_impl,
GLsizei n,
const GLuint* ids) {
gl_impl->DeleteTextures(n, ids);
}
};
class GLES2ImplementationTest : public testing::Test {
protected:
static const int kNumTestContexts = 2;
static const uint8_t kInitialValue = 0xBD;
static const int32_t kNumCommandEntries = 500;
static const int32_t kCommandBufferSizeBytes =
kNumCommandEntries * sizeof(CommandBufferEntry);
static const size_t kTransferBufferSize = 512;
static const GLint kMaxCombinedTextureImageUnits = 8;
static const GLint kMaxCubeMapTextureSize = 64;
static const GLint kMaxFragmentUniformVectors = 16;
static const GLint kMaxRenderbufferSize = 64;
static const GLint kMaxTextureImageUnits = 8;
static const GLint kMaxTextureSize = 128;
static const GLint kMaxVaryingVectors = 8;
static const GLint kMaxVertexAttribs = 8;
static const GLint kMaxVertexTextureImageUnits = 0;
static const GLint kMaxVertexUniformVectors = 128;
static const GLint kMaxViewportWidth = 8192;
static const GLint kMaxViewportHeight = 6144;
static const GLint kNumCompressedTextureFormats = 0;
static const GLint kNumShaderBinaryFormats = 0;
static const GLuint kMaxTransformFeedbackSeparateAttribs = 4;
static const GLuint kMaxUniformBufferBindings = 36;
static const GLuint kStartId = 1024;
static const GLuint kBuffersStartId = 1;
static const GLuint kFramebuffersStartId = 1;
static const GLuint kProgramsAndShadersStartId = 1;
static const GLuint kRenderbuffersStartId = 1;
static const GLuint kSamplersStartId = 1;
static const GLuint kTexturesStartId = 1;
static const GLuint kTransformFeedbacksStartId = 1;
static const GLuint kQueriesStartId = 1;
static const GLuint kVertexArraysStartId = 1;
typedef MockTransferBuffer::ExpectedMemoryInfo ExpectedMemoryInfo;
class TestContext {
public:
TestContext() : commands_(nullptr), token_(0) {}
bool Initialize(ShareGroup* share_group,
bool lose_context_when_out_of_memory,
bool transfer_buffer_initialize_fail,
bool sync_query,
bool occlusion_query_boolean,
bool timer_queries,
int major_version,
int minor_version) {
SharedMemoryLimits limits = SharedMemoryLimitsForTesting();
command_buffer_.reset(new StrictMock<MockClientCommandBuffer>());
transfer_buffer_.reset(
new MockTransferBuffer(command_buffer_.get(),
kTransferBufferSize,
GLES2Implementation::kStartingOffset,
GLES2Implementation::kAlignment,
transfer_buffer_initialize_fail));
helper_.reset(new GLES2CmdHelper(command_buffer()));
helper_->Initialize(limits.command_buffer_size);
gpu_control_.reset(new StrictMock<MockClientGpuControl>());
gl_capabilities_.VisitPrecisions(
[](GLenum shader, GLenum type,
GLCapabilities::ShaderPrecision* precision) {
precision->min_range = 3;
precision->max_range = 5;
precision->precision = 7;
});
gl_capabilities_.max_combined_texture_image_units =
kMaxCombinedTextureImageUnits;
gl_capabilities_.max_cube_map_texture_size = kMaxCubeMapTextureSize;
gl_capabilities_.max_fragment_uniform_vectors =
kMaxFragmentUniformVectors;
gl_capabilities_.max_renderbuffer_size = kMaxRenderbufferSize;
gl_capabilities_.max_texture_image_units = kMaxTextureImageUnits;
capabilities_.max_texture_size = kMaxTextureSize;
gl_capabilities_.max_texture_size = kMaxTextureSize;
gl_capabilities_.max_varying_vectors = kMaxVaryingVectors;
gl_capabilities_.max_vertex_attribs = kMaxVertexAttribs;
gl_capabilities_.max_vertex_texture_image_units =
kMaxVertexTextureImageUnits;
gl_capabilities_.max_vertex_uniform_vectors = kMaxVertexUniformVectors;
gl_capabilities_.max_viewport_width = kMaxViewportWidth;
gl_capabilities_.max_viewport_height = kMaxViewportHeight;
gl_capabilities_.num_compressed_texture_formats =
kNumCompressedTextureFormats;
gl_capabilities_.num_shader_binary_formats = kNumShaderBinaryFormats;
gl_capabilities_.max_transform_feedback_separate_attribs =
kMaxTransformFeedbackSeparateAttribs;
gl_capabilities_.max_uniform_buffer_bindings = kMaxUniformBufferBindings;
capabilities_.sync_query = sync_query;
gl_capabilities_.sync_query = sync_query;
gl_capabilities_.occlusion_query_boolean = occlusion_query_boolean;
gl_capabilities_.timer_queries = timer_queries;
gl_capabilities_.major_version = major_version;
gl_capabilities_.minor_version = minor_version;
EXPECT_CALL(*gpu_control_, GetCapabilities())
.WillOnce(ReturnRef(capabilities_));
EXPECT_CALL(*gpu_control_, GetGLCapabilities())
.WillOnce(ReturnRef(gl_capabilities_));
{
InSequence sequence;
gl_ = std::make_unique<GLES2Implementation>(
helper_.get(), share_group, transfer_buffer_.get(),
lose_context_when_out_of_memory, gpu_control_.get());
}
EXPECT_CALL(*gpu_control_, SetGpuControlClient(gl_.get())).Times(1);
if (gl_->Initialize(limits) != gpu::ContextResult::kSuccess)
return false;
helper_->CommandBufferHelper::Finish();
Mock::VerifyAndClearExpectations(gl_.get());
scoped_refptr<Buffer> ring_buffer = helper_->get_ring_buffer();
commands_ =
UNSAFE_TODO(static_cast<CommandBufferEntry*>(ring_buffer->memory()) +
command_buffer()->GetServicePutOffset());
ClearCommands();
EXPECT_TRUE(transfer_buffer_->InSync());
Mock::VerifyAndClearExpectations(command_buffer());
return true;
}
void TearDown() {
Mock::VerifyAndClear(gl_.get());
EXPECT_CALL(*command_buffer(), OnFlush()).Times(AnyNumber());
EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
.Times(AtLeast(1));
EXPECT_CALL(*gpu_control_, SetGpuControlClient(nullptr)).Times(1);
gl_.reset();
}
MockClientCommandBuffer* command_buffer() const {
return command_buffer_.get();
}
int GetNextToken() { return ++token_; }
void ClearCommands() {
scoped_refptr<Buffer> ring_buffer = helper_->get_ring_buffer();
UNSAFE_TODO(
memset(ring_buffer->memory(), kInitialValue, ring_buffer->size()));
}
std::unique_ptr<MockClientCommandBuffer> command_buffer_;
std::unique_ptr<MockClientGpuControl> gpu_control_;
std::unique_ptr<GLES2CmdHelper> helper_;
std::unique_ptr<MockTransferBuffer> transfer_buffer_;
std::unique_ptr<GLES2Implementation> gl_;
raw_ptr<CommandBufferEntry> commands_;
int token_;
Capabilities capabilities_;
GLCapabilities gl_capabilities_;
};
GLES2ImplementationTest() : commands_(nullptr) {}
void SetUp() override;
void TearDown() override;
bool NoCommandsWritten() {
scoped_refptr<Buffer> ring_buffer = helper_->get_ring_buffer();
const uint8_t* cmds = static_cast<const uint8_t*>(ring_buffer->memory());
const uint8_t* end = UNSAFE_TODO(cmds + ring_buffer->size());
for (; cmds < end; UNSAFE_TODO(++cmds)) {
if (*cmds != kInitialValue) {
return false;
}
}
return true;
}
QueryTracker::Query* GetQuery(GLuint id) {
return gl_->query_tracker_->GetQuery(id);
}
QueryTracker* GetQueryTracker() { return gl_->query_tracker_.get(); }
struct ContextInitOptions {
bool lose_context_when_out_of_memory = false;
bool transfer_buffer_initialize_fail = false;
bool sync_query = true;
bool occlusion_query_boolean = true;
bool timer_queries = true;
int major_version = 2;
int minor_version = 0;
};
bool Initialize(const ContextInitOptions& init_options) {
bool success = true;
share_group_ = base::MakeRefCounted<ShareGroup>(0);
for (int i = 0; i < kNumTestContexts; i++) {
if (!test_contexts_[i].Initialize(
share_group_.get(),
init_options.lose_context_when_out_of_memory,
init_options.transfer_buffer_initialize_fail,
init_options.sync_query,
init_options.occlusion_query_boolean,
init_options.timer_queries,
init_options.major_version,
init_options.minor_version))
success = false;
}
gpu_control_ = test_contexts_[0].gpu_control_.get();
helper_ = test_contexts_[0].helper_.get();
transfer_buffer_ = test_contexts_[0].transfer_buffer_.get();
gl_ = test_contexts_[0].gl_.get();
commands_ = test_contexts_[0].commands_;
return success;
}
MockClientCommandBuffer* command_buffer() const {
return test_contexts_[0].command_buffer_.get();
}
int GetNextToken() { return test_contexts_[0].GetNextToken(); }
const void* GetPut() {
return helper_->GetSpace(0);
}
void ClearCommands() {
scoped_refptr<Buffer> ring_buffer = helper_->get_ring_buffer();
UNSAFE_TODO(
memset(ring_buffer->memory(), kInitialValue, ring_buffer->size()));
}
size_t MaxTransferBufferSize() {
return transfer_buffer_->MaxTransferBufferSize();
}
void SetMappedMemoryLimit(size_t limit) {
gl_->mapped_memory_->set_max_allocated_bytes(limit);
}
ExpectedMemoryInfo GetExpectedMemory(size_t size) {
return transfer_buffer_->GetExpectedMemory(size);
}
ExpectedMemoryInfo GetExpectedResultMemory(size_t size) {
return transfer_buffer_->GetExpectedResultMemory(size);
}
ExpectedMemoryInfo GetExpectedMappedMemory(size_t size) {
ExpectedMemoryInfo mem;
mem.ptr = static_cast<uint8_t*>(
gl_->mapped_memory_->Alloc(size, &mem.id, &mem.offset));
gl_->mapped_memory_->Free(mem.ptr);
return mem;
}
void SetProgramInfoManager(ProgramInfoManager* manager) {
gl_->share_group()->SetProgramInfoManagerForTesting(manager);
}
int CheckError() {
ExpectedMemoryInfo result =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
return gl_->GetError();
}
const std::string& GetLastError() {
return gl_->GetLastError();
}
bool GetBucketContents(uint32_t bucket_id, std::vector<int8_t>* data) {
return gl_->GetBucketContents(bucket_id, data);
}
bool AllowExtraTransferBufferSize() {
return gl_->max_extra_transfer_buffer_size_ > 0;
}
static SharedMemoryLimits SharedMemoryLimitsForTesting() {
SharedMemoryLimits limits;
limits.command_buffer_size = kCommandBufferSizeBytes;
limits.start_transfer_buffer_size = kTransferBufferSize;
limits.min_transfer_buffer_size = kTransferBufferSize;
limits.max_transfer_buffer_size = kTransferBufferSize;
limits.mapped_memory_reclaim_limit = SharedMemoryLimits::kNoLimit;
return limits;
}
void ResetErrorMessageCallback() { gl_->error_message_callback_.Reset(); }
std::array<TestContext, kNumTestContexts> test_contexts_;
scoped_refptr<ShareGroup> share_group_;
raw_ptr<MockClientGpuControl> gpu_control_;
raw_ptr<GLES2CmdHelper> helper_;
raw_ptr<MockTransferBuffer> transfer_buffer_;
raw_ptr<GLES2Implementation> gl_;
raw_ptr<CommandBufferEntry> commands_;
};
void GLES2ImplementationTest::SetUp() {
ContextInitOptions init_options;
ASSERT_TRUE(Initialize(init_options));
}
void GLES2ImplementationTest::TearDown() {
gl_ = nullptr;
for (int i = 0; i < kNumTestContexts; i++)
test_contexts_[i].TearDown();
}
class GLES2ImplementationManualInitTest : public GLES2ImplementationTest {
protected:
void SetUp() override {}
};
class GLES2ImplementationStrictSharedTest : public GLES2ImplementationTest {
protected:
void SetUp() override;
template <class ResApi>
void FlushGenerationTest() {
GLuint id1, id2, id3;
ResApi::Gen(gl_, 1, &id1);
EXPECT_NE(id1, 0u);
ResApi::Delete(gl_, 1, &id1);
ResApi::Gen(gl_, 1, &id2);
EXPECT_NE(id2, 0u);
EXPECT_NE(id2, id1);
gl_->Flush();
ResApi::Gen(gl_, 1, &id3);
EXPECT_EQ(id3, id1);
}
template <class ResApi>
void CrossContextGenerationTest() {
GLES2Implementation* gl1 = test_contexts_[0].gl_.get();
GLES2Implementation* gl2 = test_contexts_[1].gl_.get();
GLuint id1, id2, id3;
ResApi::Gen(gl1, 1, &id1);
ResApi::Delete(gl1, 1, &id1);
ResApi::Gen(gl1, 1, &id2);
EXPECT_NE(id1, id2);
gl2->Flush();
ResApi::Gen(gl2, 1, &id3);
EXPECT_NE(id1, id3);
EXPECT_NE(id2, id3);
gl1->Flush();
ResApi::Gen(gl2, 1, &id3);
EXPECT_NE(id1, id3);
ResApi::Delete(gl1, 1, &id2);
ResApi::Gen(gl2, 1, &id3);
EXPECT_EQ(id1, id3);
}
template <class ResApi>
void CrossContextGenerationAutoFlushTest() {
GLES2Implementation* gl1 = test_contexts_[0].gl_.get();
GLES2Implementation* gl2 = test_contexts_[1].gl_.get();
GLuint id1, id2, id3;
ResApi::Gen(gl1, 1, &id1);
gl1->helper()->Noop(kNumCommandEntries / 2);
ResApi::Delete(gl1, 1, &id1);
ResApi::Gen(gl1, 1, &id2);
EXPECT_NE(id1, id2);
gl2->Flush();
ResApi::Gen(gl2, 1, &id3);
EXPECT_NE(id1, id3);
EXPECT_NE(id2, id3);
gl1->Flush();
ResApi::Gen(gl2, 1, &id3);
EXPECT_NE(id1, id3);
ResApi::Delete(gl1, 1, &id2);
ResApi::Gen(gl2, 1, &id3);
EXPECT_EQ(id1, id3);
}
template <class ResApi>
void DeletingInvalidIdGeneratesError() {
GLES2Implementation* gl1 = test_contexts_[0].gl_.get();
GLuint id1;
ResApi::Gen(gl1, 1, &id1);
const GLuint kDefinitelyInvalidId = 0xBEEF;
EXPECT_EQ(GL_NO_ERROR, CheckError());
ResApi::Delete(gl1, 1, &kDefinitelyInvalidId);
EXPECT_EQ(GL_INVALID_VALUE, CheckError());
}
template <class ResApi>
void DoubleDeletingIdGeneratesError() {
GLES2Implementation* gl1 = test_contexts_[0].gl_.get();
GLuint id1;
ResApi::Gen(gl1, 1, &id1);
ResApi::Delete(gl1, 1, &id1);
EXPECT_EQ(GL_NO_ERROR, CheckError());
ResApi::Delete(gl1, 1, &id1);
EXPECT_EQ(GL_INVALID_VALUE, CheckError());
}
};
void GLES2ImplementationStrictSharedTest::SetUp() {
ContextInitOptions init_options;
ASSERT_TRUE(Initialize(init_options));
}
class GLES3ImplementationTest : public GLES2ImplementationTest {
protected:
void SetUp() override;
};
void GLES3ImplementationTest::SetUp() {
ContextInitOptions init_options;
init_options.major_version = 3;
init_options.minor_version = 0;
ASSERT_TRUE(Initialize(init_options));
}
const uint8_t GLES2ImplementationTest::kInitialValue;
const int32_t GLES2ImplementationTest::kNumCommandEntries;
const int32_t GLES2ImplementationTest::kCommandBufferSizeBytes;
const size_t GLES2ImplementationTest::kTransferBufferSize;
const GLint GLES2ImplementationTest::kMaxCombinedTextureImageUnits;
const GLint GLES2ImplementationTest::kMaxCubeMapTextureSize;
const GLint GLES2ImplementationTest::kMaxFragmentUniformVectors;
const GLint GLES2ImplementationTest::kMaxRenderbufferSize;
const GLint GLES2ImplementationTest::kMaxTextureImageUnits;
const GLint GLES2ImplementationTest::kMaxTextureSize;
const GLint GLES2ImplementationTest::kMaxVaryingVectors;
const GLint GLES2ImplementationTest::kMaxVertexAttribs;
const GLint GLES2ImplementationTest::kMaxVertexTextureImageUnits;
const GLint GLES2ImplementationTest::kMaxVertexUniformVectors;
const GLint GLES2ImplementationTest::kNumCompressedTextureFormats;
const GLint GLES2ImplementationTest::kNumShaderBinaryFormats;
const GLuint GLES2ImplementationTest::kStartId;
const GLuint GLES2ImplementationTest::kBuffersStartId;
const GLuint GLES2ImplementationTest::kFramebuffersStartId;
const GLuint GLES2ImplementationTest::kProgramsAndShadersStartId;
const GLuint GLES2ImplementationTest::kRenderbuffersStartId;
const GLuint GLES2ImplementationTest::kSamplersStartId;
const GLuint GLES2ImplementationTest::kTexturesStartId;
const GLuint GLES2ImplementationTest::kTransformFeedbacksStartId;
const GLuint GLES2ImplementationTest::kQueriesStartId;
const GLuint GLES2ImplementationTest::kVertexArraysStartId;
TEST_F(GLES2ImplementationTest, Basic) {
EXPECT_TRUE(gl_->share_group());
}
TEST_F(GLES2ImplementationTest, GetBucketContents) {
const uint32_t kBucketId = GLES2Implementation::kResultBucketId;
const uint32_t kTestSize = MaxTransferBufferSize() + 32;
auto buf = base::HeapArray<uint8_t>::Uninit(kTestSize);
base::span<uint8_t> expected_data = buf;
for (uint32_t ii = 0; ii < kTestSize; ++ii) {
expected_data[ii] = ii * 3;
}
struct Cmds {
cmd::GetBucketStart get_bucket_start;
cmd::SetToken set_token1;
cmd::GetBucketData get_bucket_data;
cmd::SetToken set_token2;
cmd::SetBucketSize set_bucket_size2;
};
ExpectedMemoryInfo mem1 = GetExpectedMemory(MaxTransferBufferSize());
ExpectedMemoryInfo result1 = GetExpectedResultMemory(sizeof(uint32_t));
ExpectedMemoryInfo mem2 = GetExpectedMemory(
kTestSize - MaxTransferBufferSize());
Cmds expected;
expected.get_bucket_start.Init(
kBucketId, result1.id, result1.offset,
MaxTransferBufferSize(), mem1.id, mem1.offset);
expected.set_token1.Init(GetNextToken());
expected.get_bucket_data.Init(
kBucketId, MaxTransferBufferSize(),
kTestSize - MaxTransferBufferSize(), mem2.id, mem2.offset);
expected.set_bucket_size2.Init(kBucketId, 0);
expected.set_token2.Init(GetNextToken());
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(DoAll(SetMemory(result1.ptr, kTestSize),
SetMemoryFromArray(mem1.span, expected_data,
MaxTransferBufferSize())))
.WillOnce(SetMemoryFromArray(
mem2.span, expected_data.subspan(MaxTransferBufferSize()),
kTestSize - MaxTransferBufferSize()))
.RetiresOnSaturation();
std::vector<int8_t> data;
GetBucketContents(kBucketId, &data);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
ASSERT_EQ(kTestSize, data.size());
EXPECT_THAT(data, testing::ElementsAreArray(expected_data));
}
TEST_F(GLES2ImplementationTest, GetShaderPrecisionFormat) {
struct Cmds {
cmds::GetShaderPrecisionFormat cmd;
};
typedef cmds::GetShaderPrecisionFormat::Result Result;
const unsigned kDummyType1 = 3;
const unsigned kDummyType2 = 4;
GLint range1[2] = {0, 0};
GLint precision1 = 0;
Cmds expected1;
ExpectedMemoryInfo client_result1 = GetExpectedResultMemory(4);
expected1.cmd.Init(GL_FRAGMENT_SHADER, kDummyType1, client_result1.id,
client_result1.offset);
Result server_result1 = {true, 14, 14, 10};
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(client_result1.ptr, server_result1))
.RetiresOnSaturation();
gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, kDummyType1, range1,
&precision1);
const void* commands2 = GetPut();
EXPECT_NE(commands_, commands2);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected1, commands_, sizeof(expected1))));
EXPECT_EQ(range1[0], 14);
EXPECT_EQ(range1[1], 14);
EXPECT_EQ(precision1, 10);
GLint range2[2] = {0, 0};
GLint precision2 = 0;
gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, kDummyType1, range2,
&precision2);
const void* commands3 = GetPut();
EXPECT_EQ(commands2, commands3);
EXPECT_EQ(range2[0], 14);
EXPECT_EQ(range2[1], 14);
EXPECT_EQ(precision2, 10);
GLint range3[2] = {0, 0};
GLint precision3 = 0;
Cmds expected3;
ExpectedMemoryInfo result3 = GetExpectedResultMemory(4);
expected3.cmd.Init(GL_FRAGMENT_SHADER, kDummyType2, result3.id,
result3.offset);
Result result3_source = {true, 62, 62, 16};
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result3.ptr, result3_source))
.RetiresOnSaturation();
gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, kDummyType2, range3,
&precision3);
const void* commands4 = GetPut();
EXPECT_NE(commands3, commands4);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected3, commands3, sizeof(expected3))));
EXPECT_EQ(range3[0], 62);
EXPECT_EQ(range3[1], 62);
EXPECT_EQ(precision3, 16);
GLint range4[2] = {0, 0};
GLint precision4 = 0;
gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT, range4,
&precision4);
const void* commands5 = GetPut();
EXPECT_EQ(commands4, commands5);
EXPECT_EQ(range4[0], 3);
EXPECT_EQ(range4[1], 5);
EXPECT_EQ(precision4, 7);
}
TEST_F(GLES2ImplementationTest, GetShaderSource) {
const uint32_t kBucketId = GLES2Implementation::kResultBucketId;
const GLuint kShaderId = 456;
const Str7 kString = {"foobar"};
const char kBad = 0x12;
struct Cmds {
cmd::SetBucketSize set_bucket_size1;
cmds::GetShaderSource get_shader_source;
cmd::GetBucketStart get_bucket_start;
cmd::SetToken set_token1;
cmd::SetBucketSize set_bucket_size2;
};
ExpectedMemoryInfo mem1 = GetExpectedMemory(MaxTransferBufferSize());
ExpectedMemoryInfo result1 = GetExpectedResultMemory(sizeof(uint32_t));
Cmds expected;
expected.set_bucket_size1.Init(kBucketId, 0);
expected.get_shader_source.Init(kShaderId, kBucketId);
expected.get_bucket_start.Init(
kBucketId, result1.id, result1.offset,
MaxTransferBufferSize(), mem1.id, mem1.offset);
expected.set_token1.Init(GetNextToken());
expected.set_bucket_size2.Init(kBucketId, 0);
char buf[sizeof(kString) + 1];
UNSAFE_TODO(memset(buf, kBad, sizeof(buf)));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(DoAll(SetMemory(result1.ptr, uint32_t(sizeof(kString))),
SetMemory(mem1.ptr, kString)))
.RetiresOnSaturation();
GLsizei length = 0;
gl_->GetShaderSource(kShaderId, sizeof(buf), &length, buf);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_EQ(sizeof(kString) - 1, static_cast<size_t>(length));
EXPECT_STREQ(kString.str, buf);
EXPECT_EQ(buf[sizeof(kString)], kBad);
}
TEST_F(GLES2ImplementationTest, ReadPixels2Reads) {
struct Cmds {
cmds::ReadPixels read1;
cmd::SetToken set_token1;
cmds::ReadPixels read2;
cmd::SetToken set_token2;
};
const GLint kBytesPerPixel = 4;
const GLint kWidth =
(kTransferBufferSize - GLES2Implementation::kStartingOffset) /
kBytesPerPixel;
const GLint kHeight = 2;
const GLenum kFormat = GL_RGBA;
const GLenum kType = GL_UNSIGNED_BYTE;
ExpectedMemoryInfo mem1 =
GetExpectedMemory(kWidth * kHeight / 2 * kBytesPerPixel);
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmds::ReadPixels::Result));
ExpectedMemoryInfo mem2 =
GetExpectedMemory(kWidth * kHeight / 2 * kBytesPerPixel);
ExpectedMemoryInfo result2 =
GetExpectedResultMemory(sizeof(cmds::ReadPixels::Result));
Cmds expected;
expected.read1.Init(
0, 0, kWidth, kHeight / 2, kFormat, kType,
mem1.id, mem1.offset, result1.id, result1.offset,
false);
expected.set_token1.Init(GetNextToken());
expected.read2.Init(
0, kHeight / 2, kWidth, kHeight / 2, kFormat, kType,
mem2.id, mem2.offset, result2.id, result2.offset, false);
expected.set_token2.Init(GetNextToken());
auto buffer =
base::HeapArray<int8_t>::Uninit(kWidth * kHeight * kBytesPerPixel);
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result1.ptr, static_cast<uint32_t>(1)))
.WillOnce(SetMemory(result2.ptr, static_cast<uint32_t>(1)))
.RetiresOnSaturation();
gl_->ReadPixels(0, 0, kWidth, kHeight, kFormat, kType, buffer.data());
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
}
TEST_F(GLES2ImplementationTest, ReadPixelsBadFormatType) {
struct Cmds {
cmds::ReadPixels read;
cmd::SetToken set_token;
};
const GLint kBytesPerPixel = 4;
const GLint kWidth = 2;
const GLint kHeight = 2;
const GLenum kFormat = 0;
const GLenum kType = 0;
ExpectedMemoryInfo mem1 =
GetExpectedMemory(kWidth * kHeight * kBytesPerPixel);
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmds::ReadPixels::Result));
Cmds expected;
expected.read.Init(
0, 0, kWidth, kHeight, kFormat, kType,
mem1.id, mem1.offset, result1.id, result1.offset, false);
expected.set_token.Init(GetNextToken());
auto buffer =
base::HeapArray<int8_t>::Uninit(kWidth * kHeight * kBytesPerPixel);
EXPECT_CALL(*command_buffer(), OnFlush())
.Times(1)
.RetiresOnSaturation();
gl_->ReadPixels(0, 0, kWidth, kHeight, kFormat, kType, buffer.data());
}
TEST_F(GLES2ImplementationTest, FreeUnusedSharedMemory) {
struct Cmds {
cmds::BufferSubData buf;
cmd::SetToken set_token;
};
const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER;
const GLintptr kOffset = 15;
const GLsizeiptr kSize = 16;
ExpectedMemoryInfo mem1 = GetExpectedMemory(kSize);
Cmds expected;
expected.buf.Init(
kTarget, kOffset, kSize, mem1.id, mem1.offset);
expected.set_token.Init(GetNextToken());
void* mem = gl_->MapBufferSubDataCHROMIUM(
kTarget, kOffset, kSize, GL_WRITE_ONLY);
ASSERT_TRUE(mem != nullptr);
gl_->UnmapBufferSubDataCHROMIUM(mem);
EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
.Times(1)
.RetiresOnSaturation();
gl_->FreeUnusedSharedMemory();
}
TEST_F(GLES2ImplementationTest, MapUnmapBufferSubDataCHROMIUM) {
struct Cmds {
cmds::BufferSubData buf;
cmd::SetToken set_token;
};
const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER;
const GLintptr kOffset = 15;
const GLsizeiptr kSize = 16;
uint32_t offset = 0;
Cmds expected;
expected.buf.Init(
kTarget, kOffset, kSize,
command_buffer()->GetNextFreeTransferBufferId(), offset);
expected.set_token.Init(GetNextToken());
void* mem = gl_->MapBufferSubDataCHROMIUM(
kTarget, kOffset, kSize, GL_WRITE_ONLY);
ASSERT_TRUE(mem != nullptr);
gl_->UnmapBufferSubDataCHROMIUM(mem);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
}
TEST_F(GLES2ImplementationTest, MapUnmapBufferSubDataCHROMIUMBadArgs) {
const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER;
const GLintptr kOffset = 15;
const GLsizeiptr kSize = 16;
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
ExpectedMemoryInfo result2 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
ExpectedMemoryInfo result3 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
ExpectedMemoryInfo result4 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
.WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
.WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR)))
.WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
void* mem;
mem = gl_->MapBufferSubDataCHROMIUM(kTarget, -1, kSize, GL_WRITE_ONLY);
ASSERT_TRUE(mem == nullptr);
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
mem = gl_->MapBufferSubDataCHROMIUM(kTarget, kOffset, -1, GL_WRITE_ONLY);
ASSERT_TRUE(mem == nullptr);
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
mem = gl_->MapBufferSubDataCHROMIUM(kTarget, kOffset, kSize, GL_READ_ONLY);
ASSERT_TRUE(mem == nullptr);
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), gl_->GetError());
const char* kPtr = "something";
gl_->UnmapBufferSubDataCHROMIUM(kPtr);
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
}
TEST_F(GLES2ImplementationTest, MapUnmapTexSubImage2DCHROMIUM) {
struct Cmds {
cmds::TexSubImage2D tex;
cmd::SetToken set_token;
};
const GLint kLevel = 1;
const GLint kXOffset = 2;
const GLint kYOffset = 3;
const GLint kWidth = 4;
const GLint kHeight = 5;
const GLenum kFormat = GL_RGBA;
const GLenum kType = GL_UNSIGNED_BYTE;
uint32_t offset = 0;
Cmds expected;
expected.tex.Init(
GL_TEXTURE_2D, kLevel, kXOffset, kYOffset, kWidth, kHeight, kFormat,
kType,
command_buffer()->GetNextFreeTransferBufferId(), offset, GL_FALSE);
expected.set_token.Init(GetNextToken());
void* mem = gl_->MapTexSubImage2DCHROMIUM(
GL_TEXTURE_2D,
kLevel,
kXOffset,
kYOffset,
kWidth,
kHeight,
kFormat,
kType,
GL_WRITE_ONLY);
ASSERT_TRUE(mem != nullptr);
gl_->UnmapTexSubImage2DCHROMIUM(mem);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
}
TEST_F(GLES2ImplementationTest, MapUnmapTexSubImage2DCHROMIUMBadArgs) {
const GLint kLevel = 1;
const GLint kXOffset = 2;
const GLint kYOffset = 3;
const GLint kWidth = 4;
const GLint kHeight = 5;
const GLenum kFormat = GL_RGBA;
const GLenum kType = GL_UNSIGNED_BYTE;
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
ExpectedMemoryInfo result2 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
ExpectedMemoryInfo result3 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
ExpectedMemoryInfo result4 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
ExpectedMemoryInfo result5 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
ExpectedMemoryInfo result6 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
ExpectedMemoryInfo result7 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
.WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
.WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR)))
.WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR)))
.WillOnce(SetMemory(result5.ptr, GLuint(GL_NO_ERROR)))
.WillOnce(SetMemory(result6.ptr, GLuint(GL_NO_ERROR)))
.WillOnce(SetMemory(result7.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
void* mem;
mem = gl_->MapTexSubImage2DCHROMIUM(
GL_TEXTURE_2D,
-1,
kXOffset,
kYOffset,
kWidth,
kHeight,
kFormat,
kType,
GL_WRITE_ONLY);
EXPECT_TRUE(mem == nullptr);
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
mem = gl_->MapTexSubImage2DCHROMIUM(
GL_TEXTURE_2D,
kLevel,
-1,
kYOffset,
kWidth,
kHeight,
kFormat,
kType,
GL_WRITE_ONLY);
EXPECT_TRUE(mem == nullptr);
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
mem = gl_->MapTexSubImage2DCHROMIUM(
GL_TEXTURE_2D,
kLevel,
kXOffset,
-1,
kWidth,
kHeight,
kFormat,
kType,
GL_WRITE_ONLY);
EXPECT_TRUE(mem == nullptr);
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
mem = gl_->MapTexSubImage2DCHROMIUM(
GL_TEXTURE_2D,
kLevel,
kXOffset,
kYOffset,
-1,
kHeight,
kFormat,
kType,
GL_WRITE_ONLY);
EXPECT_TRUE(mem == nullptr);
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
mem = gl_->MapTexSubImage2DCHROMIUM(
GL_TEXTURE_2D,
kLevel,
kXOffset,
kYOffset,
kWidth,
-1,
kFormat,
kType,
GL_WRITE_ONLY);
EXPECT_TRUE(mem == nullptr);
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
mem = gl_->MapTexSubImage2DCHROMIUM(
GL_TEXTURE_2D,
kLevel,
kXOffset,
kYOffset,
kWidth,
kHeight,
kFormat,
kType,
GL_READ_ONLY);
EXPECT_TRUE(mem == nullptr);
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), gl_->GetError());
const char* kPtr = "something";
gl_->UnmapTexSubImage2DCHROMIUM(kPtr);
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
}
TEST_F(GLES2ImplementationTest, GetProgramInfoCHROMIUMGoodArgs) {
const uint32_t kBucketId = GLES2Implementation::kResultBucketId;
const GLuint kProgramId = 123;
const char kBad = 0x12;
GLsizei size = 0;
const Str7 kString = {"foobar"};
char buf[20];
ExpectedMemoryInfo mem1 =
GetExpectedMemory(MaxTransferBufferSize());
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmd::GetBucketStart::Result));
ExpectedMemoryInfo result2 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
UNSAFE_TODO(memset(buf, kBad, sizeof(buf)));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(DoAll(SetMemory(result1.ptr, uint32_t(sizeof(kString))),
SetMemory(mem1.ptr, kString)))
.WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
struct Cmds {
cmd::SetBucketSize set_bucket_size1;
cmds::GetProgramInfoCHROMIUM get_program_info;
cmd::GetBucketStart get_bucket_start;
cmd::SetToken set_token1;
cmd::SetBucketSize set_bucket_size2;
};
Cmds expected;
expected.set_bucket_size1.Init(kBucketId, 0);
expected.get_program_info.Init(kProgramId, kBucketId);
expected.get_bucket_start.Init(
kBucketId, result1.id, result1.offset,
MaxTransferBufferSize(), mem1.id, mem1.offset);
expected.set_token1.Init(GetNextToken());
expected.set_bucket_size2.Init(kBucketId, 0);
gl_->GetProgramInfoCHROMIUM(kProgramId, sizeof(buf), &size, &buf);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
EXPECT_EQ(sizeof(kString), static_cast<size_t>(size));
EXPECT_STREQ(kString.str, buf);
EXPECT_EQ(buf[sizeof(kString)], kBad);
}
TEST_F(GLES2ImplementationTest, GetProgramInfoCHROMIUMBadArgs) {
const uint32_t kBucketId = GLES2Implementation::kResultBucketId;
const GLuint kProgramId = 123;
GLsizei size = 0;
const Str7 kString = {"foobar"};
char buf[20];
ExpectedMemoryInfo mem1 = GetExpectedMemory(MaxTransferBufferSize());
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmd::GetBucketStart::Result));
ExpectedMemoryInfo result2 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
ExpectedMemoryInfo result3 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
ExpectedMemoryInfo result4 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(DoAll(SetMemory(result1.ptr, uint32_t(sizeof(kString))),
SetMemory(mem1.ptr, kString)))
.WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
.WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR)))
.WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
struct Cmds {
cmd::SetBucketSize set_bucket_size1;
cmds::GetProgramInfoCHROMIUM get_program_info;
cmd::GetBucketStart get_bucket_start;
cmd::SetToken set_token1;
cmd::SetBucketSize set_bucket_size2;
};
Cmds expected;
expected.set_bucket_size1.Init(kBucketId, 0);
expected.get_program_info.Init(kProgramId, kBucketId);
expected.get_bucket_start.Init(
kBucketId, result1.id, result1.offset,
MaxTransferBufferSize(), mem1.id, mem1.offset);
expected.set_token1.Init(GetNextToken());
expected.set_bucket_size2.Init(kBucketId, 0);
gl_->GetProgramInfoCHROMIUM(kProgramId, 6, &size, &buf);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), gl_->GetError());
ClearCommands();
gl_->GetProgramInfoCHROMIUM(kProgramId, -1, &size, &buf);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
ClearCommands();
gl_->GetProgramInfoCHROMIUM(kProgramId, sizeof(buf), nullptr, &buf);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
}
TEST_F(GLES2ImplementationTest, GetUniformBlocksCHROMIUMGoodArgs) {
const uint32_t kBucketId = GLES2Implementation::kResultBucketId;
const GLuint kProgramId = 123;
const char kBad = 0x12;
GLsizei size = 0;
const Str7 kString = {"foobar"};
char buf[20];
ExpectedMemoryInfo mem1 =
GetExpectedMemory(MaxTransferBufferSize());
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmd::GetBucketStart::Result));
ExpectedMemoryInfo result2 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
UNSAFE_TODO(memset(buf, kBad, sizeof(buf)));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(DoAll(SetMemory(result1.ptr, uint32_t(sizeof(kString))),
SetMemory(mem1.ptr, kString)))
.WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
struct Cmds {
cmd::SetBucketSize set_bucket_size1;
cmds::GetUniformBlocksCHROMIUM get_uniform_blocks;
cmd::GetBucketStart get_bucket_start;
cmd::SetToken set_token1;
cmd::SetBucketSize set_bucket_size2;
};
Cmds expected;
expected.set_bucket_size1.Init(kBucketId, 0);
expected.get_uniform_blocks.Init(kProgramId, kBucketId);
expected.get_bucket_start.Init(
kBucketId, result1.id, result1.offset,
MaxTransferBufferSize(), mem1.id, mem1.offset);
expected.set_token1.Init(GetNextToken());
expected.set_bucket_size2.Init(kBucketId, 0);
gl_->GetUniformBlocksCHROMIUM(kProgramId, sizeof(buf), &size, &buf);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
EXPECT_EQ(sizeof(kString), static_cast<size_t>(size));
EXPECT_STREQ(kString.str, buf);
EXPECT_EQ(buf[sizeof(kString)], kBad);
}
TEST_F(GLES2ImplementationTest, GetUniformBlocksCHROMIUMBadArgs) {
const uint32_t kBucketId = GLES2Implementation::kResultBucketId;
const GLuint kProgramId = 123;
GLsizei size = 0;
const Str7 kString = {"foobar"};
char buf[20];
ExpectedMemoryInfo mem1 = GetExpectedMemory(MaxTransferBufferSize());
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmd::GetBucketStart::Result));
ExpectedMemoryInfo result2 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
ExpectedMemoryInfo result3 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
ExpectedMemoryInfo result4 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(DoAll(SetMemory(result1.ptr, uint32_t(sizeof(kString))),
SetMemory(mem1.ptr, kString)))
.WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
.WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR)))
.WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
struct Cmds {
cmd::SetBucketSize set_bucket_size1;
cmds::GetUniformBlocksCHROMIUM get_uniform_blocks;
cmd::GetBucketStart get_bucket_start;
cmd::SetToken set_token1;
cmd::SetBucketSize set_bucket_size2;
};
Cmds expected;
expected.set_bucket_size1.Init(kBucketId, 0);
expected.get_uniform_blocks.Init(kProgramId, kBucketId);
expected.get_bucket_start.Init(
kBucketId, result1.id, result1.offset,
MaxTransferBufferSize(), mem1.id, mem1.offset);
expected.set_token1.Init(GetNextToken());
expected.set_bucket_size2.Init(kBucketId, 0);
gl_->GetUniformBlocksCHROMIUM(kProgramId, 6, &size, &buf);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), gl_->GetError());
ClearCommands();
gl_->GetUniformBlocksCHROMIUM(kProgramId, -1, &size, &buf);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
ClearCommands();
gl_->GetUniformBlocksCHROMIUM(kProgramId, sizeof(buf), nullptr, &buf);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
}
TEST_F(GLES2ImplementationTest, GetIntegerCacheRead) {
struct PNameValue {
GLenum pname;
GLint expected;
};
const auto pairs = std::to_array<PNameValue>({
{
GL_ACTIVE_TEXTURE,
GL_TEXTURE0,
},
{
GL_TEXTURE_BINDING_2D,
0,
},
{
GL_TEXTURE_BINDING_CUBE_MAP,
0,
},
{
GL_TEXTURE_BINDING_EXTERNAL_OES,
0,
},
{
GL_FRAMEBUFFER_BINDING,
0,
},
{
GL_RENDERBUFFER_BINDING,
0,
},
{
GL_ARRAY_BUFFER_BINDING,
0,
},
{
GL_ELEMENT_ARRAY_BUFFER_BINDING,
0,
},
{
GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
kMaxCombinedTextureImageUnits,
},
{
GL_MAX_CUBE_MAP_TEXTURE_SIZE,
kMaxCubeMapTextureSize,
},
{
GL_MAX_FRAGMENT_UNIFORM_VECTORS,
kMaxFragmentUniformVectors,
},
{
GL_MAX_RENDERBUFFER_SIZE,
kMaxRenderbufferSize,
},
{
GL_MAX_TEXTURE_IMAGE_UNITS,
kMaxTextureImageUnits,
},
{
GL_MAX_TEXTURE_SIZE,
kMaxTextureSize,
},
{
GL_MAX_VARYING_VECTORS,
kMaxVaryingVectors,
},
{
GL_MAX_VERTEX_ATTRIBS,
kMaxVertexAttribs,
},
{
GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
kMaxVertexTextureImageUnits,
},
{
GL_MAX_VERTEX_UNIFORM_VECTORS,
kMaxVertexUniformVectors,
},
{
GL_NUM_COMPRESSED_TEXTURE_FORMATS,
kNumCompressedTextureFormats,
},
{
GL_NUM_SHADER_BINARY_FORMATS,
kNumShaderBinaryFormats,
},
});
size_t num_pairs =
(pairs.size() * sizeof(decltype(pairs)::value_type)) / sizeof(pairs[0]);
for (size_t ii = 0; ii < num_pairs; ++ii) {
const PNameValue& pv = pairs[ii];
GLint v = -1;
gl_->GetIntegerv(pv.pname, &v);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(pv.expected, v);
}
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
}
TEST_F(GLES2ImplementationTest, GetIntegerDisjointValue) {
ExpectedMemoryInfo mem = GetExpectedMappedMemory(sizeof(DisjointValueSync));
gl_->SetDisjointValueSyncCHROMIUM();
ASSERT_EQ(mem.id, GetQueryTracker()->DisjointCountSyncShmID());
ASSERT_EQ(mem.offset, GetQueryTracker()->DisjointCountSyncShmOffset());
DisjointValueSync* disjoint_sync =
reinterpret_cast<DisjointValueSync*>(mem.ptr);
ClearCommands();
GLint disjoint_value = -1;
gl_->GetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(0, disjoint_value);
disjoint_value = -1;
disjoint_sync->SetDisjointCount(1);
gl_->GetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(1, disjoint_value);
disjoint_value = -1;
gl_->GetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(0, disjoint_value);
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
}
TEST_F(GLES2ImplementationTest, GetIntegerCacheWrite) {
struct PNameValue {
GLenum pname;
GLuint expected;
};
GLuint buffer_ids[2];
gl_->GenBuffers(std::size(buffer_ids), buffer_ids);
GLuint framebuffer_id;
gl_->GenFramebuffers(1, &framebuffer_id);
GLuint renderbuffer_id;
gl_->GenRenderbuffers(1, &renderbuffer_id);
GLuint texture_ids[3];
gl_->GenTextures(std::size(texture_ids), texture_ids);
gl_->ActiveTexture(GL_TEXTURE4);
gl_->BindBuffer(GL_ARRAY_BUFFER, buffer_ids[0]);
gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_ids[1]);
gl_->BindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
gl_->BindRenderbuffer(GL_RENDERBUFFER, renderbuffer_id);
gl_->BindTexture(GL_TEXTURE_2D, texture_ids[0]);
gl_->BindTexture(GL_TEXTURE_CUBE_MAP, texture_ids[1]);
gl_->BindTexture(GL_TEXTURE_EXTERNAL_OES, texture_ids[2]);
const auto pairs = std::to_array<PNameValue>({
{
GL_ACTIVE_TEXTURE,
GL_TEXTURE4,
},
{
GL_ARRAY_BUFFER_BINDING,
buffer_ids[0],
},
{
GL_ELEMENT_ARRAY_BUFFER_BINDING,
buffer_ids[1],
},
{
GL_FRAMEBUFFER_BINDING,
framebuffer_id,
},
{
GL_RENDERBUFFER_BINDING,
renderbuffer_id,
},
{
GL_TEXTURE_BINDING_2D,
texture_ids[0],
},
{
GL_TEXTURE_BINDING_CUBE_MAP,
texture_ids[1],
},
{
GL_TEXTURE_BINDING_EXTERNAL_OES,
texture_ids[2],
},
});
size_t num_pairs =
(pairs.size() * sizeof(decltype(pairs)::value_type)) / sizeof(pairs[0]);
for (size_t ii = 0; ii < num_pairs; ++ii) {
const PNameValue& pv = pairs[ii];
GLint v = -1;
gl_->GetIntegerv(pv.pname, &v);
EXPECT_EQ(pv.expected, static_cast<GLuint>(v));
}
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
}
static bool CheckRect(int width,
int height,
GLenum format,
GLenum type,
int alignment,
const uint8_t* r1,
const uint8_t* r2) {
uint32_t size = 0;
uint32_t unpadded_row_size = 0;
uint32_t padded_row_size = 0;
if (!GLES2Util::ComputeImageDataSizes(
width, height, 1, format, type, alignment, &size, &unpadded_row_size,
&padded_row_size)) {
return false;
}
int r2_stride = static_cast<int>(padded_row_size);
for (int y = 0; y < height; ++y) {
if (UNSAFE_TODO(memcmp(r1, r2, unpadded_row_size)) != 0) {
return false;
}
UNSAFE_TODO(r1 += padded_row_size);
UNSAFE_TODO(r2 += r2_stride);
}
return true;
}
ACTION_P7(CheckRectAction, width, height, format, type, alignment, r1, r2) {
EXPECT_TRUE(CheckRect(
width, height, format, type, alignment, r1, r2));
}
TEST_F(GLES2ImplementationTest, TexImage2D) {
struct Cmds {
cmds::TexImage2D tex_image_2d;
cmd::SetToken set_token;
};
struct Cmds2 {
cmds::TexImage2D tex_image_2d;
cmd::SetToken set_token;
};
const GLenum kTarget = GL_TEXTURE_2D;
const GLint kLevel = 0;
const GLenum kFormat = GL_RGB;
const GLsizei kWidth = 3;
const GLsizei kHeight = 4;
const GLint kBorder = 0;
const GLenum kType = GL_UNSIGNED_BYTE;
const GLint kPixelStoreUnpackAlignment = 4;
static uint8_t pixels[] = {
11, 12, 13, 13, 14, 15, 15, 16, 17, 101, 102, 103, 21, 22, 23,
23, 24, 25, 25, 26, 27, 201, 202, 203, 31, 32, 33, 33, 34, 35,
35, 36, 37, 123, 124, 125, 41, 42, 43, 43, 44, 45, 45, 46, 47,
};
ExpectedMemoryInfo mem1 = GetExpectedMemory(sizeof(pixels));
Cmds expected;
expected.tex_image_2d.Init(
kTarget, kLevel, kFormat, kWidth, kHeight, kFormat, kType,
mem1.id, mem1.offset);
expected.set_token.Init(GetNextToken());
gl_->TexImage2D(
kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
pixels);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_TRUE(CheckRect(
kWidth, kHeight, kFormat, kType, kPixelStoreUnpackAlignment,
pixels, mem1.ptr));
}
TEST_F(GLES2ImplementationTest, TexImage2DViaMappedMem) {
if (!AllowExtraTransferBufferSize()) {
LOG(WARNING) << "Low memory device do not support MappedMem. Skipping test";
return;
}
struct Cmds {
cmds::TexImage2D tex_image_2d;
cmd::SetToken set_token;
};
const GLenum kTarget = GL_TEXTURE_2D;
const GLint kLevel = 0;
const GLenum kFormat = GL_RGB;
const GLsizei kWidth = 3;
const GLint kBorder = 0;
const GLenum kType = GL_UNSIGNED_BYTE;
const GLint kPixelStoreUnpackAlignment = 4;
uint32_t size = 0;
uint32_t unpadded_row_size = 0;
uint32_t padded_row_size = 0;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, 2, 1, kFormat, kType, kPixelStoreUnpackAlignment,
&size, &unpadded_row_size, &padded_row_size));
const GLsizei kMaxHeight = (MaxTransferBufferSize() / padded_row_size) * 2;
const GLsizei kHeight = kMaxHeight * 2;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, kHeight, 1, kFormat, kType, kPixelStoreUnpackAlignment,
&size, &unpadded_row_size, &padded_row_size));
auto pixels = base::HeapArray<uint8_t>::Uninit(size);
for (uint32_t ii = 0; ii < size; ++ii) {
pixels[ii] = static_cast<uint8_t>(ii);
}
ExpectedMemoryInfo mem1 = GetExpectedMappedMemory(size);
Cmds expected;
expected.tex_image_2d.Init(
kTarget, kLevel, kFormat, kWidth, kHeight, kFormat, kType,
mem1.id, mem1.offset);
expected.set_token.Init(GetNextToken());
gl_->TexImage2D(kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat,
kType, pixels.data());
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_TRUE(CheckRect(kWidth, kHeight, kFormat, kType,
kPixelStoreUnpackAlignment, pixels.data(), mem1.ptr));
}
TEST_F(GLES2ImplementationTest, TexImage2DViaTexSubImage2D) {
SetMappedMemoryLimit(1);
struct Cmds {
cmds::TexImage2D tex_image_2d;
cmds::TexSubImage2D tex_sub_image_2d1;
cmd::SetToken set_token1;
cmds::TexSubImage2D tex_sub_image_2d2;
cmd::SetToken set_token2;
};
const GLenum kTarget = GL_TEXTURE_2D;
const GLint kLevel = 0;
const GLenum kFormat = GL_RGB;
const GLint kBorder = 0;
const GLenum kType = GL_UNSIGNED_BYTE;
const GLint kPixelStoreUnpackAlignment = 4;
const GLsizei kWidth = 3;
uint32_t size = 0;
uint32_t unpadded_row_size = 0;
uint32_t padded_row_size = 0;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, 2, 1, kFormat, kType, kPixelStoreUnpackAlignment,
&size, &unpadded_row_size, &padded_row_size));
const GLsizei kHeight = (MaxTransferBufferSize() / padded_row_size) * 2;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, kHeight, 1, kFormat, kType, kPixelStoreUnpackAlignment, &size,
nullptr, nullptr));
uint32_t half_size = 0;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, kHeight / 2, 1, kFormat, kType, kPixelStoreUnpackAlignment,
&half_size, nullptr, nullptr));
auto pixels = base::HeapArray<uint8_t>::Uninit(size);
for (uint32_t ii = 0; ii < size; ++ii) {
pixels[ii] = static_cast<uint8_t>(ii);
}
ExpectedMemoryInfo mem1 = GetExpectedMemory(half_size);
ExpectedMemoryInfo mem2 = GetExpectedMemory(half_size);
Cmds expected;
expected.tex_image_2d.Init(
kTarget, kLevel, kFormat, kWidth, kHeight, kFormat, kType,
0, 0);
expected.tex_sub_image_2d1.Init(
kTarget, kLevel, 0, 0, kWidth, kHeight / 2, kFormat, kType,
mem1.id, mem1.offset, true);
expected.set_token1.Init(GetNextToken());
expected.tex_sub_image_2d2.Init(
kTarget, kLevel, 0, kHeight / 2, kWidth, kHeight / 2, kFormat, kType,
mem2.id, mem2.offset, true);
expected.set_token2.Init(GetNextToken());
gl_->TexImage2D(kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat,
kType, pixels.data());
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
UNSAFE_TODO(EXPECT_TRUE(
CheckRect(kWidth, kHeight / 2, kFormat, kType, kPixelStoreUnpackAlignment,
pixels.data() + kHeight / 2 * padded_row_size, mem2.ptr)));
}
TEST_F(GLES2ImplementationTest, SubImage2DUnpack) {
static const auto unpack_alignments = std::to_array<GLint>({1, 2, 4, 8});
static const GLenum kFormat = GL_RGB;
static const GLenum kType = GL_UNSIGNED_BYTE;
static const GLint kLevel = 0;
static const GLint kBorder = 0;
static const GLint kSrcWidth = 33;
static const GLint kSrcSubImageX0 = 11;
static const GLint kSrcSubImageX1 = 20;
static const GLint kSrcSubImageY0 = 18;
static const GLint kSrcSubImageY1 = 23;
static const GLint kSrcSubImageWidth = kSrcSubImageX1 - kSrcSubImageX0;
static const GLint kSrcSubImageHeight = kSrcSubImageY1 - kSrcSubImageY0;
static const GLint kTexWidth = 1023;
static const GLint kTexHeight = 511;
static const GLint kTexSubXOffset = 419;
static const GLint kTexSubYOffset = 103;
struct {
cmds::PixelStorei pixel_store_i;
cmds::TexImage2D tex_image_2d;
} texImageExpected;
struct {
cmds::PixelStorei pixel_store_i;
cmds::TexImage2D tex_image_2d;
cmds::TexSubImage2D tex_sub_image_2d;
} texSubImageExpected;
uint32_t pixel_size;
PixelStoreParams pixel_params;
pixel_params.alignment = 8;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizesES3(
kSrcWidth, kSrcSubImageY1, 1, kFormat, kType,
pixel_params, &pixel_size, nullptr, nullptr, nullptr, nullptr));
auto src_pixels = base::HeapArray<uint8_t>::WithSize(pixel_size);
for (size_t i = 0; i < pixel_size; ++i) {
src_pixels[i] = static_cast<uint8_t>(i % 255);
}
for (int sub = 0; sub < 2; ++sub) {
for (size_t a = 0; a < std::size(unpack_alignments); ++a) {
const void* commands = GetPut();
GLint alignment = unpack_alignments[a];
gl_->PixelStorei(GL_UNPACK_ALIGNMENT, alignment);
gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, kSrcWidth);
gl_->PixelStorei(GL_UNPACK_SKIP_PIXELS, kSrcSubImageX0);
gl_->PixelStorei(GL_UNPACK_SKIP_ROWS, kSrcSubImageY0);
uint32_t client_size;
uint32_t client_unpadded_row_size;
uint32_t client_padded_row_size;
uint32_t client_skip_size;
{
PixelStoreParams params;
params.alignment = alignment;
params.row_length = kSrcWidth;
params.skip_pixels = kSrcSubImageX0;
params.skip_rows = kSrcSubImageY0;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizesES3(
kSrcSubImageWidth, kSrcSubImageHeight, 1, kFormat, kType, params,
&client_size, &client_unpadded_row_size, &client_padded_row_size,
&client_skip_size, nullptr));
ASSERT_TRUE(client_size + client_skip_size <= pixel_size);
}
uint32_t service_size;
uint32_t service_unpadded_row_size;
uint32_t service_padded_row_size;
uint32_t service_skip_size;
{
PixelStoreParams params;
params.alignment = alignment;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizesES3(
kSrcSubImageWidth, kSrcSubImageHeight, 1, kFormat, kType, params,
&service_size, &service_unpadded_row_size, &service_padded_row_size,
&service_skip_size, nullptr));
ASSERT_TRUE(service_size <= MaxTransferBufferSize());
ASSERT_TRUE(service_skip_size == 0);
ASSERT_TRUE(client_unpadded_row_size == service_unpadded_row_size);
}
ExpectedMemoryInfo mem = GetExpectedMemory(service_size);
if (sub) {
gl_->TexImage2D(
GL_TEXTURE_2D, kLevel, kFormat, kTexWidth, kTexHeight, kBorder,
kFormat, kType, nullptr);
gl_->TexSubImage2D(GL_TEXTURE_2D, kLevel, kTexSubXOffset,
kTexSubYOffset, kSrcSubImageWidth,
kSrcSubImageHeight, kFormat, kType,
src_pixels.data());
texSubImageExpected.pixel_store_i.Init(GL_UNPACK_ALIGNMENT, alignment);
texSubImageExpected.tex_image_2d.Init(
GL_TEXTURE_2D, kLevel, kFormat, kTexWidth, kTexHeight,
kFormat, kType, 0, 0);
texSubImageExpected.tex_sub_image_2d.Init(
GL_TEXTURE_2D, kLevel, kTexSubXOffset, kTexSubYOffset,
kSrcSubImageWidth, kSrcSubImageHeight, kFormat, kType, mem.id,
mem.offset, GL_FALSE);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&texSubImageExpected, commands,
sizeof(texSubImageExpected))));
} else {
gl_->TexImage2D(GL_TEXTURE_2D, kLevel, kFormat, kSrcSubImageWidth,
kSrcSubImageHeight, kBorder, kFormat, kType,
src_pixels.data());
texImageExpected.pixel_store_i.Init(GL_UNPACK_ALIGNMENT, alignment);
texImageExpected.tex_image_2d.Init(
GL_TEXTURE_2D, kLevel, kFormat, kSrcSubImageWidth,
kSrcSubImageHeight, kFormat, kType, mem.id, mem.offset);
UNSAFE_TODO(EXPECT_EQ(
0, memcmp(&texImageExpected, commands, sizeof(texImageExpected))));
}
for (int y = 0; y < kSrcSubImageHeight; ++y) {
const uint8_t* src_row = UNSAFE_TODO(
src_pixels.data() + client_skip_size + y * client_padded_row_size);
const uint8_t* dst_row =
UNSAFE_TODO(mem.ptr + y * service_padded_row_size);
UNSAFE_TODO(
EXPECT_EQ(0, memcmp(src_row, dst_row, service_unpadded_row_size)));
}
ClearCommands();
}
}
}
TEST_F(GLES3ImplementationTest, SubImage3DUnpack) {
static const auto unpack_alignments = std::to_array<GLint>({1, 2, 4, 8});
static const GLenum kFormat = GL_RGB;
static const GLenum kType = GL_UNSIGNED_BYTE;
static const GLint kLevel = 0;
static const GLint kBorder = 0;
static const GLint kSrcWidth = 23;
static const GLint kSrcHeight = 7;
static const GLint kSrcSubImageX0 = 11;
static const GLint kSrcSubImageX1 = 16;
static const GLint kSrcSubImageY0 = 1;
static const GLint kSrcSubImageY1 = 4;
static const GLint kSrcSubImageZ0 = 2;
static const GLint kSrcSubImageZ1 = 5;
static const GLint kSrcSubImageWidth = kSrcSubImageX1 - kSrcSubImageX0;
static const GLint kSrcSubImageHeight = kSrcSubImageY1 - kSrcSubImageY0;
static const GLint kSrcSubImageDepth = kSrcSubImageZ1 - kSrcSubImageZ0;
static const GLint kTexWidth = 255;
static const GLint kTexHeight = 127;
static const GLint kTexDepth = 11;
static const GLint kTexSubXOffset = 119;
static const GLint kTexSubYOffset = 63;
static const GLint kTexSubZOffset = 1;
struct {
cmds::PixelStorei pixel_store_i[3];
cmds::TexImage3D tex_image_3d;
} texImageExpected;
struct {
cmds::PixelStorei pixel_store_i[3];
cmds::TexImage3D tex_image_3d;
cmds::TexSubImage3D tex_sub_image_3d;
} texSubImageExpected;
uint32_t pixel_size;
PixelStoreParams pixel_params;
pixel_params.alignment = 8;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizesES3(
kSrcWidth, kSrcHeight, kSrcSubImageZ1, kFormat, kType,
pixel_params, &pixel_size, nullptr, nullptr, nullptr, nullptr));
auto src_pixels = base::HeapArray<uint8_t>::WithSize(pixel_size);
for (size_t i = 0; i < pixel_size; ++i) {
src_pixels[i] = static_cast<uint8_t>(i % 255);
}
for (int sub = 0; sub < 2; ++sub) {
for (size_t a = 0; a < std::size(unpack_alignments); ++a) {
const void* commands = GetPut();
GLint alignment = unpack_alignments[a];
gl_->PixelStorei(GL_UNPACK_ALIGNMENT, alignment);
gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, kSrcWidth);
gl_->PixelStorei(GL_UNPACK_IMAGE_HEIGHT, kSrcHeight);
gl_->PixelStorei(GL_UNPACK_SKIP_PIXELS, kSrcSubImageX0);
gl_->PixelStorei(GL_UNPACK_SKIP_ROWS, kSrcSubImageY0);
gl_->PixelStorei(GL_UNPACK_SKIP_IMAGES, kSrcSubImageZ0);
uint32_t client_size;
uint32_t client_unpadded_row_size;
uint32_t client_padded_row_size;
uint32_t client_skip_size;
{
PixelStoreParams params;
params.alignment = alignment;
params.row_length = kSrcWidth;
params.image_height = kSrcHeight;
params.skip_pixels = kSrcSubImageX0;
params.skip_rows = kSrcSubImageY0;
params.skip_images = kSrcSubImageZ0;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizesES3(
kSrcSubImageWidth, kSrcSubImageHeight, kSrcSubImageDepth,
kFormat, kType, params,
&client_size, &client_unpadded_row_size, &client_padded_row_size,
&client_skip_size, nullptr));
ASSERT_TRUE(client_size + client_skip_size <= pixel_size);
}
uint32_t service_size;
uint32_t service_unpadded_row_size;
uint32_t service_padded_row_size;
uint32_t service_skip_size;
{
PixelStoreParams params;
params.alignment = alignment;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizesES3(
kSrcSubImageWidth, kSrcSubImageHeight, kSrcSubImageDepth,
kFormat, kType, params,
&service_size, &service_unpadded_row_size, &service_padded_row_size,
&service_skip_size, nullptr));
ASSERT_TRUE(service_size <= MaxTransferBufferSize());
ASSERT_TRUE(service_skip_size == 0);
ASSERT_TRUE(client_unpadded_row_size == service_unpadded_row_size);
}
ExpectedMemoryInfo mem = GetExpectedMemory(service_size);
if (sub) {
gl_->TexImage3D(
GL_TEXTURE_3D, kLevel, kFormat, kTexWidth, kTexHeight, kTexDepth,
kBorder, kFormat, kType, nullptr);
gl_->TexSubImage3D(GL_TEXTURE_3D, kLevel, kTexSubXOffset,
kTexSubYOffset, kTexSubZOffset, kSrcSubImageWidth,
kSrcSubImageHeight, kSrcSubImageDepth, kFormat,
kType, src_pixels.data());
texSubImageExpected.pixel_store_i[0].Init(
GL_UNPACK_ALIGNMENT, alignment);
texSubImageExpected.pixel_store_i[1].Init(
GL_UNPACK_ROW_LENGTH, kSrcWidth);
texSubImageExpected.pixel_store_i[2].Init(
GL_UNPACK_IMAGE_HEIGHT, kSrcHeight);
texSubImageExpected.tex_image_3d.Init(
GL_TEXTURE_3D, kLevel, kFormat, kTexWidth, kTexHeight, kTexDepth,
kFormat, kType, 0, 0);
texSubImageExpected.tex_sub_image_3d.Init(
GL_TEXTURE_3D, kLevel,
kTexSubXOffset, kTexSubYOffset, kTexSubZOffset,
kSrcSubImageWidth, kSrcSubImageHeight, kSrcSubImageDepth,
kFormat, kType, mem.id, mem.offset, GL_FALSE);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&texSubImageExpected, commands,
sizeof(texSubImageExpected))));
} else {
gl_->TexImage3D(GL_TEXTURE_3D, kLevel, kFormat, kSrcSubImageWidth,
kSrcSubImageHeight, kSrcSubImageDepth, kBorder, kFormat,
kType, src_pixels.data());
texImageExpected.pixel_store_i[0].Init(GL_UNPACK_ALIGNMENT, alignment);
texImageExpected.pixel_store_i[1].Init(
GL_UNPACK_ROW_LENGTH, kSrcWidth);
texImageExpected.pixel_store_i[2].Init(
GL_UNPACK_IMAGE_HEIGHT, kSrcHeight);
texImageExpected.tex_image_3d.Init(
GL_TEXTURE_3D, kLevel, kFormat,
kSrcSubImageWidth, kSrcSubImageHeight, kSrcSubImageDepth,
kFormat, kType, mem.id, mem.offset);
UNSAFE_TODO(EXPECT_EQ(
0, memcmp(&texImageExpected, commands, sizeof(texImageExpected))));
}
for (int z = 0; z < kSrcSubImageDepth; ++z) {
for (int y = 0; y < kSrcSubImageHeight; ++y) {
const uint8_t* src_row =
UNSAFE_TODO(src_pixels.data() + client_skip_size +
(kSrcHeight * z + y) * client_padded_row_size);
const uint8_t* dst_row = UNSAFE_TODO(
mem.ptr + (kSrcSubImageHeight * z + y) * service_padded_row_size);
UNSAFE_TODO(EXPECT_EQ(
0, memcmp(src_row, dst_row, service_unpadded_row_size)));
}
}
ClearCommands();
}
}
}
TEST_F(GLES2ImplementationTest, TextureInvalidArguments) {
struct Cmds {
cmds::TexImage2D tex_image_2d;
cmd::SetToken set_token;
};
const GLenum kTarget = GL_TEXTURE_2D;
const GLint kLevel = 0;
const GLenum kFormat = GL_RGB;
const GLsizei kWidth = 3;
const GLsizei kHeight = 4;
const GLint kBorder = 0;
const GLint kInvalidBorder = 1;
const GLenum kType = GL_UNSIGNED_BYTE;
const GLint kPixelStoreUnpackAlignment = 4;
static uint8_t pixels[] = {
11, 12, 13, 13, 14, 15, 15, 16, 17, 101, 102, 103, 21, 22, 23,
23, 24, 25, 25, 26, 27, 201, 202, 203, 31, 32, 33, 33, 34, 35,
35, 36, 37, 123, 124, 125, 41, 42, 43, 43, 44, 45, 45, 46, 47,
};
ExpectedMemoryInfo mem1 = GetExpectedMemory(sizeof(pixels));
Cmds expected;
expected.tex_image_2d.Init(
kTarget, kLevel, kFormat, kWidth, kHeight, kFormat, kType,
mem1.id, mem1.offset);
expected.set_token.Init(GetNextToken());
gl_->TexImage2D(
kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
pixels);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_TRUE(CheckRect(
kWidth, kHeight, kFormat, kType, kPixelStoreUnpackAlignment,
pixels, mem1.ptr));
ClearCommands();
gl_->TexImage2D(
kTarget, kLevel, kFormat, kWidth, kHeight, kInvalidBorder, kFormat, kType,
pixels);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_INVALID_VALUE, CheckError());
ClearCommands();
const GLenum kCompressedFormat = GL_ETC1_RGB8_OES;
gl_->CompressedTexImage2D(kTarget, kLevel, kCompressedFormat, kWidth, kHeight,
kBorder, std::size(pixels), pixels);
EXPECT_FALSE(NoCommandsWritten());
ClearCommands();
gl_->CompressedTexImage2D(kTarget, kLevel, kCompressedFormat, kWidth, kHeight,
kInvalidBorder, std::size(pixels), pixels);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_INVALID_VALUE, CheckError());
}
TEST_F(GLES2ImplementationTest, TexImage3DSingleCommand) {
struct Cmds {
cmds::TexImage3D tex_image_3d;
};
const GLenum kTarget = GL_TEXTURE_3D;
const GLint kLevel = 0;
const GLint kBorder = 0;
const GLenum kFormat = GL_RGB;
const GLenum kType = GL_UNSIGNED_BYTE;
const GLint kPixelStoreUnpackAlignment = 4;
const GLsizei kWidth = 3;
const GLsizei kDepth = 2;
uint32_t size = 0;
uint32_t unpadded_row_size = 0;
uint32_t padded_row_size = 0;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, 2, kDepth, kFormat, kType, kPixelStoreUnpackAlignment,
&size, &unpadded_row_size, &padded_row_size));
const GLsizei kHeight = MaxTransferBufferSize() / padded_row_size / kDepth;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, kHeight, kDepth, kFormat, kType, kPixelStoreUnpackAlignment,
&size, nullptr, nullptr));
auto pixels = base::HeapArray<uint8_t>::Uninit(size);
for (uint32_t ii = 0; ii < size; ++ii) {
pixels[ii] = static_cast<uint8_t>(ii);
}
ExpectedMemoryInfo mem = GetExpectedMemory(size);
Cmds expected;
expected.tex_image_3d.Init(
kTarget, kLevel, kFormat, kWidth, kHeight, kDepth,
kFormat, kType, mem.id, mem.offset);
gl_->TexImage3D(kTarget, kLevel, kFormat, kWidth, kHeight, kDepth, kBorder,
kFormat, kType, pixels.data());
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_TRUE(CheckRect(kWidth, kHeight * kDepth, kFormat, kType,
kPixelStoreUnpackAlignment,
reinterpret_cast<uint8_t*>(pixels.data()), mem.ptr));
}
TEST_F(GLES2ImplementationTest, TexImage3DViaMappedMem) {
if (!AllowExtraTransferBufferSize()) {
LOG(WARNING) << "Low memory device do not support MappedMem. Skipping test";
return;
}
struct Cmds {
cmds::TexImage3D tex_image_3d;
};
const GLenum kTarget = GL_TEXTURE_3D;
const GLint kLevel = 0;
const GLint kBorder = 0;
const GLenum kFormat = GL_RGB;
const GLenum kType = GL_UNSIGNED_BYTE;
const GLint kPixelStoreUnpackAlignment = 4;
const GLsizei kWidth = 3;
const GLsizei kDepth = 2;
uint32_t size = 0;
uint32_t unpadded_row_size = 0;
uint32_t padded_row_size = 0;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, 2, kDepth, kFormat, kType, kPixelStoreUnpackAlignment,
&size, &unpadded_row_size, &padded_row_size));
const GLsizei kMaxHeight = MaxTransferBufferSize() / padded_row_size / kDepth;
const GLsizei kHeight = kMaxHeight * 2;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, kHeight, kDepth, kFormat, kType, kPixelStoreUnpackAlignment,
&size, nullptr, nullptr));
auto pixels = base::HeapArray<uint8_t>::Uninit(size);
for (uint32_t ii = 0; ii < size; ++ii) {
pixels[ii] = static_cast<uint8_t>(ii);
}
ExpectedMemoryInfo mem = GetExpectedMappedMemory(size);
Cmds expected;
expected.tex_image_3d.Init(
kTarget, kLevel, kFormat, kWidth, kHeight, kDepth,
kFormat, kType, mem.id, mem.offset);
gl_->TexImage3D(kTarget, kLevel, kFormat, kWidth, kHeight, kDepth, kBorder,
kFormat, kType, pixels.data());
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_TRUE(CheckRect(kWidth, kHeight * kDepth, kFormat, kType,
kPixelStoreUnpackAlignment,
reinterpret_cast<uint8_t*>(pixels.data()), mem.ptr));
}
TEST_F(GLES2ImplementationTest, TexImage3DViaTexSubImage3D) {
SetMappedMemoryLimit(1);
struct Cmds {
cmds::TexImage3D tex_image_3d;
cmds::TexSubImage3D tex_sub_image_3d1;
cmd::SetToken set_token;
cmds::TexSubImage3D tex_sub_image_3d2;
};
const GLenum kTarget = GL_TEXTURE_3D;
const GLint kLevel = 0;
const GLint kBorder = 0;
const GLenum kFormat = GL_RGB;
const GLenum kType = GL_UNSIGNED_BYTE;
const GLint kPixelStoreUnpackAlignment = 4;
const GLsizei kWidth = 3;
uint32_t size = 0;
uint32_t unpadded_row_size = 0;
uint32_t padded_row_size = 0;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, 2, 1, kFormat, kType, kPixelStoreUnpackAlignment,
&size, &unpadded_row_size, &padded_row_size));
const GLsizei kHeight = MaxTransferBufferSize() / padded_row_size + 3;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, kHeight, 1, kFormat, kType, kPixelStoreUnpackAlignment, &size,
nullptr, nullptr));
uint32_t first_size = padded_row_size * (kHeight - 3);
uint32_t second_size =
padded_row_size * 3 - (padded_row_size - unpadded_row_size);
EXPECT_EQ(size, first_size + second_size);
ExpectedMemoryInfo mem1 = GetExpectedMemory(first_size);
ExpectedMemoryInfo mem2 = GetExpectedMemory(second_size);
auto pixels = base::HeapArray<uint8_t>::Uninit(size);
for (uint32_t ii = 0; ii < size; ++ii) {
pixels[ii] = static_cast<uint8_t>(ii);
}
Cmds expected;
expected.tex_image_3d.Init(
kTarget, kLevel, kFormat, kWidth, kHeight, 1, kFormat, kType, 0, 0);
expected.tex_sub_image_3d1.Init(
kTarget, kLevel, 0, 0, 0, kWidth, kHeight - 3, 1, kFormat, kType,
mem1.id, mem1.offset, GL_TRUE);
expected.tex_sub_image_3d2.Init(
kTarget, kLevel, 0, kHeight - 3, 0, kWidth, 3, 1, kFormat, kType,
mem2.id, mem2.offset, GL_TRUE);
expected.set_token.Init(GetNextToken());
gl_->TexImage3D(kTarget, kLevel, kFormat, kWidth, kHeight, 1, kBorder,
kFormat, kType, pixels.data());
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
}
TEST_F(GLES2ImplementationTest, TexSubImage3D4Writes) {
struct Cmds {
cmds::TexSubImage3D tex_sub_image_3d1_1;
cmd::SetToken set_token1;
cmds::TexSubImage3D tex_sub_image_3d1_2;
cmd::SetToken set_token2;
cmds::TexSubImage3D tex_sub_image_3d2_1;
cmd::SetToken set_token3;
cmds::TexSubImage3D tex_sub_image_3d2_2;
};
const GLenum kTarget = GL_TEXTURE_3D;
const GLint kLevel = 0;
const GLint kXOffset = 0;
const GLint kYOffset = 0;
const GLint kZOffset = 0;
const GLenum kFormat = GL_RGB;
const GLenum kType = GL_UNSIGNED_BYTE;
const GLint kPixelStoreUnpackAlignment = 4;
const GLsizei kWidth = 3;
const GLsizei kDepth = 2;
uint32_t size = 0;
uint32_t unpadded_row_size = 0;
uint32_t padded_row_size = 0;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, 2, 1, kFormat, kType, kPixelStoreUnpackAlignment,
&size, &unpadded_row_size, &padded_row_size));
const GLsizei kHeight = MaxTransferBufferSize() / padded_row_size + 2;
ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, kHeight, kDepth, kFormat, kType, kPixelStoreUnpackAlignment,
&size, nullptr, nullptr));
uint32_t first_size = (kHeight - 2) * padded_row_size;
uint32_t second_size = 2 * padded_row_size;
uint32_t third_size = first_size;
uint32_t fourth_size = second_size - (padded_row_size - unpadded_row_size);
EXPECT_EQ(size, first_size + second_size + third_size + fourth_size);
auto pixels = base::HeapArray<uint8_t>::Uninit(size);
for (uint32_t ii = 0; ii < size; ++ii) {
pixels[ii] = static_cast<uint8_t>(ii);
}
ExpectedMemoryInfo mem1_1 = GetExpectedMemory(first_size);
ExpectedMemoryInfo mem1_2 = GetExpectedMemory(second_size);
ExpectedMemoryInfo mem2_1 = GetExpectedMemory(third_size);
ExpectedMemoryInfo mem2_2 = GetExpectedMemory(fourth_size);
Cmds expected;
expected.tex_sub_image_3d1_1.Init(
kTarget, kLevel, kXOffset, kYOffset, kZOffset,
kWidth, kHeight - 2, 1, kFormat, kType,
mem1_1.id, mem1_1.offset, GL_FALSE);
expected.tex_sub_image_3d1_2.Init(
kTarget, kLevel, kXOffset, kYOffset + kHeight - 2, kZOffset,
kWidth, 2, 1, kFormat, kType, mem1_2.id, mem1_2.offset, GL_FALSE);
expected.tex_sub_image_3d2_1.Init(
kTarget, kLevel, kXOffset, kYOffset, kZOffset + 1,
kWidth, kHeight - 2, 1, kFormat, kType,
mem2_1.id, mem2_1.offset, GL_FALSE);
expected.tex_sub_image_3d2_2.Init(
kTarget, kLevel, kXOffset, kYOffset + kHeight - 2, kZOffset + 1,
kWidth, 2, 1, kFormat, kType, mem2_2.id, mem2_2.offset, GL_FALSE);
expected.set_token1.Init(GetNextToken());
expected.set_token2.Init(GetNextToken());
expected.set_token3.Init(GetNextToken());
gl_->TexSubImage3D(kTarget, kLevel, kXOffset, kYOffset, kZOffset, kWidth,
kHeight, kDepth, kFormat, kType, pixels.data());
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
uint32_t offset_to_last = first_size + second_size + third_size;
UNSAFE_TODO(EXPECT_TRUE(CheckRect(
kWidth, 2, kFormat, kType, kPixelStoreUnpackAlignment,
reinterpret_cast<uint8_t*>(pixels.data()) + offset_to_last, mem2_2.ptr)));
}
TEST_F(GLES2ImplementationStrictSharedTest, FlushGenerationTestBuffers) {
FlushGenerationTest<GenBuffersAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest, FlushGenerationTestRenderbuffers) {
FlushGenerationTest<GenRenderbuffersAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest, FlushGenerationTestTextures) {
FlushGenerationTest<GenTexturesAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest, CrossContextGenerationTestBuffers) {
CrossContextGenerationTest<GenBuffersAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest,
CrossContextGenerationTestRenderbuffers) {
CrossContextGenerationTest<GenRenderbuffersAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest,
CrossContextGenerationTestTextures) {
CrossContextGenerationTest<GenTexturesAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest,
CrossContextGenerationAutoFlushTestBuffers) {
CrossContextGenerationAutoFlushTest<GenBuffersAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest,
CrossContextGenerationAutoFlushTestRenderbuffers) {
CrossContextGenerationAutoFlushTest<GenRenderbuffersAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest,
CrossContextGenerationAutoFlushTestTextures) {
CrossContextGenerationAutoFlushTest<GenTexturesAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest,
DeletingInvalidIdGeneratesErrorBuffers) {
DeletingInvalidIdGeneratesError<GenBuffersAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest,
DeletingInvalidIdGeneratesErrorRenderbuffers) {
DeletingInvalidIdGeneratesError<GenRenderbuffersAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest,
DeletingInvalidIdGeneratesErrorTextures) {
DeletingInvalidIdGeneratesError<GenTexturesAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest,
DoubleDeletingIdGeneratesErrorBuffers) {
DoubleDeletingIdGeneratesError<GenBuffersAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest,
DoubleDeletingIdGeneratesErrorRenderbuffers) {
DoubleDeletingIdGeneratesError<GenRenderbuffersAPI>();
}
TEST_F(GLES2ImplementationStrictSharedTest,
DoubleDeletingIdGeneratesErrorTextures) {
DoubleDeletingIdGeneratesError<GenTexturesAPI>();
}
TEST_F(GLES2ImplementationTest, GetString) {
const uint32_t kBucketId = GLES2Implementation::kResultBucketId;
const Str7 kString = {"foobar"};
const char* expected_str =
"foobar "
"GL_CHROMIUM_map_sub "
"GL_CHROMIUM_ordering_barrier "
"GL_CHROMIUM_sync_point "
"GL_EXT_unpack_subimage";
const char kBad = 0x12;
struct Cmds {
cmd::SetBucketSize set_bucket_size1;
cmds::GetString get_string;
cmd::GetBucketStart get_bucket_start;
cmd::SetToken set_token1;
cmd::SetBucketSize set_bucket_size2;
};
ExpectedMemoryInfo mem1 = GetExpectedMemory(MaxTransferBufferSize());
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmd::GetBucketStart::Result));
Cmds expected;
expected.set_bucket_size1.Init(kBucketId, 0);
expected.get_string.Init(GL_EXTENSIONS, kBucketId);
expected.get_bucket_start.Init(
kBucketId, result1.id, result1.offset,
MaxTransferBufferSize(), mem1.id, mem1.offset);
expected.set_token1.Init(GetNextToken());
expected.set_bucket_size2.Init(kBucketId, 0);
char buf[sizeof(kString) + 1];
UNSAFE_TODO(memset(buf, kBad, sizeof(buf)));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(DoAll(SetMemory(result1.ptr, uint32_t(sizeof(kString))),
SetMemory(mem1.ptr, kString)))
.RetiresOnSaturation();
const GLubyte* result = gl_->GetString(GL_EXTENSIONS);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_STREQ(expected_str, reinterpret_cast<const char*>(result));
}
TEST_F(GLES2ImplementationTest, CreateProgram) {
struct Cmds {
cmds::CreateProgram cmd;
};
Cmds expected;
expected.cmd.Init(kProgramsAndShadersStartId);
GLuint id = gl_->CreateProgram();
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_EQ(kProgramsAndShadersStartId, id);
}
TEST_F(GLES2ImplementationTest, BufferDataLargerThanTransferBuffer) {
struct Cmds {
cmds::BufferData set_size;
cmds::BufferSubData copy_data1;
cmd::SetToken set_token1;
cmds::BufferSubData copy_data2;
cmd::SetToken set_token2;
};
const unsigned kUsableSize =
kTransferBufferSize - GLES2Implementation::kStartingOffset;
uint8_t buf[kUsableSize * 2] = {
0,
};
ExpectedMemoryInfo mem1 = GetExpectedMemory(kUsableSize);
ExpectedMemoryInfo mem2 = GetExpectedMemory(kUsableSize);
Cmds expected;
expected.set_size.Init(GL_ARRAY_BUFFER, std::size(buf), 0, 0,
GL_DYNAMIC_DRAW);
expected.copy_data1.Init(
GL_ARRAY_BUFFER, 0, kUsableSize, mem1.id, mem1.offset);
expected.set_token1.Init(GetNextToken());
expected.copy_data2.Init(
GL_ARRAY_BUFFER, kUsableSize, kUsableSize, mem2.id, mem2.offset);
expected.set_token2.Init(GetNextToken());
gl_->BufferData(GL_ARRAY_BUFFER, std::size(buf), buf, GL_DYNAMIC_DRAW);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
}
TEST_F(GLES2ImplementationTest, MultiDrawArraysWEBGLLargerThanTransferBuffer) {
struct Cmds {
cmds::MultiDrawBeginCHROMIUM begin;
cmds::MultiDrawArraysCHROMIUM draw1;
cmd::SetToken set_token1;
cmds::MultiDrawArraysCHROMIUM draw2;
cmd::SetToken set_token2;
cmds::MultiDrawEndCHROMIUM end;
};
const unsigned kUsableSize =
kTransferBufferSize - GLES2Implementation::kStartingOffset;
const unsigned kDrawCount = kUsableSize / sizeof(int);
const unsigned kChunkDrawCount = kDrawCount / 2;
const unsigned kCountsOffset = kChunkDrawCount * sizeof(int);
GLint firsts[kDrawCount] = {};
GLsizei counts[kDrawCount] = {};
ExpectedMemoryInfo mem1 = GetExpectedMemory(kUsableSize);
ExpectedMemoryInfo mem2 = GetExpectedMemory(kUsableSize);
Cmds expected;
expected.begin.Init(kDrawCount);
expected.draw1.Init(GL_TRIANGLES, mem1.id, mem1.offset, mem1.id,
mem1.offset + kCountsOffset, kChunkDrawCount);
expected.set_token1.Init(GetNextToken());
expected.draw2.Init(GL_TRIANGLES, mem2.id, mem2.offset, mem2.id,
mem2.offset + kCountsOffset, kChunkDrawCount);
expected.set_token2.Init(GetNextToken());
expected.end.Init();
gl_->MultiDrawArraysWEBGL(GL_TRIANGLES, firsts, counts, kDrawCount);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
}
TEST_F(GLES2ImplementationTest, CapabilitiesAreCached) {
static const auto kStates = std::to_array<GLenum>({
GL_DITHER,
GL_BLEND,
GL_CULL_FACE,
GL_DEPTH_TEST,
GL_POLYGON_OFFSET_FILL,
GL_SAMPLE_ALPHA_TO_COVERAGE,
GL_SAMPLE_COVERAGE,
GL_SCISSOR_TEST,
GL_STENCIL_TEST,
});
struct Cmds {
cmds::Enable enable_cmd;
};
Cmds expected;
for (size_t ii = 0; ii < std::size(kStates); ++ii) {
GLenum state = kStates[ii];
expected.enable_cmd.Init(state);
GLboolean result = gl_->IsEnabled(state);
EXPECT_EQ(static_cast<GLboolean>(ii == 0), result);
EXPECT_TRUE(NoCommandsWritten());
const void* commands = GetPut();
if (!result) {
gl_->Enable(state);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands, sizeof(expected))));
}
ClearCommands();
result = gl_->IsEnabled(state);
EXPECT_TRUE(result);
EXPECT_TRUE(NoCommandsWritten());
}
}
TEST_F(GLES2ImplementationTest, BindVertexArrayOES) {
GLuint id = 0;
gl_->GenVertexArraysOES(1, &id);
ClearCommands();
struct Cmds {
cmds::BindVertexArrayOES cmd;
};
Cmds expected;
expected.cmd.Init(id);
const void* commands = GetPut();
gl_->BindVertexArrayOES(id);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands, sizeof(expected))));
ClearCommands();
gl_->BindVertexArrayOES(id);
EXPECT_TRUE(NoCommandsWritten());
}
TEST_F(GLES2ImplementationTest, BeginEndQueryEXT) {
GLint param = -1;
gl_->GetQueryivEXT(GL_ANY_SAMPLES_PASSED_EXT, GL_CURRENT_QUERY_EXT, ¶m);
EXPECT_EQ(0, param);
GLuint expected_ids[2] = { 1, 2 };
struct GenCmds {
cmds::GenQueriesEXTImmediate gen;
GLuint data[2];
};
GenCmds expected_gen_cmds;
expected_gen_cmds.gen.Init(std::size(expected_ids), &expected_ids[0]);
GLuint ids[std::size(expected_ids)] = {
0,
};
gl_->GenQueriesEXT(std::size(expected_ids), &ids[0]);
UNSAFE_TODO(EXPECT_EQ(
0, memcmp(&expected_gen_cmds, commands_, sizeof(expected_gen_cmds))));
GLuint id1 = ids[0];
GLuint id2 = ids[1];
ClearCommands();
gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, 0);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
struct BeginCmds {
cmds::BeginQueryEXT begin_query;
};
BeginCmds expected_begin_cmds;
const void* commands = GetPut();
gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, id1);
QueryTracker::Query* query = GetQuery(id1);
ASSERT_TRUE(query != nullptr);
expected_begin_cmds.begin_query.Init(
GL_ANY_SAMPLES_PASSED_EXT, id1, query->shm_id(), query->shm_offset());
UNSAFE_TODO(EXPECT_EQ(
0, memcmp(&expected_begin_cmds, commands, sizeof(expected_begin_cmds))));
ClearCommands();
param = -1;
gl_->GetQueryivEXT(GL_ANY_SAMPLES_PASSED_EXT, GL_CURRENT_QUERY_EXT, ¶m);
EXPECT_EQ(id1, static_cast<GLuint>(param));
gl_->GetQueryivEXT(
GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, GL_CURRENT_QUERY_EXT, ¶m);
EXPECT_EQ(0, param);
gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, id2);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
ClearCommands();
gl_->EndQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
struct EndCmds {
cmds::EndQueryEXT end_query;
};
commands = GetPut();
gl_->EndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
EndCmds expected_end_cmds;
expected_end_cmds.end_query.Init(
GL_ANY_SAMPLES_PASSED_EXT, query->submit_count());
UNSAFE_TODO(EXPECT_EQ(
0, memcmp(&expected_end_cmds, commands, sizeof(expected_end_cmds))));
ClearCommands();
gl_->EndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
base::subtle::Atomic32 old_submit_count = query->submit_count();
gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, id1);
EXPECT_EQ(old_submit_count, query->submit_count());
commands = GetPut();
gl_->EndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
EXPECT_NE(old_submit_count, query->submit_count());
expected_end_cmds.end_query.Init(
GL_ANY_SAMPLES_PASSED_EXT, query->submit_count());
UNSAFE_TODO(EXPECT_EQ(
0, memcmp(&expected_end_cmds, commands, sizeof(expected_end_cmds))));
ClearCommands();
gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, id1);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
GLuint available = 0xBDu;
ClearCommands();
gl_->GetQueryObjectuivEXT(id2, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(0xBDu, available);
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
ClearCommands();
gl_->GetQueryObjectuivEXT(4567, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(0xBDu, available);
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
ClearCommands();
gl_->GetQueryObjectuivEXT(id1, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
EXPECT_EQ(0u, available);
GLuint64 available2 = 0xBDu;
ClearCommands();
gl_->GetQueryObjectui64vEXT(id2, GL_QUERY_RESULT_AVAILABLE_EXT, &available2);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(0xBDu, available2);
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
ClearCommands();
gl_->GetQueryObjectui64vEXT(4567, GL_QUERY_RESULT_AVAILABLE_EXT, &available2);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(0xBDu, available2);
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
ClearCommands();
gl_->GetQueryObjectui64vEXT(id1, GL_QUERY_RESULT_AVAILABLE_EXT, &available2);
EXPECT_EQ(0u, available2);
}
TEST_F(GLES2ImplementationManualInitTest, BadQueryTargets) {
ContextInitOptions init_options;
init_options.sync_query = false;
init_options.occlusion_query_boolean = false;
init_options.timer_queries = false;
ASSERT_TRUE(Initialize(init_options));
GLuint id = 0;
gl_->GenQueriesEXT(1, &id);
ClearCommands();
gl_->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, id);
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
EXPECT_EQ(nullptr, GetQuery(id));
gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED, id);
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
EXPECT_EQ(nullptr, GetQuery(id));
gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, id);
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
EXPECT_EQ(nullptr, GetQuery(id));
gl_->BeginQueryEXT(GL_TIME_ELAPSED_EXT, id);
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
EXPECT_EQ(nullptr, GetQuery(id));
gl_->BeginQueryEXT(0x123, id);
EXPECT_EQ(GL_INVALID_ENUM, CheckError());
EXPECT_EQ(nullptr, GetQuery(id));
gl_->QueryCounterEXT(id, GL_TIMESTAMP_EXT);
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
EXPECT_EQ(nullptr, GetQuery(id));
gl_->QueryCounterEXT(id, 0x123);
EXPECT_EQ(GL_INVALID_ENUM, CheckError());
EXPECT_EQ(nullptr, GetQuery(id));
}
TEST_F(GLES2ImplementationTest, SetDisjointSync) {
struct SetDisjointSyncCmd {
cmds::SetDisjointValueSyncCHROMIUM disjoint_sync;
};
SetDisjointSyncCmd expected_disjoint_sync_cmd;
const void* commands = GetPut();
gl_->SetDisjointValueSyncCHROMIUM();
expected_disjoint_sync_cmd.disjoint_sync.Init(
GetQueryTracker()->DisjointCountSyncShmID(),
GetQueryTracker()->DisjointCountSyncShmOffset());
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected_disjoint_sync_cmd, commands,
sizeof(expected_disjoint_sync_cmd))));
}
TEST_F(GLES2ImplementationTest, QueryCounterEXT) {
GLuint expected_ids[2] = {1, 2};
struct GenCmds {
cmds::GenQueriesEXTImmediate gen;
GLuint data[2];
};
GenCmds expected_gen_cmds;
expected_gen_cmds.gen.Init(std::size(expected_ids), &expected_ids[0]);
GLuint ids[std::size(expected_ids)] = {
0,
};
gl_->GenQueriesEXT(std::size(expected_ids), &ids[0]);
UNSAFE_TODO(EXPECT_EQ(
0, memcmp(&expected_gen_cmds, commands_, sizeof(expected_gen_cmds))));
GLuint id1 = ids[0];
GLuint id2 = ids[1];
ClearCommands();
gl_->SetDisjointValueSyncCHROMIUM();
ClearCommands();
gl_->QueryCounterEXT(0, GL_TIMESTAMP_EXT);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
ClearCommands();
gl_->QueryCounterEXT(id1, GL_TIME_ELAPSED_EXT);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_INVALID_ENUM, CheckError());
struct QueryCounterCmds {
cmds::QueryCounterEXT query_counter;
};
QueryCounterCmds expected_query_counter_cmds;
const void* commands = GetPut();
gl_->QueryCounterEXT(id1, GL_TIMESTAMP_EXT);
EXPECT_EQ(GL_NO_ERROR, CheckError());
QueryTracker::Query* query = GetQuery(id1);
ASSERT_TRUE(query != nullptr);
expected_query_counter_cmds.query_counter.Init(
id1, GL_TIMESTAMP_EXT, query->shm_id(), query->shm_offset(),
query->submit_count());
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected_query_counter_cmds, commands,
sizeof(expected_query_counter_cmds))));
commands = GetPut();
gl_->QueryCounterEXT(id2, GL_TIMESTAMP_EXT);
EXPECT_EQ(GL_NO_ERROR, CheckError());
QueryTracker::Query* query2 = GetQuery(id2);
ASSERT_TRUE(query2 != nullptr);
expected_query_counter_cmds.query_counter.Init(
id2, GL_TIMESTAMP_EXT, query2->shm_id(), query2->shm_offset(),
query2->submit_count());
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected_query_counter_cmds, commands,
sizeof(expected_query_counter_cmds))));
ClearCommands();
base::subtle::Atomic32 old_submit_count = query->submit_count();
commands = GetPut();
gl_->QueryCounterEXT(id1, GL_TIMESTAMP_EXT);
EXPECT_EQ(GL_NO_ERROR, CheckError());
EXPECT_NE(old_submit_count, query->submit_count());
expected_query_counter_cmds.query_counter.Init(
id1, GL_TIMESTAMP_EXT, query->shm_id(), query->shm_offset(),
query->submit_count());
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected_query_counter_cmds, commands,
sizeof(expected_query_counter_cmds))));
ClearCommands();
GLuint available = 0xBDu;
ClearCommands();
gl_->GetQueryObjectuivEXT(id1, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
EXPECT_EQ(0u, available);
GLuint64 available2 = 0xBDu;
ClearCommands();
gl_->GetQueryObjectui64vEXT(id1, GL_QUERY_RESULT_AVAILABLE_EXT, &available2);
EXPECT_EQ(0u, available2);
}
TEST_F(GLES2ImplementationTest, ErrorQuery) {
GLuint id = 0;
gl_->GenQueriesEXT(1, &id);
ClearCommands();
gl_->BeginQueryEXT(GL_GET_ERROR_QUERY_CHROMIUM, id);
EXPECT_TRUE(NoCommandsWritten());
QueryTracker::Query* query = GetQuery(id);
ASSERT_TRUE(query != nullptr);
struct EndCmds {
cmds::BeginQueryEXT begin_query;
cmds::EndQueryEXT end_query;
};
const void* commands = GetPut();
gl_->EndQueryEXT(GL_GET_ERROR_QUERY_CHROMIUM);
EndCmds expected_end_cmds;
expected_end_cmds.begin_query.Init(
GL_GET_ERROR_QUERY_CHROMIUM, id, query->shm_id(), query->shm_offset());
expected_end_cmds.end_query.Init(
GL_GET_ERROR_QUERY_CHROMIUM, query->submit_count());
UNSAFE_TODO(EXPECT_EQ(
0, memcmp(&expected_end_cmds, commands, sizeof(expected_end_cmds))));
ClearCommands();
GLuint available = 0xBDu;
gl_->GetQueryObjectuivEXT(id, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(0u, available);
gl_->ActiveTexture(GL_TEXTURE0 - 1);
gl_->BeginQueryEXT(GL_GET_ERROR_QUERY_CHROMIUM, id);
gl_->EndQueryEXT(GL_GET_ERROR_QUERY_CHROMIUM);
EXPECT_TRUE(NoCommandsWritten());
gl_->GetQueryObjectuivEXT(id, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_NE(0u, available);
GLuint result = 0xBDu;
gl_->GetQueryObjectuivEXT(id, GL_QUERY_RESULT_EXT, &result);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(static_cast<GLuint>(GL_INVALID_ENUM), result);
}
TEST_F(GLES2ImplementationTest, VertexArrays) {
const GLuint kAttribIndex1 = 1;
const GLint kNumComponents1 = 3;
const GLsizei kClientStride = 12;
GLuint id = 0;
gl_->GenVertexArraysOES(1, &id);
ClearCommands();
gl_->BindVertexArrayOES(id);
gl_->BindBuffer(GL_ARRAY_BUFFER, 0);
gl_->VertexAttribPointer(
kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, kClientStride,
reinterpret_cast<const void*>(4));
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
gl_->VertexAttribPointer(kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE,
kClientStride, nullptr);
EXPECT_EQ(GL_NO_ERROR, CheckError());
}
TEST_F(GLES2ImplementationTest, Disable) {
struct Cmds {
cmds::Disable cmd;
};
Cmds expected;
expected.cmd.Init(GL_DITHER);
gl_->Disable(GL_DITHER);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
ClearCommands();
gl_->Disable(GL_DITHER);
EXPECT_TRUE(NoCommandsWritten());
}
TEST_F(GLES2ImplementationTest, Enable) {
struct Cmds {
cmds::Enable cmd;
};
Cmds expected;
expected.cmd.Init(GL_BLEND);
gl_->Enable(GL_BLEND);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
ClearCommands();
gl_->Enable(GL_BLEND);
EXPECT_TRUE(NoCommandsWritten());
}
TEST_F(GLES2ImplementationTest, CreateAndTexStorage2DSharedImageCHROMIUM) {
struct Cmds {
cmds::CreateAndTexStorage2DSharedImageINTERNALImmediate cmd;
GLbyte data[GL_MAILBOX_SIZE_CHROMIUM];
};
Mailbox mailbox = Mailbox::Generate();
Cmds expected;
expected.cmd.Init(kTexturesStartId, mailbox.name);
GLuint id = gl_->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox.name);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_EQ(kTexturesStartId, id);
}
TEST_F(GLES2ImplementationTest, LimitSizeAndOffsetTo32Bit) {
GLsizeiptr size;
GLintptr offset;
if (sizeof(size) <= 4 || sizeof(offset) <= 4)
return;
int64_t value64 = 0x100000000;
size = static_cast<GLsizeiptr>(value64);
offset = static_cast<GLintptr>(value64);
const char kSizeOverflowMessage[] = "size more than 32-bit";
const char kOffsetOverflowMessage[] = "offset more than 32-bit";
const GLfloat buf[] = { 1.0, 1.0, 1.0, 1.0 };
const GLubyte indices[] = { 0 };
GLuint buffer_ids[2];
gl_->GenBuffers(2, buffer_ids);
gl_->BindBuffer(GL_ARRAY_BUFFER, buffer_ids[0]);
gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_ids[1]);
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->BufferData(GL_ARRAY_BUFFER, sizeof(buf), buf, GL_DYNAMIC_DRAW);
gl_->BufferData(
GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW);
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->BufferData(GL_ARRAY_BUFFER, size, buf, GL_DYNAMIC_DRAW);
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
EXPECT_STREQ(kSizeOverflowMessage, GetLastError().c_str());
gl_->BufferSubData(GL_ARRAY_BUFFER, 0, sizeof(buf[0]), buf);
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->BufferSubData(GL_ARRAY_BUFFER, offset, 1, buf);
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->BufferSubData(GL_ARRAY_BUFFER, 0, size, buf);
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
EXPECT_STREQ(kSizeOverflowMessage, GetLastError().c_str());
void* mem =
gl_->MapBufferSubDataCHROMIUM(GL_ARRAY_BUFFER, 0, 1, GL_WRITE_ONLY);
EXPECT_TRUE(nullptr != mem);
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->UnmapBufferSubDataCHROMIUM(mem);
EXPECT_TRUE(nullptr == gl_->MapBufferSubDataCHROMIUM(GL_ARRAY_BUFFER, offset,
1, GL_WRITE_ONLY));
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
EXPECT_EQ(GL_NO_ERROR, CheckError());
EXPECT_TRUE(nullptr == gl_->MapBufferSubDataCHROMIUM(GL_ARRAY_BUFFER, 0, size,
GL_WRITE_ONLY));
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
EXPECT_STREQ(kSizeOverflowMessage, GetLastError().c_str());
gl_->DrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, nullptr);
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->DrawElements(
GL_POINTS, 1, GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
gl_->DrawElementsInstancedANGLE(GL_POINTS, 1, GL_UNSIGNED_BYTE, nullptr, 1);
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->DrawElementsInstancedANGLE(
GL_POINTS, 1, GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset), 1);
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
const GLuint kAttribIndex = 1;
const GLsizei kStride = 4;
gl_->VertexAttribPointer(kAttribIndex, 1, GL_FLOAT, GL_FALSE, kStride,
nullptr);
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->VertexAttribPointer(
kAttribIndex, 1, GL_FLOAT, GL_FALSE, kStride,
reinterpret_cast<void*>(offset));
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
}
TEST_F(GLES2ImplementationTest, TraceBeginCHROMIUM) {
const uint32_t kCategoryBucketId = GLES2Implementation::kResultBucketId;
const uint32_t kNameBucketId = GLES2Implementation::kResultBucketId + 1;
const std::string category_name = "test category";
const std::string trace_name = "test trace";
const size_t kPaddedString1Size =
transfer_buffer_->RoundToAlignment(category_name.size() + 1);
const size_t kPaddedString2Size =
transfer_buffer_->RoundToAlignment(trace_name.size() + 1);
gl_->TraceBeginCHROMIUM(category_name.c_str(), trace_name.c_str());
EXPECT_EQ(GL_NO_ERROR, CheckError());
struct Cmds {
cmd::SetBucketSize category_size1;
cmd::SetBucketData category_data;
cmd::SetToken set_token1;
cmd::SetBucketSize name_size1;
cmd::SetBucketData name_data;
cmd::SetToken set_token2;
cmds::TraceBeginCHROMIUM trace_call_begin;
cmd::SetBucketSize category_size2;
cmd::SetBucketSize name_size2;
};
ExpectedMemoryInfo mem1 = GetExpectedMemory(kPaddedString1Size);
ExpectedMemoryInfo mem2 = GetExpectedMemory(kPaddedString2Size);
ASSERT_STREQ(category_name.c_str(), reinterpret_cast<char*>(mem1.ptr));
ASSERT_STREQ(trace_name.c_str(), reinterpret_cast<char*>(mem2.ptr));
Cmds expected;
expected.category_size1.Init(kCategoryBucketId, category_name.size() + 1);
expected.category_data.Init(
kCategoryBucketId, 0, category_name.size() + 1, mem1.id, mem1.offset);
expected.set_token1.Init(GetNextToken());
expected.name_size1.Init(kNameBucketId, trace_name.size() + 1);
expected.name_data.Init(
kNameBucketId, 0, trace_name.size() + 1, mem2.id, mem2.offset);
expected.set_token2.Init(GetNextToken());
expected.trace_call_begin.Init(kCategoryBucketId, kNameBucketId);
expected.category_size2.Init(kCategoryBucketId, 0);
expected.name_size2.Init(kNameBucketId, 0);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
}
TEST_F(GLES2ImplementationTest, SetActiveURLCHROMIUM) {
const uint32_t kURLBucketId = GLES2Implementation::kResultBucketId;
const std::string url = "chrome://test";
const size_t kPaddedStringSize =
transfer_buffer_->RoundToAlignment(url.size());
gl_->SetActiveURLCHROMIUM(url.c_str());
EXPECT_EQ(GL_NO_ERROR, CheckError());
struct Cmds {
cmd::SetBucketSize url_size;
cmd::SetBucketData url_data;
cmd::SetToken set_token;
cmds::SetActiveURLCHROMIUM set_url_call;
cmd::SetBucketSize url_size_end;
};
ExpectedMemoryInfo mem = GetExpectedMemory(kPaddedStringSize);
UNSAFE_TODO(EXPECT_EQ(
0, memcmp(url.c_str(), reinterpret_cast<char*>(mem.ptr), url.size())));
Cmds expected;
expected.url_size.Init(kURLBucketId, url.size());
expected.url_data.Init(kURLBucketId, 0, url.size(), mem.id, mem.offset);
expected.set_token.Init(GetNextToken());
expected.set_url_call.Init(kURLBucketId);
expected.url_size_end.Init(kURLBucketId, 0);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_FALSE(NoCommandsWritten());
ClearCommands();
gl_->SetActiveURLCHROMIUM(url.c_str());
EXPECT_TRUE(NoCommandsWritten());
}
TEST_F(GLES2ImplementationTest, AllowNestedTracesCHROMIUM) {
const std::string category1_name = "test category 1";
const std::string trace1_name = "test trace 1";
const std::string category2_name = "test category 2";
const std::string trace2_name = "test trace 2";
gl_->TraceBeginCHROMIUM(category1_name.c_str(), trace1_name.c_str());
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->TraceBeginCHROMIUM(category2_name.c_str(), trace2_name.c_str());
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->TraceEndCHROMIUM();
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->TraceEndCHROMIUM();
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->TraceEndCHROMIUM();
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
}
TEST_F(GLES2ImplementationTest, GenSyncTokenCHROMIUM) {
const CommandBufferNamespace kNamespaceId = CommandBufferNamespace::GPU_IO;
const CommandBufferId kCommandBufferId =
CommandBufferId::FromUnsafeValue(234u);
const GLuint64 kFenceSync = 123u;
SyncToken sync_token;
EXPECT_CALL(*gpu_control_, GetNamespaceID())
.WillRepeatedly(Return(kNamespaceId));
EXPECT_CALL(*gpu_control_, GetCommandBufferID())
.WillRepeatedly(Return(kCommandBufferId));
gl_->GenSyncTokenCHROMIUM(nullptr);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_INVALID_VALUE, CheckError());
const void* commands = GetPut();
cmd::InsertFenceSync insert_fence_sync;
insert_fence_sync.Init(kFenceSync);
EXPECT_CALL(*gpu_control_, GenerateFenceSyncRelease())
.WillOnce(Return(kFenceSync));
EXPECT_CALL(*gpu_control_, EnsureWorkVisible());
gl_->GenSyncTokenCHROMIUM(sync_token.GetData());
UNSAFE_TODO(EXPECT_EQ(
0, memcmp(&insert_fence_sync, commands, sizeof(insert_fence_sync))));
EXPECT_EQ(GL_NO_ERROR, CheckError());
EXPECT_TRUE(sync_token.verified_flush());
EXPECT_EQ(kNamespaceId, sync_token.namespace_id());
EXPECT_EQ(kCommandBufferId, sync_token.command_buffer_id());
EXPECT_EQ(kFenceSync, sync_token.release_count());
}
TEST_F(GLES2ImplementationTest, GenUnverifiedSyncTokenCHROMIUM) {
const CommandBufferNamespace kNamespaceId = CommandBufferNamespace::GPU_IO;
const CommandBufferId kCommandBufferId =
CommandBufferId::FromUnsafeValue(234u);
const GLuint64 kFenceSync = 123u;
SyncToken sync_token;
EXPECT_CALL(*gpu_control_, GetNamespaceID())
.WillRepeatedly(Return(kNamespaceId));
EXPECT_CALL(*gpu_control_, GetCommandBufferID())
.WillRepeatedly(Return(kCommandBufferId));
gl_->GenUnverifiedSyncTokenCHROMIUM(nullptr);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_INVALID_VALUE, CheckError());
const void* commands = GetPut();
cmd::InsertFenceSync insert_fence_sync;
insert_fence_sync.Init(kFenceSync);
EXPECT_CALL(*gpu_control_, GenerateFenceSyncRelease())
.WillOnce(Return(kFenceSync));
gl_->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
UNSAFE_TODO(EXPECT_EQ(
0, memcmp(&insert_fence_sync, commands, sizeof(insert_fence_sync))));
EXPECT_EQ(GL_NO_ERROR, CheckError());
EXPECT_FALSE(sync_token.verified_flush());
EXPECT_EQ(kNamespaceId, sync_token.namespace_id());
EXPECT_EQ(kCommandBufferId, sync_token.command_buffer_id());
EXPECT_EQ(kFenceSync, sync_token.release_count());
}
TEST_F(GLES2ImplementationTest, VerifySyncTokensCHROMIUM) {
ExpectedMemoryInfo result =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillRepeatedly(SetMemory(result.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
const CommandBufferNamespace kNamespaceId = CommandBufferNamespace::GPU_IO;
const CommandBufferId kCommandBufferId =
CommandBufferId::FromUnsafeValue(234u);
const GLuint64 kFenceSync = 123u;
gpu::SyncToken sync_token;
GLbyte* sync_token_datas[] = {sync_token.GetData()};
EXPECT_CALL(*gpu_control_, GetNamespaceID())
.WillRepeatedly(Return(kNamespaceId));
EXPECT_CALL(*gpu_control_, GetCommandBufferID())
.WillRepeatedly(Return(kCommandBufferId));
EXPECT_CALL(*gpu_control_, GenerateFenceSyncRelease())
.WillOnce(Return(kFenceSync));
gl_->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
EXPECT_TRUE(sync_token.HasData());
EXPECT_FALSE(sync_token.verified_flush());
ClearCommands();
EXPECT_CALL(*gpu_control_, CanWaitUnverifiedSyncToken(sync_token))
.WillOnce(Return(false));
gl_->VerifySyncTokensCHROMIUM(sync_token_datas, 1);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
EXPECT_FALSE(sync_token.verified_flush());
ClearCommands();
EXPECT_CALL(*gpu_control_, CanWaitUnverifiedSyncToken(sync_token))
.WillOnce(Return(true));
EXPECT_CALL(*gpu_control_, EnsureWorkVisible());
gl_->VerifySyncTokensCHROMIUM(sync_token_datas, std::size(sync_token_datas));
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_NO_ERROR, CheckError());
EXPECT_EQ(kNamespaceId, sync_token.namespace_id());
EXPECT_EQ(kCommandBufferId, sync_token.command_buffer_id());
EXPECT_EQ(kFenceSync, sync_token.release_count());
EXPECT_TRUE(sync_token.verified_flush());
}
TEST_F(GLES2ImplementationTest, VerifySyncTokensCHROMIUM_Sequence) {
ExpectedMemoryInfo result =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillRepeatedly(SetMemory(result.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
const CommandBufferNamespace kNamespaceId = CommandBufferNamespace::GPU_IO;
const CommandBufferId kCommandBufferId =
CommandBufferId::FromUnsafeValue(234u);
const GLuint64 kFenceSync1 = 123u;
const GLuint64 kFenceSync2 = 234u;
gpu::SyncToken sync_token1;
gpu::SyncToken sync_token2;
GLbyte* sync_token_datas[] = {sync_token1.GetData(), sync_token2.GetData()};
EXPECT_CALL(*gpu_control_, GetNamespaceID())
.WillRepeatedly(Return(kNamespaceId));
EXPECT_CALL(*gpu_control_, GetCommandBufferID())
.WillRepeatedly(Return(kCommandBufferId));
EXPECT_CALL(*gpu_control_, GenerateFenceSyncRelease())
.WillOnce(Return(kFenceSync1));
gl_->GenUnverifiedSyncTokenCHROMIUM(sync_token1.GetData());
EXPECT_TRUE(sync_token1.HasData());
EXPECT_FALSE(sync_token1.verified_flush());
EXPECT_CALL(*gpu_control_, GenerateFenceSyncRelease())
.WillOnce(Return(kFenceSync2));
gl_->GenUnverifiedSyncTokenCHROMIUM(sync_token2.GetData());
EXPECT_TRUE(sync_token2.HasData());
EXPECT_FALSE(sync_token2.verified_flush());
Sequence sequence;
EXPECT_CALL(*gpu_control_, CanWaitUnverifiedSyncToken(sync_token1))
.InSequence(sequence)
.WillOnce(Return(true));
EXPECT_CALL(*gpu_control_, CanWaitUnverifiedSyncToken(sync_token2))
.InSequence(sequence)
.WillOnce(Return(true));
EXPECT_CALL(*gpu_control_, EnsureWorkVisible()).InSequence(sequence);
gl_->VerifySyncTokensCHROMIUM(sync_token_datas, std::size(sync_token_datas));
EXPECT_EQ(GL_NO_ERROR, CheckError());
EXPECT_TRUE(sync_token1.verified_flush());
EXPECT_TRUE(sync_token2.verified_flush());
}
TEST_F(GLES2ImplementationTest, VerifySyncTokensCHROMIUM_EmptySyncToken) {
ExpectedMemoryInfo result =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillRepeatedly(SetMemory(result.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
gpu::SyncToken sync_token1, sync_token2;
GLbyte* sync_token_datas[] = {sync_token1.GetData(), sync_token2.GetData()};
EXPECT_CALL(*gpu_control_, CanWaitUnverifiedSyncToken(_)).Times(0);
EXPECT_CALL(*gpu_control_, EnsureWorkVisible()).Times(0);
gl_->VerifySyncTokensCHROMIUM(sync_token_datas, std::size(sync_token_datas));
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_NO_ERROR, CheckError());
EXPECT_TRUE(sync_token1.verified_flush());
EXPECT_TRUE(sync_token2.verified_flush());
}
TEST_F(GLES2ImplementationTest, WaitSyncTokenCHROMIUM) {
const CommandBufferNamespace kNamespaceId = CommandBufferNamespace::GPU_IO;
const CommandBufferId kCommandBufferId =
CommandBufferId::FromUnsafeValue(234u);
const GLuint64 kFenceSync = 456u;
gpu::SyncToken sync_token;
GLbyte* sync_token_data = sync_token.GetData();
struct Cmds {
cmd::InsertFenceSync insert_fence_sync;
};
Cmds expected;
expected.insert_fence_sync.Init(kFenceSync);
EXPECT_CALL(*gpu_control_, GetNamespaceID()).WillOnce(Return(kNamespaceId));
EXPECT_CALL(*gpu_control_, GetCommandBufferID())
.WillOnce(Return(kCommandBufferId));
EXPECT_CALL(*gpu_control_, GenerateFenceSyncRelease())
.WillOnce(Return(kFenceSync));
EXPECT_CALL(*gpu_control_, EnsureWorkVisible());
gl_->GenSyncTokenCHROMIUM(sync_token_data);
EXPECT_CALL(*gpu_control_, WaitSyncToken(sync_token));
gl_->WaitSyncTokenCHROMIUM(sync_token_data);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
}
TEST_F(GLES2ImplementationTest, WaitSyncTokenCHROMIUMErrors) {
ExpectedMemoryInfo result =
GetExpectedResultMemory(sizeof(cmds::GetError::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillRepeatedly(SetMemory(result.ptr, GLuint(GL_NO_ERROR)))
.RetiresOnSaturation();
ClearCommands();
gl_->WaitSyncTokenCHROMIUM(nullptr);
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
ClearCommands();
gpu::SyncToken invalid_sync_token;
gl_->WaitSyncTokenCHROMIUM(invalid_sync_token.GetConstData());
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
ClearCommands();
gpu::SyncToken unverified_sync_token(CommandBufferNamespace::GPU_IO,
gpu::CommandBufferId(), 0);
EXPECT_CALL(*gpu_control_, CanWaitUnverifiedSyncToken(unverified_sync_token))
.WillOnce(Return(false));
gl_->WaitSyncTokenCHROMIUM(unverified_sync_token.GetConstData());
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
}
TEST_F(GLES2ImplementationTest, IsEnabled) {
GLenum kCap = 1;
struct Cmds {
cmds::IsEnabled cmd;
};
Cmds expected;
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmds::IsEnabled::Result));
expected.cmd.Init(kCap, result1.id, result1.offset);
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result1.ptr, uint32_t(GL_TRUE)))
.RetiresOnSaturation();
GLboolean result = gl_->IsEnabled(kCap);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_TRUE(result);
}
TEST_F(GLES2ImplementationTest, ClientWaitSync) {
const GLuint client_sync_id = 36;
struct Cmds {
cmds::ClientWaitSync cmd;
};
Cmds expected;
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(cmds::ClientWaitSync::Result));
const GLuint64 kTimeout = 0xABCDEF0123456789;
expected.cmd.Init(client_sync_id, GL_SYNC_FLUSH_COMMANDS_BIT,
kTimeout, result1.id, result1.offset);
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result1.ptr, uint32_t(GL_CONDITION_SATISFIED)))
.RetiresOnSaturation();
GLenum result = gl_->ClientWaitSync(
reinterpret_cast<GLsync>(client_sync_id), GL_SYNC_FLUSH_COMMANDS_BIT,
kTimeout);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_EQ(static_cast<GLenum>(GL_CONDITION_SATISFIED), result);
}
TEST_F(GLES2ImplementationTest, WaitSync) {
const GLuint kClientSyncId = 36;
struct Cmds {
cmds::WaitSync cmd;
};
Cmds expected;
const GLuint64 kTimeout = GL_TIMEOUT_IGNORED;
expected.cmd.Init(kClientSyncId, 0, kTimeout);
gl_->WaitSync(reinterpret_cast<GLsync>(kClientSyncId), 0, kTimeout);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
}
TEST_F(GLES2ImplementationTest, MapBufferRangeUnmapBufferWrite) {
ExpectedMemoryInfo result =
GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result.ptr, uint32_t(1)))
.RetiresOnSaturation();
GLuint buffer_id;
gl_->GenBuffers(1, &buffer_id);
gl_->BindBuffer(GL_ARRAY_BUFFER, buffer_id);
void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_WRITE_BIT);
EXPECT_TRUE(mem != nullptr);
EXPECT_TRUE(gl_->UnmapBuffer(GL_ARRAY_BUFFER));
}
TEST_F(GLES2ImplementationTest, MapBufferRangeWriteWithInvalidateBit) {
ExpectedMemoryInfo result =
GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result.ptr, uint32_t(1)))
.RetiresOnSaturation();
GLuint buffer_id;
gl_->GenBuffers(1, &buffer_id);
gl_->BindBuffer(GL_ARRAY_BUFFER, buffer_id);
GLsizeiptr kSize = 64;
void* mem = gl_->MapBufferRange(
GL_ARRAY_BUFFER, 10, kSize,
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
EXPECT_TRUE(mem != nullptr);
std::vector<int8_t> zero(kSize);
UNSAFE_TODO(memset(&zero[0], 0, kSize));
UNSAFE_TODO(EXPECT_EQ(0, memcmp(mem, &zero[0], kSize)));
}
TEST_F(GLES2ImplementationTest, MapBufferRangeWriteWithGLError) {
ExpectedMemoryInfo result =
GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result.ptr, uint32_t(0)))
.RetiresOnSaturation();
GLuint buffer_id;
gl_->GenBuffers(1, &buffer_id);
gl_->BindBuffer(GL_ARRAY_BUFFER, buffer_id);
void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_WRITE_BIT);
EXPECT_TRUE(mem == nullptr);
}
TEST_F(GLES2ImplementationTest, MapBufferRangeUnmapBufferRead) {
ExpectedMemoryInfo result =
GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result.ptr, uint32_t(1)))
.RetiresOnSaturation();
GLuint buffer_id;
gl_->GenBuffers(1, &buffer_id);
gl_->BindBuffer(GL_ARRAY_BUFFER, buffer_id);
void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_READ_BIT);
EXPECT_TRUE(mem != nullptr);
EXPECT_TRUE(gl_->UnmapBuffer(GL_ARRAY_BUFFER));
}
TEST_F(GLES2ImplementationTest, MapBufferRangeReadWithGLError) {
ExpectedMemoryInfo result =
GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result.ptr, uint32_t(0)))
.RetiresOnSaturation();
GLuint buffer_id;
gl_->GenBuffers(1, &buffer_id);
gl_->BindBuffer(GL_ARRAY_BUFFER, buffer_id);
void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_READ_BIT);
EXPECT_TRUE(mem == nullptr);
}
TEST_F(GLES2ImplementationTest, UnmapBufferFails) {
EXPECT_FALSE(gl_->UnmapBuffer(GL_ARRAY_BUFFER));
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
GLuint buffer_id;
gl_->GenBuffers(1, &buffer_id);
gl_->BindBuffer(GL_ARRAY_BUFFER, buffer_id);
EXPECT_FALSE(gl_->UnmapBuffer(GL_ARRAY_BUFFER));
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
}
TEST_F(GLES2ImplementationTest, BufferDataUnmapsDataStore) {
ExpectedMemoryInfo result =
GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result.ptr, uint32_t(1)))
.RetiresOnSaturation();
GLuint buffer_id;
gl_->GenBuffers(1, &buffer_id);
gl_->BindBuffer(GL_ARRAY_BUFFER, buffer_id);
void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_WRITE_BIT);
EXPECT_TRUE(mem != nullptr);
std::vector<uint8_t> data(16);
gl_->BufferData(GL_ARRAY_BUFFER, 16, &data[0], GL_STREAM_DRAW);
EXPECT_FALSE(gl_->UnmapBuffer(GL_ARRAY_BUFFER));
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
}
TEST_F(GLES2ImplementationTest, DeleteBuffersUnmapsDataStore) {
ExpectedMemoryInfo result =
GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result));
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result.ptr, uint32_t(1)))
.RetiresOnSaturation();
GLuint buffer_id = 0;
gl_->GenBuffers(1, &buffer_id);
gl_->BindBuffer(GL_ARRAY_BUFFER, buffer_id);
void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_WRITE_BIT);
EXPECT_TRUE(mem != nullptr);
std::vector<uint8_t> data(16);
gl_->DeleteBuffers(1, &buffer_id);
EXPECT_FALSE(gl_->UnmapBuffer(GL_ARRAY_BUFFER));
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
}
TEST_F(GLES2ImplementationTest, GetInternalformativ) {
const GLint kNumSampleCounts = 8;
struct Cmds {
cmds::GetInternalformativ cmd;
};
typedef cmds::GetInternalformativ::Result::Type ResultType;
ResultType result = 0;
Cmds expected;
ExpectedMemoryInfo result1 =
GetExpectedResultMemory(sizeof(uint32_t) + sizeof(ResultType));
expected.cmd.Init(123, GL_RGBA8, GL_NUM_SAMPLE_COUNTS,
result1.id, result1.offset);
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result1.ptr,
SizedResultHelper<ResultType>(kNumSampleCounts)))
.RetiresOnSaturation();
gl_->GetInternalformativ(123, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, 1, &result);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
EXPECT_EQ(static_cast<ResultType>(kNumSampleCounts), result);
}
static void CountCallback(int* count) {
(*count)++;
}
TEST_F(GLES2ImplementationTest, SignalSyncToken) {
const CommandBufferNamespace kNamespaceId = CommandBufferNamespace::GPU_IO;
const CommandBufferId kCommandBufferId = CommandBufferId::FromUnsafeValue(1);
const uint64_t kFenceSync = 123u;
EXPECT_CALL(*gpu_control_, GetNamespaceID())
.WillRepeatedly(Return(kNamespaceId));
EXPECT_CALL(*gpu_control_, GetCommandBufferID())
.WillRepeatedly(Return(kCommandBufferId));
EXPECT_CALL(*gpu_control_, GenerateFenceSyncRelease())
.WillOnce(Return(kFenceSync));
EXPECT_CALL(*gpu_control_, EnsureWorkVisible());
gpu::SyncToken sync_token;
gl_->GenSyncTokenCHROMIUM(sync_token.GetData());
int signaled_count = 0;
base::OnceClosure signal_closure;
EXPECT_CALL(*gpu_control_, DoSignalSyncToken(_, _))
.WillOnce([&signal_closure](const SyncToken& sync_token,
base::OnceClosure* callback) {
signal_closure = std::move(*callback);
});
gl_->SignalSyncToken(sync_token,
base::BindOnce(&CountCallback, &signaled_count));
EXPECT_EQ(0, signaled_count);
std::move(signal_closure).Run();
EXPECT_EQ(1, signaled_count);
}
TEST_F(GLES2ImplementationTest, SignalSyncTokenAfterContextLoss) {
const CommandBufferNamespace kNamespaceId = CommandBufferNamespace::GPU_IO;
const CommandBufferId kCommandBufferId = CommandBufferId::FromUnsafeValue(1);
const uint64_t kFenceSync = 123u;
EXPECT_CALL(*gpu_control_, GetNamespaceID()).WillOnce(Return(kNamespaceId));
EXPECT_CALL(*gpu_control_, GetCommandBufferID())
.WillOnce(Return(kCommandBufferId));
EXPECT_CALL(*gpu_control_, GenerateFenceSyncRelease())
.WillOnce(Return(kFenceSync));
EXPECT_CALL(*gpu_control_, EnsureWorkVisible());
gpu::SyncToken sync_token;
gl_->GenSyncTokenCHROMIUM(sync_token.GetData());
int signaled_count = 0;
base::OnceClosure signal_closure;
EXPECT_CALL(*gpu_control_, DoSignalSyncToken(_, _))
.WillOnce([&signal_closure](const SyncToken& sync_token,
base::OnceClosure* callback) {
signal_closure = std::move(*callback);
});
gl_->SignalSyncToken(sync_token,
base::BindOnce(&CountCallback, &signaled_count));
EXPECT_EQ(0, signaled_count);
GpuControlClient* gl_as_client = gl_;
gl_as_client->OnGpuControlLostContext();
std::move(signal_closure).Run();
EXPECT_EQ(0, signaled_count);
}
TEST_F(GLES2ImplementationTest, ReportLoss) {
GpuControlClient* gl_as_client = gl_;
int lost_count = 0;
gl_->SetLostContextCallback(base::BindOnce(&CountCallback, &lost_count));
EXPECT_EQ(0, lost_count);
EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetGraphicsResetStatusKHR());
gl_as_client->OnGpuControlLostContext();
EXPECT_NE(static_cast<GLenum>(GL_NO_ERROR), gl_->GetGraphicsResetStatusKHR());
EXPECT_EQ(1, lost_count);
}
TEST_F(GLES2ImplementationTest, ReportLossReentrant) {
GpuControlClient* gl_as_client = gl_;
int lost_count = 0;
gl_->SetLostContextCallback(base::BindOnce(&CountCallback, &lost_count));
EXPECT_EQ(0, lost_count);
EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetGraphicsResetStatusKHR());
gl_as_client->OnGpuControlLostContextMaybeReentrant();
EXPECT_NE(static_cast<GLenum>(GL_NO_ERROR), gl_->GetGraphicsResetStatusKHR());
EXPECT_EQ(0, lost_count);
}
TEST_F(GLES2ImplementationManualInitTest, FailInitOnTransferBufferFail) {
ContextInitOptions init_options;
init_options.transfer_buffer_initialize_fail = true;
EXPECT_FALSE(Initialize(init_options));
}
struct ErrorMessageCounter {
explicit ErrorMessageCounter(GLES2Implementation* gl) : gl(gl) {}
void Callback(const char* message, int32_t id) {
if (++num_calls == 1)
gl->ShaderBinary(-1, nullptr, 0, nullptr, 0);
}
raw_ptr<GLES2Implementation> gl;
int32_t num_calls = 0;
};
TEST_F(GLES2ImplementationTest, ReentrantErrorCallbacksShouldNotCrash) {
ErrorMessageCounter counter(gl_);
gl_->SetErrorMessageCallback(base::BindRepeating(
&ErrorMessageCounter::Callback, base::Unretained(&counter)));
gl_->ShaderBinary(-1, nullptr, 0, nullptr, 0);
EXPECT_EQ(2, counter.num_calls);
ResetErrorMessageCallback();
}
TEST_F(GLES2ImplementationTest, DeleteZero) {
gl_->DeleteProgram(0);
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->DeleteShader(0);
EXPECT_EQ(GL_NO_ERROR, CheckError());
gl_->DeleteSync(0);
EXPECT_EQ(GL_NO_ERROR, CheckError());
}
TEST_F(GLES2ImplementationTest, BindBuffer) {
struct Cmds {
cmds::GenBuffersImmediate gen;
GLuint id;
cmds::BindBuffer cmd;
};
Cmds expected;
expected.gen.Init(1, &expected.id);
expected.id = kBuffersStartId;
expected.cmd.Init(GL_ARRAY_BUFFER, kBuffersStartId);
gl_->GenBuffers(1, &expected.id);
gl_->BindBuffer(GL_ARRAY_BUFFER, expected.id);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
ClearCommands();
gl_->BindBuffer(GL_ARRAY_BUFFER, expected.id);
EXPECT_TRUE(NoCommandsWritten());
}
TEST_F(GLES2ImplementationTest, BindBufferBase) {
struct Cmds {
cmds::GenBuffersImmediate gen;
GLuint id;
cmds::BindBufferBase cmd;
};
Cmds expected;
expected.gen.Init(1, &expected.id);
expected.id = kBuffersStartId;
expected.cmd.Init(GL_TRANSFORM_FEEDBACK_BUFFER, 2, kBuffersStartId);
gl_->GenBuffers(1, &expected.id);
gl_->BindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 2, expected.id);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
}
TEST_F(GLES2ImplementationTest, BindBufferRange) {
struct Cmds {
cmds::GenBuffersImmediate gen;
GLuint id;
cmds::BindBufferRange cmd;
};
Cmds expected;
expected.gen.Init(1, &expected.id);
expected.id = kBuffersStartId;
expected.cmd.Init(GL_TRANSFORM_FEEDBACK_BUFFER, 2, kBuffersStartId, 4, 4);
gl_->GenBuffers(1, &expected.id);
gl_->BindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 2, expected.id, 4, 4);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
}
TEST_F(GLES2ImplementationTest, BindFramebuffer) {
struct Cmds {
cmds::GenFramebuffersImmediate gen;
GLuint id;
cmds::BindFramebuffer cmd;
};
Cmds expected;
expected.gen.Init(1, &expected.id);
expected.id = kFramebuffersStartId;
expected.cmd.Init(GL_FRAMEBUFFER, kFramebuffersStartId);
gl_->GenFramebuffers(1, &expected.id);
gl_->BindFramebuffer(GL_FRAMEBUFFER, expected.id);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
ClearCommands();
gl_->BindFramebuffer(GL_FRAMEBUFFER, expected.id);
EXPECT_TRUE(NoCommandsWritten());
}
TEST_F(GLES2ImplementationTest, BindRenderbuffer) {
struct Cmds {
cmds::GenRenderbuffersImmediate gen;
GLuint id;
cmds::BindRenderbuffer cmd;
};
Cmds expected;
expected.gen.Init(1, &expected.id);
expected.id = kFramebuffersStartId;
expected.cmd.Init(GL_RENDERBUFFER, kFramebuffersStartId);
gl_->GenRenderbuffers(1, &expected.id);
gl_->BindRenderbuffer(GL_RENDERBUFFER, expected.id);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
ClearCommands();
gl_->BindRenderbuffer(GL_RENDERBUFFER, expected.id);
EXPECT_TRUE(NoCommandsWritten());
}
TEST_F(GLES2ImplementationTest, BindSampler) {
struct Cmds {
cmds::GenSamplersImmediate gen;
GLuint id;
cmds::BindSampler cmd;
};
Cmds expected;
expected.gen.Init(1, &expected.id);
expected.id = kSamplersStartId;
expected.cmd.Init(1, kSamplersStartId);
gl_->GenSamplers(1, &expected.id);
gl_->BindSampler(1, expected.id);
UNSAFE_TODO(EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))));
}
#include "gpu/command_buffer/client/gles2_implementation_unittest_autogen.h"
}
}