blob: 4b738a5047321bb43cba524249a11b41c240513d [file] [log] [blame]
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "gpu/command_buffer/common/gles2_cmd_format.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/command_buffer/common/gl_mock.h"
#include "gpu/command_buffer/common/id_allocator.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h"
#include "gpu/command_buffer/service/cmd_buffer_engine.h"
#include "gpu/command_buffer/service/context_group.h"
#include "gpu/command_buffer/service/program_manager.h"
#include "gpu/command_buffer/service/test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::gfx::MockGLInterface;
using ::testing::_;
using ::testing::DoAll;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::MatcherCast;
using ::testing::Pointee;
using ::testing::Return;
using ::testing::SetArrayArgument;
using ::testing::SetArgumentPointee;
using ::testing::StrEq;
using ::testing::StrictMock;
namespace gpu {
namespace gles2 {
class GLES2DecoderTest : public GLES2DecoderTestBase {
public:
GLES2DecoderTest() { }
protected:
void CheckReadPixelsOutOfRange(
GLint in_read_x, GLint in_read_y,
GLsizei in_read_width, GLsizei in_read_height,
bool init);
};
class GLES2DecoderWithShaderTest : public GLES2DecoderWithShaderTestBase {
public:
GLES2DecoderWithShaderTest()
: GLES2DecoderWithShaderTestBase() {
}
void AddExpectationsForSimulatedAttrib0(
GLsizei num_vertices, GLuint buffer_id) {
EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, kServiceAttrib0BufferId))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, BufferData(GL_ARRAY_BUFFER,
num_vertices * sizeof(GLfloat) * 4,
_, GL_DYNAMIC_DRAW))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, BufferSubData(
GL_ARRAY_BUFFER, 0, num_vertices * sizeof(GLfloat) * 4, _))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, VertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, 0))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, VertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, buffer_id))
.Times(1)
.RetiresOnSaturation();
}
};
TEST_F(GLES2DecoderWithShaderTest, DrawArraysNoAttributesSucceeds) {
SetupTexture();
AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
.Times(1)
.RetiresOnSaturation();
DrawArrays cmd;
cmd.Init(GL_TRIANGLES, 0, kNumVertices);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawArraysBadTextureUsesBlack) {
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
// This is an NPOT texture. As the default filtering requires mips
// this should trigger replacing with black textures before rendering.
DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
0, 0);
AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
{
InSequence sequence;
EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, BindTexture(
GL_TEXTURE_2D, TestHelper::kServiceBlackTexture2dId))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0))
.Times(1)
.RetiresOnSaturation();
}
DrawArrays cmd;
cmd.Init(GL_TRIANGLES, 0, kNumVertices);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawArraysMissingAttributesFails) {
DoEnableVertexAttribArray(1);
EXPECT_CALL(*gl_, DrawArrays(_, _, _))
.Times(0);
DrawArrays cmd;
cmd.Init(GL_TRIANGLES, 0, kNumVertices);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest,
DrawArraysMissingAttributesZeroCountSucceeds) {
DoEnableVertexAttribArray(1);
EXPECT_CALL(*gl_, DrawArrays(_, _, _))
.Times(0);
DrawArrays cmd;
cmd.Init(GL_TRIANGLES, 0, 0);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawArraysValidAttributesSucceeds) {
SetupTexture();
SetupVertexBuffer();
DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId);
EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
.Times(1)
.RetiresOnSaturation();
DrawArrays cmd;
cmd.Init(GL_TRIANGLES, 0, kNumVertices);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawArraysDeletedBufferFails) {
SetupVertexBuffer();
DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
DeleteVertexBuffer();
EXPECT_CALL(*gl_, DrawArrays(_, _, _))
.Times(0);
DrawArrays cmd;
cmd.Init(GL_TRIANGLES, 0, kNumVertices);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawArraysDeletedProgramSucceeds) {
SetupTexture();
AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
DoDeleteProgram(client_program_id_, kServiceProgramId);
EXPECT_CALL(*gl_, DrawArrays(_, _, _))
.Times(1)
.RetiresOnSaturation();
DrawArrays cmd;
cmd.Init(GL_TRIANGLES, 0, kNumVertices);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawArraysWithInvalidModeFails) {
SetupVertexBuffer();
DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
EXPECT_CALL(*gl_, DrawArrays(_, _, _))
.Times(0);
DrawArrays cmd;
cmd.Init(GL_QUADS, 0, 1);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
cmd.Init(GL_POLYGON, 0, 1);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawArraysInvalidCountFails) {
SetupVertexBuffer();
DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
// Try start > 0
EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0);
DrawArrays cmd;
cmd.Init(GL_TRIANGLES, 1, kNumVertices);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
EXPECT_EQ(GL_NO_ERROR, GetGLError());
// Try with count > size
cmd.Init(GL_TRIANGLES, 0, kNumVertices + 1);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
EXPECT_EQ(GL_NO_ERROR, GetGLError());
// Try with attrib offset > 0
cmd.Init(GL_TRIANGLES, 0, kNumVertices);
DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 4);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
EXPECT_EQ(GL_NO_ERROR, GetGLError());
// Try with size > 2 (ie, vec3 instead of vec2)
DoVertexAttribPointer(1, 3, GL_FLOAT, 0, 0);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
EXPECT_EQ(GL_NO_ERROR, GetGLError());
// Try with stride > 8 (vec2 + vec2 byte)
DoVertexAttribPointer(1, 2, GL_FLOAT, sizeof(GLfloat) * 3, 0);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawElementsNoAttributesSucceeds) {
SetupTexture();
SetupIndexBuffer();
AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0);
EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount,
GL_UNSIGNED_SHORT,
BufferOffset(kValidIndexRangeStart * 2)))
.Times(1)
.RetiresOnSaturation();
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawElementsMissingAttributesFails) {
SetupIndexBuffer();
DoEnableVertexAttribArray(1);
EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
.Times(0);
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest,
DrawElementsMissingAttributesZeroCountSucceeds) {
SetupIndexBuffer();
DoEnableVertexAttribArray(1);
EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
.Times(0);
DrawElements cmd;
cmd.Init(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawElementsExtraAttributesFails) {
SetupIndexBuffer();
DoEnableVertexAttribArray(6);
EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
.Times(0);
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawElementsValidAttributesSucceeds) {
SetupTexture();
SetupVertexBuffer();
SetupIndexBuffer();
DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, kServiceBufferId);
EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount,
GL_UNSIGNED_SHORT,
BufferOffset(kValidIndexRangeStart * 2)))
.Times(1)
.RetiresOnSaturation();
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawElementsDeletedBufferFails) {
SetupVertexBuffer();
SetupIndexBuffer();
DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
DeleteIndexBuffer();
EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
.Times(0);
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawElementsDeletedProgramSucceeds) {
SetupTexture();
SetupIndexBuffer();
AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0);
DoDeleteProgram(client_program_id_, kServiceProgramId);
EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
.Times(1);
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawElementsWithInvalidModeFails) {
SetupVertexBuffer();
SetupIndexBuffer();
DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
.Times(0);
DrawElements cmd;
cmd.Init(GL_QUADS, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
cmd.Init(GL_POLYGON, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
kValidIndexRangeStart);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawElementsInvalidCountFails) {
SetupVertexBuffer();
SetupIndexBuffer();
DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
// Try start > 0
EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kNumIndices, GL_UNSIGNED_SHORT, 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
EXPECT_EQ(GL_NO_ERROR, GetGLError());
// Try with count > size
cmd.Init(GL_TRIANGLES, kNumIndices + 1, GL_UNSIGNED_SHORT, 0);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawElementsOutOfRangeIndicesFails) {
SetupVertexBuffer();
SetupIndexBuffer();
DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kInvalidIndexRangeCount, GL_UNSIGNED_SHORT,
kInvalidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, DrawElementsOddOffsetForUint16Fails) {
SetupVertexBuffer();
SetupIndexBuffer();
DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kInvalidIndexRangeCount, GL_UNSIGNED_SHORT, 1);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, GetVertexAttribPointervSucceeds) {
const float dummy = 0;
const GLuint kOffsetToTestFor = sizeof(dummy) * 4;
const GLuint kIndexToTest = 1;
GetVertexAttribPointerv::Result* result =
static_cast<GetVertexAttribPointerv::Result*>(shared_memory_address_);
result->size = 0;
const GLuint* result_value = result->GetData();
// Test that initial value is 0.
GetVertexAttribPointerv cmd;
cmd.Init(kIndexToTest, GL_VERTEX_ATTRIB_ARRAY_POINTER,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(sizeof(*result_value), result->size);
EXPECT_EQ(0u, *result_value);
EXPECT_EQ(GL_NO_ERROR, GetGLError());
// Set the value and see that we get it.
SetupVertexBuffer();
DoVertexAttribPointer(kIndexToTest, 2, GL_FLOAT, 0, kOffsetToTestFor);
result->size = 0;
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(sizeof(*result_value), result->size);
EXPECT_EQ(kOffsetToTestFor, *result_value);
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, GetVertexAttribPointervBadArgsFails) {
const GLuint kIndexToTest = 1;
GetVertexAttribPointerv::Result* result =
static_cast<GetVertexAttribPointerv::Result*>(shared_memory_address_);
result->size = 0;
const GLuint* result_value = result->GetData();
// Test pname invalid fails.
GetVertexAttribPointerv cmd;
cmd.Init(kIndexToTest, GL_VERTEX_ATTRIB_ARRAY_POINTER + 1,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0u, result->size);
EXPECT_EQ(kInitialResult, *result_value);
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
// Test index out of range fails.
result->size = 0;
cmd.Init(kNumVertexAttribs, GL_VERTEX_ATTRIB_ARRAY_POINTER,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0u, result->size);
EXPECT_EQ(kInitialResult, *result_value);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
// Test memory id bad fails.
cmd.Init(kIndexToTest, GL_VERTEX_ATTRIB_ARRAY_POINTER,
kInvalidSharedMemoryId, shared_memory_offset_);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
// Test memory offset bad fails.
cmd.Init(kIndexToTest, GL_VERTEX_ATTRIB_ARRAY_POINTER,
shared_memory_id_, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformivSucceeds) {
GetUniformiv::Result* result =
static_cast<GetUniformiv::Result*>(shared_memory_address_);
result->size = 0;
GetUniformiv cmd;
cmd.Init(client_program_id_, kUniform2Location,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_CALL(*gl_, GetUniformiv(kServiceProgramId, kUniform2Location, _))
.Times(1);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GLES2Util::GetGLDataTypeSizeForUniforms(kUniform2Type),
result->size);
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformivArrayElementSucceeds) {
GetUniformiv::Result* result =
static_cast<GetUniformiv::Result*>(shared_memory_address_);
result->size = 0;
GetUniformiv cmd;
cmd.Init(client_program_id_, kUniform2ElementLocation,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_CALL(*gl_,
GetUniformiv(kServiceProgramId, kUniform2ElementLocation, _))
.Times(1);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GLES2Util::GetGLDataTypeSizeForUniforms(kUniform2Type),
result->size);
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformivBadProgramFails) {
GetUniformiv::Result* result =
static_cast<GetUniformiv::Result*>(shared_memory_address_);
result->size = 0;
GetUniformiv cmd;
// non-existant program
cmd.Init(kInvalidClientId, kUniform2Location,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_CALL(*gl_, GetUniformiv(_, _, _))
.Times(0);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0U, result->size);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
// Valid id that is not a program. The GL spec requires a different error for
// this case.
#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
result->size = kInitialResult;
cmd.Init(client_shader_id_, kUniform2Location,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0U, result->size);
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
// Unlinked program
EXPECT_CALL(*gl_, CreateProgram())
.Times(1)
.WillOnce(Return(kNewServiceId))
.RetiresOnSaturation();
CreateProgram cmd2;
cmd2.Init(kNewClientId);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
result->size = kInitialResult;
cmd.Init(kNewClientId, kUniform2Location,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0U, result->size);
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformivBadLocationFails) {
GetUniformiv::Result* result =
static_cast<GetUniformiv::Result*>(shared_memory_address_);
result->size = 0;
GetUniformiv cmd;
// invalid location
cmd.Init(client_program_id_, kInvalidUniformLocation,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_CALL(*gl_, GetUniformiv(_, _, _))
.Times(0);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0U, result->size);
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformivBadSharedMemoryFails) {
GetUniformiv cmd;
cmd.Init(client_program_id_, kUniform2Location,
kInvalidSharedMemoryId, kSharedMemoryOffset);
EXPECT_CALL(*gl_, GetUniformiv(_, _, _))
.Times(0);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(client_program_id_, kUniform2Location,
kSharedMemoryId, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
};
TEST_F(GLES2DecoderWithShaderTest, GetUniformfvSucceeds) {
GetUniformfv::Result* result =
static_cast<GetUniformfv::Result*>(shared_memory_address_);
result->size = 0;
GetUniformfv cmd;
cmd.Init(client_program_id_, kUniform2Location,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_CALL(*gl_, GetUniformfv(kServiceProgramId, kUniform2Location, _))
.Times(1);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GLES2Util::GetGLDataTypeSizeForUniforms(kUniform2Type),
result->size);
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformfvArrayElementSucceeds) {
GetUniformfv::Result* result =
static_cast<GetUniformfv::Result*>(shared_memory_address_);
result->size = 0;
GetUniformfv cmd;
cmd.Init(client_program_id_, kUniform2ElementLocation,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_CALL(*gl_,
GetUniformfv(kServiceProgramId, kUniform2ElementLocation, _))
.Times(1);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GLES2Util::GetGLDataTypeSizeForUniforms(kUniform2Type),
result->size);
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformfvBadProgramFails) {
GetUniformfv::Result* result =
static_cast<GetUniformfv::Result*>(shared_memory_address_);
result->size = 0;
GetUniformfv cmd;
// non-existant program
cmd.Init(kInvalidClientId, kUniform2Location,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_CALL(*gl_, GetUniformfv(_, _, _))
.Times(0);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0U, result->size);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
// Valid id that is not a program. The GL spec requires a different error for
// this case.
#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
result->size = kInitialResult;
cmd.Init(client_shader_id_, kUniform2Location,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0U, result->size);
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
// Unlinked program
EXPECT_CALL(*gl_, CreateProgram())
.Times(1)
.WillOnce(Return(kNewServiceId))
.RetiresOnSaturation();
CreateProgram cmd2;
cmd2.Init(kNewClientId);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
result->size = kInitialResult;
cmd.Init(kNewClientId, kUniform2Location,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0U, result->size);
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformfvBadLocationFails) {
GetUniformfv::Result* result =
static_cast<GetUniformfv::Result*>(shared_memory_address_);
result->size = 0;
GetUniformfv cmd;
// invalid location
cmd.Init(client_program_id_, kInvalidUniformLocation,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_CALL(*gl_, GetUniformfv(_, _, _))
.Times(0);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0U, result->size);
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformfvBadSharedMemoryFails) {
GetUniformfv cmd;
cmd.Init(client_program_id_, kUniform2Location,
kInvalidSharedMemoryId, kSharedMemoryOffset);
EXPECT_CALL(*gl_, GetUniformfv(_, _, _))
.Times(0);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(client_program_id_, kUniform2Location,
kSharedMemoryId, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
};
TEST_F(GLES2DecoderWithShaderTest, GetAttachedShadersSucceeds) {
GetAttachedShaders cmd;
typedef GetAttachedShaders::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->size = 0;
EXPECT_CALL(*gl_, GetAttachedShaders(kServiceProgramId, 1, _, _))
.WillOnce(DoAll(SetArgumentPointee<2>(1),
SetArgumentPointee<3>(kServiceShaderId)));
cmd.Init(client_program_id_, shared_memory_id_, shared_memory_offset_,
Result::ComputeSize(1));
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(1, result->GetNumResults());
EXPECT_EQ(client_shader_id_, result->GetData()[0]);
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, GetAttachedShadersResultNotInitFail) {
GetAttachedShaders cmd;
typedef GetAttachedShaders::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->size = 1;
EXPECT_CALL(*gl_, GetAttachedShaders(_, _, _, _))
.Times(0);
cmd.Init(client_program_id_, shared_memory_id_, shared_memory_offset_,
Result::ComputeSize(1));
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, GetAttachedShadersBadProgramFails) {
GetAttachedShaders cmd;
typedef GetAttachedShaders::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->size = 0;
EXPECT_CALL(*gl_, GetAttachedShaders(_, _, _, _))
.Times(0);
cmd.Init(kInvalidClientId, shared_memory_id_, shared_memory_offset_,
Result::ComputeSize(1));
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0U, result->size);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, GetAttachedShadersBadSharedMemoryFails) {
GetAttachedShaders cmd;
typedef GetAttachedShaders::Result Result;
cmd.Init(client_program_id_, kInvalidSharedMemoryId, shared_memory_offset_,
Result::ComputeSize(1));
EXPECT_CALL(*gl_, GetAttachedShaders(_, _, _, _))
.Times(0);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(client_program_id_, shared_memory_id_, kInvalidSharedMemoryOffset,
Result::ComputeSize(1));
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, GetShaderPrecisionFormatSucceeds) {
GetShaderPrecisionFormat cmd;
typedef GetShaderPrecisionFormat::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->success = 0;
// NOTE: GL will not be called. There is no equivalent Desktop OpenGL
// function.
cmd.Init(GL_VERTEX_SHADER, GL_HIGH_FLOAT,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_NE(0, result->success);
EXPECT_EQ(-62, result->min_range);
EXPECT_EQ(62, result->max_range);
EXPECT_EQ(-16, result->precision);
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, GetShaderPrecisionFormatResultNotInitFails) {
GetShaderPrecisionFormat cmd;
typedef GetShaderPrecisionFormat::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->success = 1;
// NOTE: GL will not be called. There is no equivalent Desktop OpenGL
// function.
cmd.Init(GL_VERTEX_SHADER, GL_HIGH_FLOAT,
shared_memory_id_, shared_memory_offset_);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, GetShaderPrecisionFormatBadArgsFails) {
typedef GetShaderPrecisionFormat::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->success = 0;
GetShaderPrecisionFormat cmd;
cmd.Init(GL_TEXTURE_2D, GL_HIGH_FLOAT,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
result->success = 0;
cmd.Init(GL_VERTEX_SHADER, GL_TEXTURE_2D,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest,
GetShaderPrecisionFormatBadSharedMemoryFails) {
GetShaderPrecisionFormat cmd;
cmd.Init(GL_VERTEX_SHADER, GL_HIGH_FLOAT,
kInvalidSharedMemoryId, shared_memory_offset_);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(GL_VERTEX_SHADER, GL_TEXTURE_2D,
shared_memory_id_, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformSucceeds) {
const GLuint kUniformIndex = 1;
const uint32 kBucketId = 123;
GetActiveUniform cmd;
typedef GetActiveUniform::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->success = 0;
cmd.Init(client_program_id_, kUniformIndex, kBucketId,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_NE(0, result->success);
EXPECT_EQ(kUniform2Size, result->size);
EXPECT_EQ(kUniform2Type, result->type);
EXPECT_EQ(GL_NO_ERROR, GetGLError());
CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
ASSERT_TRUE(bucket != NULL);
EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kUniform2Name,
bucket->size()));
}
TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformResultNotInitFails) {
const GLuint kUniformIndex = 1;
const uint32 kBucketId = 123;
GetActiveUniform cmd;
typedef GetActiveUniform::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->success = 1;
cmd.Init(client_program_id_, kUniformIndex, kBucketId,
shared_memory_id_, shared_memory_offset_);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformBadProgramFails) {
const GLuint kUniformIndex = 1;
const uint32 kBucketId = 123;
GetActiveUniform cmd;
typedef GetActiveUniform::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->success = 0;
cmd.Init(kInvalidClientId, kUniformIndex, kBucketId,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0, result->success);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
result->success = 0;
cmd.Init(client_shader_id_, kUniformIndex, kBucketId,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0, result->success);
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
}
TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformBadIndexFails) {
const uint32 kBucketId = 123;
GetActiveUniform cmd;
typedef GetActiveUniform::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->success = 0;
cmd.Init(client_program_id_, kBadUniformIndex, kBucketId,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0, result->success);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformBadSharedMemoryFails) {
const GLuint kUniformIndex = 1;
const uint32 kBucketId = 123;
GetActiveUniform cmd;
typedef GetActiveUniform::Result Result;
cmd.Init(client_program_id_, kUniformIndex, kBucketId,
kInvalidSharedMemoryId, shared_memory_offset_);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(client_program_id_, kUniformIndex, kBucketId,
shared_memory_id_, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribSucceeds) {
const GLuint kAttribIndex = 1;
const uint32 kBucketId = 123;
GetActiveAttrib cmd;
typedef GetActiveAttrib::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->success = 0;
cmd.Init(client_program_id_, kAttribIndex, kBucketId,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_NE(0, result->success);
EXPECT_EQ(kAttrib2Size, result->size);
EXPECT_EQ(kAttrib2Type, result->type);
EXPECT_EQ(GL_NO_ERROR, GetGLError());
CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
ASSERT_TRUE(bucket != NULL);
EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kAttrib2Name,
bucket->size()));
}
TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribResultNotInitFails) {
const GLuint kAttribIndex = 1;
const uint32 kBucketId = 123;
GetActiveAttrib cmd;
typedef GetActiveAttrib::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->success = 1;
cmd.Init(client_program_id_, kAttribIndex, kBucketId,
shared_memory_id_, shared_memory_offset_);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribBadProgramFails) {
const GLuint kAttribIndex = 1;
const uint32 kBucketId = 123;
GetActiveAttrib cmd;
typedef GetActiveAttrib::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->success = 0;
cmd.Init(kInvalidClientId, kAttribIndex, kBucketId,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0, result->success);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
result->success = 0;
cmd.Init(client_shader_id_, kAttribIndex, kBucketId,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0, result->success);
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
}
TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribBadIndexFails) {
const uint32 kBucketId = 123;
GetActiveAttrib cmd;
typedef GetActiveAttrib::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
result->success = 0;
cmd.Init(client_program_id_, kBadAttribIndex, kBucketId,
shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(0, result->success);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribBadSharedMemoryFails) {
const GLuint kAttribIndex = 1;
const uint32 kBucketId = 123;
GetActiveAttrib cmd;
typedef GetActiveAttrib::Result Result;
cmd.Init(client_program_id_, kAttribIndex, kBucketId,
kInvalidSharedMemoryId, shared_memory_offset_);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(client_program_id_, kAttribIndex, kBucketId,
shared_memory_id_, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, GetShaderInfoLogValidArgs) {
const char* kInfo = "hello";
const uint32 kBucketId = 123;
CompileShader compile_cmd;
GetShaderInfoLog cmd;
EXPECT_CALL(*gl_, ShaderSource(kServiceShaderId, 1, _, _));
EXPECT_CALL(*gl_, CompileShader(kServiceShaderId));
EXPECT_CALL(*gl_, GetShaderiv(kServiceShaderId, GL_COMPILE_STATUS, _))
.WillOnce(SetArgumentPointee<2>(GL_FALSE))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetShaderiv(kServiceShaderId, GL_INFO_LOG_LENGTH, _))
.WillOnce(SetArgumentPointee<2>(strlen(kInfo) + 1))
.RetiresOnSaturation();
EXPECT_CALL(
*gl_, GetShaderInfoLog(kServiceShaderId, strlen(kInfo) + 1, _, _))
.WillOnce(DoAll(SetArgumentPointee<2>(strlen(kInfo)),
SetArrayArgument<3>(kInfo, kInfo + strlen(kInfo) + 1)));
compile_cmd.Init(client_shader_id_);
cmd.Init(client_shader_id_, kBucketId);
EXPECT_EQ(error::kNoError, ExecuteCmd(compile_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
ASSERT_TRUE(bucket != NULL);
EXPECT_EQ(strlen(kInfo) + 1, bucket->size());
EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kInfo,
bucket->size()));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, GetShaderInfoLogInvalidArgs) {
const uint32 kBucketId = 123;
GetShaderInfoLog cmd;
cmd.Init(kInvalidClientId, kBucketId);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
}
TEST_F(GLES2DecoderTest, CompileShaderValidArgs) {
EXPECT_CALL(*gl_, ShaderSource(kServiceShaderId, 1, _, _));
EXPECT_CALL(*gl_, CompileShader(kServiceShaderId));
EXPECT_CALL(*gl_, GetShaderiv(kServiceShaderId, GL_COMPILE_STATUS, _))
.WillOnce(SetArgumentPointee<2>(GL_TRUE))
.RetiresOnSaturation();
CompileShader cmd;
cmd.Init(client_shader_id_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, CompileShaderInvalidArgs) {
CompileShader cmd;
cmd.Init(kInvalidClientId);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
cmd.Init(client_program_id_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
}
TEST_F(GLES2DecoderTest, ShaderSourceAndGetShaderSourceValidArgs) {
const uint32 kBucketId = 123;
const char kSource[] = "hello";
const uint32 kSourceSize = sizeof(kSource) - 1;
memcpy(shared_memory_address_, kSource, kSourceSize);
ShaderSource cmd;
cmd.Init(client_shader_id_,
kSharedMemoryId, kSharedMemoryOffset, kSourceSize);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
memset(shared_memory_address_, 0, kSourceSize);
GetShaderSource get_cmd;
get_cmd.Init(client_shader_id_, kBucketId);
EXPECT_EQ(error::kNoError, ExecuteCmd(get_cmd));
CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
ASSERT_TRUE(bucket != NULL);
EXPECT_EQ(kSourceSize + 1, bucket->size());
EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kSource,
bucket->size()));
}
TEST_F(GLES2DecoderTest, ShaderSourceInvalidArgs) {
const char kSource[] = "hello";
const uint32 kSourceSize = sizeof(kSource) - 1;
memcpy(shared_memory_address_, kSource, kSourceSize);
ShaderSource cmd;
cmd.Init(kInvalidClientId,
kSharedMemoryId, kSharedMemoryOffset, kSourceSize);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
cmd.Init(client_program_id_,
kSharedMemoryId, kSharedMemoryOffset, kSourceSize);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
cmd.Init(client_shader_id_,
kInvalidSharedMemoryId, kSharedMemoryOffset, kSourceSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(client_shader_id_,
kSharedMemoryId, kInvalidSharedMemoryOffset, kSourceSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(client_shader_id_,
kSharedMemoryId, kSharedMemoryOffset, kSharedBufferSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, ShaderSourceImmediateAndGetShaderSourceValidArgs) {
const uint32 kBucketId = 123;
const char kSource[] = "hello";
const uint32 kSourceSize = sizeof(kSource) - 1;
ShaderSourceImmediate& cmd = *GetImmediateAs<ShaderSourceImmediate>();
cmd.Init(client_shader_id_, kSourceSize);
memcpy(GetImmediateDataAs<void*>(&cmd), kSource, kSourceSize);
EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kSourceSize));
memset(shared_memory_address_, 0, kSourceSize);
// TODO(gman): GetShaderSource has to change format so result is always set.
GetShaderSource get_cmd;
get_cmd.Init(client_shader_id_, kBucketId);
EXPECT_EQ(error::kNoError, ExecuteCmd(get_cmd));
CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
ASSERT_TRUE(bucket != NULL);
EXPECT_EQ(kSourceSize + 1, bucket->size());
EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kSource,
bucket->size()));
}
TEST_F(GLES2DecoderTest, ShaderSourceImmediateInvalidArgs) {
const char kSource[] = "hello";
const uint32 kSourceSize = sizeof(kSource) - 1;
ShaderSourceImmediate& cmd = *GetImmediateAs<ShaderSourceImmediate>();
cmd.Init(kInvalidClientId, kSourceSize);
memcpy(GetImmediateDataAs<void*>(&cmd), kSource, kSourceSize);
EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kSourceSize));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
cmd.Init(client_program_id_, kSourceSize);
EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kSourceSize));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
}
TEST_F(GLES2DecoderTest, ShaderSourceBucketAndGetShaderSourceValidArgs) {
const uint32 kInBucketId = 123;
const uint32 kOutBucketId = 125;
const char kSource[] = "hello";
const uint32 kSourceSize = sizeof(kSource) - 1;
SetBucketAsCString(kInBucketId, kSource);
ShaderSourceBucket cmd;
cmd.Init(client_shader_id_, kInBucketId);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
ClearSharedMemory();
GetShaderSource get_cmd;
get_cmd.Init(client_shader_id_, kOutBucketId);
EXPECT_EQ(error::kNoError, ExecuteCmd(get_cmd));
CommonDecoder::Bucket* bucket = decoder_->GetBucket(kOutBucketId);
ASSERT_TRUE(bucket != NULL);
EXPECT_EQ(kSourceSize + 1, bucket->size());
EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kSource,
bucket->size()));
}
TEST_F(GLES2DecoderTest, ShaderSourceBucketInvalidArgs) {
const uint32 kBucketId = 123;
const char kSource[] = "hello";
const uint32 kSourceSize = sizeof(kSource) - 1;
memcpy(shared_memory_address_, kSource, kSourceSize);
ShaderSourceBucket cmd;
// Test no bucket.
cmd.Init(client_texture_id_, kBucketId);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
// Test invalid client.
SetBucketAsCString(kBucketId, kSource);
cmd.Init(kInvalidClientId, kBucketId);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
}
TEST_F(GLES2DecoderTest, GenerateMipmapWrongFormatsFails) {
EXPECT_CALL(*gl_, GenerateMipmapEXT(_))
.Times(0);
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
DoTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA, 16, 17, 0, GL_RGBA, GL_UNSIGNED_BYTE,
0, 0);
GenerateMipmap cmd;
cmd.Init(GL_TEXTURE_2D);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, Uniform1iValidArgs) {
EXPECT_CALL(*gl_, Uniform1i(kUniform1Location, 2));
SpecializedSetup<Uniform1i, 0>(true);
Uniform1i cmd;
cmd.Init(kUniform1Location, 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, Uniform1ivValidArgs) {
EXPECT_CALL(
*gl_, Uniform1iv(
kUniform1Location, 2,
reinterpret_cast<const GLint*>(shared_memory_address_)));
SpecializedSetup<Uniform1iv, 0>(true);
Uniform1iv cmd;
cmd.Init(kUniform1Location, 2, shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, Uniform1ivInvalidArgs2_0) {
EXPECT_CALL(*gl_, Uniform1iv(_, _, _)).Times(0);
SpecializedSetup<Uniform1iv, 0>(false);
Uniform1iv cmd;
cmd.Init(kUniform1Location, 2, kInvalidSharedMemoryId, 0);
EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, Uniform1ivInvalidArgs2_1) {
EXPECT_CALL(*gl_, Uniform1iv(_, _, _)).Times(0);
SpecializedSetup<Uniform1iv, 0>(false);
Uniform1iv cmd;
cmd.Init(kUniform1Location, 2, shared_memory_id_, kInvalidSharedMemoryOffset);
EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, Uniform1ivImmediateValidArgs) {
Uniform1ivImmediate& cmd = *GetImmediateAs<Uniform1ivImmediate>();
EXPECT_CALL(
*gl_,
Uniform1iv(kUniform1Location, 2,
reinterpret_cast<GLint*>(ImmediateDataAddress(&cmd))));
SpecializedSetup<Uniform1ivImmediate, 0>(true);
GLint temp[1 * 2] = { 0, };
cmd.Init(kUniform1Location, 2, &temp[0]);
EXPECT_EQ(error::kNoError,
ExecuteImmediateCmd(cmd, sizeof(temp)));
}
TEST_F(GLES2DecoderWithShaderTest, BindBufferToDifferentTargetFails) {
// Bind the buffer to GL_ARRAY_BUFFER
DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
// Attempt to rebind to GL_ELEMENT_ARRAY_BUFFER
// NOTE: Real GLES2 does not have this restriction but WebGL and we do.
// This can be restriction can be removed at runtime.
EXPECT_CALL(*gl_, BindBuffer(_, _))
.Times(0);
BindBuffer cmd;
cmd.Init(GL_ELEMENT_ARRAY_BUFFER, client_buffer_id_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderTest, ActiveTextureValidArgs) {
EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE1));
SpecializedSetup<ActiveTexture, 0>(true);
ActiveTexture cmd;
cmd.Init(GL_TEXTURE1);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderTest, ActiveTextureInvalidArgs) {
EXPECT_CALL(*gl_, ActiveTexture(_)).Times(0);
SpecializedSetup<ActiveTexture, 0>(false);
ActiveTexture cmd;
cmd.Init(GL_TEXTURE0 - 1);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
cmd.Init(kNumTextureUnits);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
}
TEST_F(GLES2DecoderTest, CheckFramebufferStatusWithNoBoundTarget) {
EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(_))
.Times(0);
CheckFramebufferStatus::Result* result =
static_cast<CheckFramebufferStatus::Result*>(shared_memory_address_);
*result = 0;
CheckFramebufferStatus cmd;
cmd.Init(GL_FRAMEBUFFER, shared_memory_id_, shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), *result);
}
TEST_F(GLES2DecoderTest, FramebufferRenderbufferWithNoBoundTarget) {
EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(_, _, _, _))
.Times(0);
FramebufferRenderbuffer cmd;
cmd.Init(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
client_renderbuffer_id_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderTest, FramebufferTexture2DWithNoBoundTarget) {
EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _))
.Times(0);
FramebufferTexture2D cmd;
cmd.Init(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, client_texture_id_,
0);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithNoBoundTarget) {
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetFramebufferAttachmentParameterivEXT(_, _, _, _))
.Times(0);
GetFramebufferAttachmentParameteriv cmd;
cmd.Init(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, shared_memory_id_,
shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithRenderbuffer) {
DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
kServiceFramebufferId);
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
kServiceRenderbufferId))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
SetupExpectationsForFramebufferAttachment(
GL_COLOR_BUFFER_BIT, // clear bits
0, 0, 0, 0, // color
0x1111, // color bits
0, // stencil
-1, // stencil mask back,
-1, // stencil mask front,
1.0f, // depth
1, // depth mask
false); // scissor test
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, _))
.WillOnce(SetArgumentPointee<3>(kServiceRenderbufferId))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, _))
.WillOnce(SetArgumentPointee<3>(GL_RENDERBUFFER))
.RetiresOnSaturation();
GetFramebufferAttachmentParameteriv::Result* result =
static_cast<GetFramebufferAttachmentParameteriv::Result*>(
shared_memory_address_);
result->size = 0;
const GLint* result_value = result->GetData();
FramebufferRenderbuffer fbrb_cmd;
GetFramebufferAttachmentParameteriv cmd;
fbrb_cmd.Init(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
client_renderbuffer_id_);
cmd.Init(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, shared_memory_id_,
shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(fbrb_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
EXPECT_EQ(static_cast<GLuint>(*result_value), client_renderbuffer_id_);
}
TEST_F(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithTexture) {
DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
kServiceFramebufferId);
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, FramebufferTexture2DEXT(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
kServiceTextureId, 0))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
SetupExpectationsForFramebufferAttachment(
0, // clear bits
0, 0, 0, 0, // color
0x1111, // color bits
0, // stencil
-1, // stencil mask back,
-1, // stencil mask front,
1.0f, // depth
1, // depth mask
false); // scissor test
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, _))
.WillOnce(SetArgumentPointee<3>(kServiceTextureId))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, _))
.WillOnce(SetArgumentPointee<3>(GL_TEXTURE))
.RetiresOnSaturation();
GetFramebufferAttachmentParameteriv::Result* result =
static_cast<GetFramebufferAttachmentParameteriv::Result*>(
shared_memory_address_);
result->SetNumResults(0);
const GLint* result_value = result->GetData();
FramebufferTexture2D fbtex_cmd;
GetFramebufferAttachmentParameteriv cmd;
fbtex_cmd.Init(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, client_texture_id_,
0);
cmd.Init(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, shared_memory_id_,
shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(fbtex_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
EXPECT_EQ(static_cast<GLuint>(*result_value), client_texture_id_);
}
TEST_F(GLES2DecoderTest, GetRenderbufferParameterivWithNoBoundTarget) {
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetRenderbufferParameterivEXT(_, _, _))
.Times(0);
GetRenderbufferParameteriv cmd;
cmd.Init(
GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, shared_memory_id_,
shared_memory_offset_);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
TEST_F(GLES2DecoderTest, RenderbufferStorageWithNoBoundTarget) {
EXPECT_CALL(*gl_, RenderbufferStorageEXT(_, _, _, _))
.Times(0);
RenderbufferStorage cmd;
cmd.Init(GL_RENDERBUFFER, GL_RGBA4, 3, 4);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
namespace {
// A class to emulate glReadPixels
class ReadPixelsEmulator {
public:
// pack_alignment is the alignment you want ReadPixels to use
// when copying. The actual data passed in pixels should be contiguous.
ReadPixelsEmulator(GLsizei width, GLsizei height, GLint bytes_per_pixel,
const void* pixels, GLint pack_alignment)
: width_(width),
height_(height),
pack_alignment_(pack_alignment),
bytes_per_pixel_(bytes_per_pixel),
pixels_(reinterpret_cast<const int8*>(pixels)) {
}
void ReadPixels(
GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type, void* pixels) const {
DCHECK_GE(x, 0);
DCHECK_GE(y, 0);
DCHECK_LE(x + width, width_);
DCHECK_LE(y + height, height_);
for (GLint yy = 0; yy < height; ++yy) {
const int8* src = GetPixelAddress(x, y + yy);
const void* dst = ComputePackAlignmentAddress(0, yy, width, pixels);
memcpy(const_cast<void*>(dst), src, width * bytes_per_pixel_);
}
}
bool CompareRowSegment(
GLint x, GLint y, GLsizei width, const void* data) const {
DCHECK(x + width <= width_ || width == 0);
return memcmp(data, GetPixelAddress(x, y), width * bytes_per_pixel_) == 0;
}
// Helper to compute address of pixel in pack aligned data.
const void* ComputePackAlignmentAddress(
GLint x, GLint y, GLsizei width, const void* address) const {
GLint unpadded_row_size = ComputeImageDataSize(width, 1);
GLint two_rows_size = ComputeImageDataSize(width, 2);
GLsizei padded_row_size = two_rows_size - unpadded_row_size;
GLint offset = y * padded_row_size + x * bytes_per_pixel_;
return static_cast<const int8*>(address) + offset;
}
GLint ComputeImageDataSize(GLint width, GLint height) const {
GLint row_size = width * bytes_per_pixel_;
if (height > 1) {
GLint temp = row_size + pack_alignment_;
GLint padded_row_size = (temp / pack_alignment_) * pack_alignment_;
GLint size_of_all_but_last_row = (height - 1) * padded_row_size;
return size_of_all_but_last_row + row_size;
} else {
return height * row_size;
}
}
private:
const int8* GetPixelAddress(GLint x, GLint y) const {
return pixels_ + (width_ * y + x) * bytes_per_pixel_;
}
GLsizei width_;
GLsizei height_;
GLint pack_alignment_;
GLint bytes_per_pixel_;
const int8* pixels_;
};
} // anonymous namespace
void GLES2DecoderTest::CheckReadPixelsOutOfRange(
GLint in_read_x, GLint in_read_y,
GLsizei in_read_width, GLsizei in_read_height,
bool init) {
const GLsizei kWidth = 5;
const GLsizei kHeight = 3;
const GLint kBytesPerPixel = 3;
const GLint kPackAlignment = 4;
const GLenum kFormat = GL_RGB;
static const int8 kSrcPixels[kWidth * kHeight * kBytesPerPixel] = {
12, 13, 14, 18, 19, 18, 19, 12, 13, 14, 18, 19, 18, 19, 13,
29, 28, 23, 22, 21, 22, 21, 29, 28, 23, 22, 21, 22, 21, 28,
31, 34, 39, 37, 32, 37, 32, 31, 34, 39, 37, 32, 37, 32, 34,
};
ClearSharedMemory();
// We need to setup an FBO so we can know the max size that ReadPixels will
// access
if (init) {
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
DoTexImage2D(GL_TEXTURE_2D, 0, kFormat, kWidth, kHeight, 0,
kFormat, GL_UNSIGNED_BYTE, 0, 0);
DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
kServiceFramebufferId);
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, FramebufferTexture2DEXT(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
kServiceTextureId, 0))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
SetupExpectationsForFramebufferAttachment(
0, // clear bits
0, 0, 0, 0, // color
0x1111, // color bits
0, // stencil
-1, // stencil mask back,
-1, // stencil mask front,
1.0f, // depth
1, // depth mask
false); // scissor test
FramebufferTexture2D fbtex_cmd;
fbtex_cmd.Init(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, client_texture_id_,
0);
EXPECT_EQ(error::kNoError, ExecuteCmd(fbtex_cmd));
}
ReadPixelsEmulator emu(
kWidth, kHeight, kBytesPerPixel, kSrcPixels, kPackAlignment);
typedef ReadPixels::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
uint32 result_shm_id = kSharedMemoryId;
uint32 result_shm_offset = kSharedMemoryOffset;
uint32 pixels_shm_id = kSharedMemoryId;
uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result);
void* dest = &result[1];
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
// ReadPixels will be called for valid size only even though the command
// is requesting a larger size.
GLint read_x = std::max(0, in_read_x);
GLint read_y = std::max(0, in_read_y);
GLint read_end_x = std::max(0, std::min(kWidth, in_read_x + in_read_width));
GLint read_end_y = std::max(0, std::min(kHeight, in_read_y + in_read_height));
GLint read_width = read_end_x - read_x;
GLint read_height = read_end_y - read_y;
if (read_width > 0 && read_height > 0) {
for (GLint yy = read_y; yy < read_end_y; ++yy) {
EXPECT_CALL(
*gl_, ReadPixels(read_x, yy, read_width, 1,
kFormat, GL_UNSIGNED_BYTE, _))
.WillOnce(Invoke(&emu, &ReadPixelsEmulator::ReadPixels))
.RetiresOnSaturation();
}
}
ReadPixels cmd;
cmd.Init(in_read_x, in_read_y, in_read_width, in_read_height,
kFormat, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
result_shm_id, result_shm_offset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
GLint unpadded_row_size = emu.ComputeImageDataSize(in_read_width, 1);
scoped_array<int8> zero(new int8[unpadded_row_size]);
scoped_array<int8> pack(new int8[kPackAlignment]);
memset(zero.get(), 0, unpadded_row_size);
memset(pack.get(), kInitialMemoryValue, kPackAlignment);
for (GLint yy = 0; yy < in_read_height; ++yy) {
const int8* row = static_cast<const int8*>(
emu.ComputePackAlignmentAddress(0, yy, in_read_width, dest));
GLint y = in_read_y + yy;
if (y < 0 || y >= kHeight) {
EXPECT_EQ(0, memcmp(zero.get(), row, unpadded_row_size));
} else {
// check off left.
GLint num_left_pixels = std::max(-in_read_x, 0);
GLint num_left_bytes = num_left_pixels * kBytesPerPixel;
EXPECT_EQ(0, memcmp(zero.get(), row, num_left_bytes));
// check off right.
GLint num_right_pixels = std::max(in_read_x + in_read_width - kWidth, 0);
GLint num_right_bytes = num_right_pixels * kBytesPerPixel;
EXPECT_EQ(0, memcmp(zero.get(),
row + unpadded_row_size - num_right_bytes,
num_right_bytes));
// check middle.
GLint x = std::max(in_read_x, 0);
GLint num_middle_pixels =
std::max(in_read_width - num_left_pixels - num_right_pixels, 0);
EXPECT_TRUE(emu.CompareRowSegment(
x, y, num_middle_pixels, row + num_left_bytes));
}
// check padding
if (yy != in_read_height - 1) {
GLint num_padding_bytes =
(kPackAlignment - 1) - (unpadded_row_size % kPackAlignment);
EXPECT_EQ(0,
memcmp(pack.get(), row + unpadded_row_size, num_padding_bytes));
}
}
}
TEST_F(GLES2DecoderTest, ReadPixels) {
const GLsizei kWidth = 5;
const GLsizei kHeight = 3;
const GLint kBytesPerPixel = 3;
const GLint kPackAlignment = 4;
static const int8 kSrcPixels[kWidth * kHeight * kBytesPerPixel] = {
12, 13, 14, 18, 19, 18, 19, 12, 13, 14, 18, 19, 18, 19, 13,
29, 28, 23, 22, 21, 22, 21, 29, 28, 23, 22, 21, 22, 21, 28,
31, 34, 39, 37, 32, 37, 32, 31, 34, 39, 37, 32, 37, 32, 34,
};
context_->SetSize(gfx::Size(INT_MAX, INT_MAX));
ReadPixelsEmulator emu(
kWidth, kHeight, kBytesPerPixel, kSrcPixels, kPackAlignment);
typedef ReadPixels::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
uint32 result_shm_id = kSharedMemoryId;
uint32 result_shm_offset = kSharedMemoryOffset;
uint32 pixels_shm_id = kSharedMemoryId;
uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result);
void* dest = &result[1];
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
EXPECT_CALL(
*gl_, ReadPixels(0, 0, kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, _))
.WillOnce(Invoke(&emu, &ReadPixelsEmulator::ReadPixels));
ReadPixels cmd;
cmd.Init(0, 0, kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
result_shm_id, result_shm_offset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
for (GLint yy = 0; yy < kHeight; ++yy) {
EXPECT_TRUE(emu.CompareRowSegment(
0, yy, kWidth,
emu.ComputePackAlignmentAddress(0, yy, kWidth, dest)));
}
}
TEST_F(GLES2DecoderTest, ReadPixelsOutOfRange) {
static GLint tests[][4] = {
{ -2, -1, 9, 5, }, // out of range on all sides
{ 2, 1, 9, 5, }, // out of range on right, bottom
{ -7, -4, 9, 5, }, // out of range on left, top
{ 0, -5, 9, 5, }, // completely off top
{ 0, 3, 9, 5, }, // completely off bottom
{ -9, 0, 9, 5, }, // completely off left
{ 5, 0, 9, 5, }, // completely off right
};
for (size_t tt = 0; tt < arraysize(tests); ++tt) {
CheckReadPixelsOutOfRange(
tests[tt][0], tests[tt][1], tests[tt][2], tests[tt][3], tt == 0);
}
}
TEST_F(GLES2DecoderTest, ReadPixelsInvalidArgs) {
typedef ReadPixels::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
uint32 result_shm_id = kSharedMemoryId;
uint32 result_shm_offset = kSharedMemoryOffset;
uint32 pixels_shm_id = kSharedMemoryId;
uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result);
EXPECT_CALL(*gl_, ReadPixels(_, _, _, _, _, _, _)).Times(0);
ReadPixels cmd;
cmd.Init(0, 0, -1, 1, GL_RGB, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
result_shm_id, result_shm_offset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(0, 0, 1, -1, GL_RGB, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
result_shm_id, result_shm_offset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(0, 0, 1, 1, GL_RGB, GL_INT,
pixels_shm_id, pixels_shm_offset,
result_shm_id, result_shm_offset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
cmd.Init(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
kInvalidSharedMemoryId, pixels_shm_offset,
result_shm_id, result_shm_offset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
pixels_shm_id, kInvalidSharedMemoryOffset,
result_shm_id, result_shm_offset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
kInvalidSharedMemoryId, result_shm_offset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
pixels_shm_id, pixels_shm_offset,
result_shm_id, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, BindAttribLocation) {
const GLint kLocation = 2;
const char* kName = "testing";
const uint32 kNameSize = strlen(kName);
EXPECT_CALL(
*gl_, BindAttribLocation(kServiceProgramId, kLocation, StrEq(kName)))
.Times(1);
memcpy(shared_memory_address_, kName, kNameSize);
BindAttribLocation cmd;
cmd.Init(client_program_id_, kLocation, kSharedMemoryId, kSharedMemoryOffset,
kNameSize);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, BindAttribLocationInvalidArgs) {
const GLint kLocation = 2;
const char* kName = "testing";
const uint32 kNameSize = strlen(kName);
EXPECT_CALL(*gl_, BindAttribLocation(_, _, _)).Times(0);
BindAttribLocation cmd;
cmd.Init(kInvalidClientId, kLocation,
kSharedMemoryId, kSharedMemoryOffset, kNameSize);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(client_program_id_, kLocation,
kInvalidSharedMemoryId, kSharedMemoryOffset, kNameSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(client_program_id_, kLocation,
kSharedMemoryId, kInvalidSharedMemoryOffset, kNameSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(client_program_id_, kLocation,
kSharedMemoryId, kSharedMemoryOffset, kSharedBufferSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, BindAttribLocationImmediate) {
const GLint kLocation = 2;
const char* kName = "testing";
const uint32 kNameSize = strlen(kName);
EXPECT_CALL(
*gl_, BindAttribLocation(kServiceProgramId, kLocation, StrEq(kName)))
.Times(1);
BindAttribLocationImmediate& cmd =
*GetImmediateAs<BindAttribLocationImmediate>();
cmd.Init(client_program_id_, kLocation, kName, kNameSize);
EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
}
TEST_F(GLES2DecoderTest, BindAttribLocationImmediateInvalidArgs) {
const GLint kLocation = 2;
const char* kName = "testing";
const uint32 kNameSize = strlen(kName);
EXPECT_CALL(*gl_, BindAttribLocation(_, _, _)).Times(0);
BindAttribLocationImmediate& cmd =
*GetImmediateAs<BindAttribLocationImmediate>();
cmd.Init(kInvalidClientId, kLocation, kName, kNameSize);
EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
}
TEST_F(GLES2DecoderTest, BindAttribLocationBucket) {
const uint32 kBucketId = 123;
const GLint kLocation = 2;
const char* kName = "testing";
EXPECT_CALL(
*gl_, BindAttribLocation(kServiceProgramId, kLocation, StrEq(kName)))
.Times(1);
SetBucketAsCString(kBucketId, kName);
BindAttribLocationBucket cmd;
cmd.Init(client_program_id_, kLocation, kBucketId);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, BindAttribLocationBucketInvalidArgs) {
const uint32 kBucketId = 123;
const GLint kLocation = 2;
const char* kName = "testing";
EXPECT_CALL(*gl_, BindAttribLocation(_, _, _)).Times(0);
BindAttribLocationBucket cmd;
// check bucket does not exist.
cmd.Init(client_program_id_, kLocation, kBucketId);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
// check bucket is empty.
SetBucketAsCString(kBucketId, NULL);
cmd.Init(client_program_id_, kLocation, kBucketId);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
// Check bad program id
SetBucketAsCString(kBucketId, kName);
cmd.Init(kInvalidClientId, kLocation, kBucketId);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
}
TEST_F(GLES2DecoderWithShaderTest, GetAttribLocation) {
const uint32 kNameSize = strlen(kAttrib2Name);
const char* kNonExistentName = "foobar";
const uint32 kNonExistentNameSize = strlen(kNonExistentName);
typedef GetAttribLocation::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
*result = -1;
char* name = GetSharedMemoryAsWithOffset<char*>(sizeof(*result));
const uint32 kNameOffset = kSharedMemoryOffset + sizeof(*result);
memcpy(name, kAttrib2Name, kNameSize);
GetAttribLocation cmd;
cmd.Init(client_program_id_,
kSharedMemoryId, kNameOffset,
kSharedMemoryId, kSharedMemoryOffset,
kNameSize);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(kAttrib2Location, *result);
*result = -1;
memcpy(name, kNonExistentName, kNonExistentNameSize);
cmd.Init(client_program_id_,
kSharedMemoryId, kNameOffset,
kSharedMemoryId, kSharedMemoryOffset,
kNonExistentNameSize);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
}
TEST_F(GLES2DecoderWithShaderTest, GetAttribLocationInvalidArgs) {
const uint32 kNameSize = strlen(kAttrib2Name);
typedef GetAttribLocation::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
*result = -1;
char* name = GetSharedMemoryAsWithOffset<char*>(sizeof(*result));
const uint32 kNameOffset = kSharedMemoryOffset + sizeof(*result);
memcpy(name, kAttrib2Name, kNameSize);
GetAttribLocation cmd;
cmd.Init(kInvalidClientId,
kSharedMemoryId, kNameOffset,
kSharedMemoryId, kSharedMemoryOffset,
kNameSize);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
*result = -1;
cmd.Init(client_program_id_,
kInvalidSharedMemoryId, kNameOffset,
kSharedMemoryId, kSharedMemoryOffset,
kNameSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
cmd.Init(client_program_id_,
kSharedMemoryId, kInvalidSharedMemoryOffset,
kSharedMemoryId, kSharedMemoryOffset,
kNameSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
cmd.Init(client_program_id_,
kSharedMemoryId, kNameOffset,
kInvalidSharedMemoryId, kSharedMemoryOffset,
kNameSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
cmd.Init(client_program_id_,
kSharedMemoryId, kNameOffset,
kSharedMemoryId, kInvalidSharedMemoryOffset,
kNameSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
cmd.Init(client_program_id_,
kSharedMemoryId, kNameOffset,
kSharedMemoryId, kSharedMemoryOffset,
kSharedBufferSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
}
TEST_F(GLES2DecoderWithShaderTest, GetAttribLocationImmediate) {
const uint32 kNameSize = strlen(kAttrib2Name);
const char* kNonExistentName = "foobar";
const uint32 kNonExistentNameSize = strlen(kNonExistentName);
typedef GetAttribLocationImmediate::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
*result = -1;
GetAttribLocationImmediate& cmd =
*GetImmediateAs<GetAttribLocationImmediate>();
cmd.Init(client_program_id_, kAttrib2Name,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
EXPECT_EQ(kAttrib2Location, *result);
*result = -1;
cmd.Init(client_program_id_, kNonExistentName,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNonExistentNameSize));
EXPECT_EQ(-1, *result);
}
TEST_F(GLES2DecoderWithShaderTest, GetAttribLocationImmediateInvalidArgs) {
const uint32 kNameSize = strlen(kAttrib2Name);
typedef GetAttribLocationImmediate::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
*result = -1;
GetAttribLocationImmediate& cmd =
*GetImmediateAs<GetAttribLocationImmediate>();
cmd.Init(kInvalidClientId, kAttrib2Name,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
EXPECT_EQ(-1, *result);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
*result = -1;
cmd.Init(client_program_id_, kAttrib2Name,
kInvalidSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
EXPECT_EQ(-1, *result);
cmd.Init(client_program_id_, kAttrib2Name,
kSharedMemoryId, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
EXPECT_EQ(-1, *result);
}
TEST_F(GLES2DecoderWithShaderTest, GetAttribLocationBucket) {
const uint32 kBucketId = 123;
const char* kNonExistentName = "foobar";
typedef GetAttribLocationBucket::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
SetBucketAsCString(kBucketId, kAttrib2Name);
*result = -1;
GetAttribLocationBucket cmd;
cmd.Init(client_program_id_, kBucketId,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(kAttrib2Location, *result);
SetBucketAsCString(kBucketId, kNonExistentName);
*result = -1;
cmd.Init(client_program_id_, kBucketId,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
}
TEST_F(GLES2DecoderWithShaderTest, GetAttribLocationBucketInvalidArgs) {
const uint32 kBucketId = 123;
typedef GetAttribLocationBucket::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
*result = -1;
GetAttribLocationBucket cmd;
// Check no bucket
cmd.Init(client_program_id_, kBucketId,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
// Check bad program id.
SetBucketAsCString(kBucketId, kAttrib2Name);
cmd.Init(kInvalidClientId, kBucketId,
kSharedMemoryId, kSharedMemoryOffset);
*result = -1;
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
// Check bad memory
cmd.Init(client_program_id_, kBucketId,
kInvalidSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(client_program_id_, kBucketId,
kSharedMemoryId, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformLocation) {
const uint32 kNameSize = strlen(kUniform2Name);
const char* kNonExistentName = "foobar";
const uint32 kNonExistentNameSize = strlen(kNonExistentName);
typedef GetUniformLocation::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
*result = -1;
char* name = GetSharedMemoryAsWithOffset<char*>(sizeof(*result));
const uint32 kNameOffset = kSharedMemoryOffset + sizeof(*result);
memcpy(name, kUniform2Name, kNameSize);
GetUniformLocation cmd;
cmd.Init(client_program_id_,
kSharedMemoryId, kNameOffset,
kSharedMemoryId, kSharedMemoryOffset,
kNameSize);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(kUniform2Location, *result);
memcpy(name, kNonExistentName, kNonExistentNameSize);
*result = -1;
cmd.Init(client_program_id_,
kSharedMemoryId, kNameOffset,
kSharedMemoryId, kSharedMemoryOffset,
kNonExistentNameSize);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformLocationInvalidArgs) {
const uint32 kNameSize = strlen(kUniform2Name);
typedef GetUniformLocation::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
*result = -1;
char* name = GetSharedMemoryAsWithOffset<char*>(sizeof(*result));
const uint32 kNameOffset = kSharedMemoryOffset + sizeof(*result);
memcpy(name, kUniform2Name, kNameSize);
GetUniformLocation cmd;
cmd.Init(kInvalidClientId,
kSharedMemoryId, kNameOffset,
kSharedMemoryId, kSharedMemoryOffset,
kNameSize);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
*result = -1;
cmd.Init(client_program_id_,
kInvalidSharedMemoryId, kNameOffset,
kSharedMemoryId, kSharedMemoryOffset,
kNameSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
cmd.Init(client_program_id_,
kSharedMemoryId, kInvalidSharedMemoryOffset,
kSharedMemoryId, kSharedMemoryOffset,
kNameSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
cmd.Init(client_program_id_,
kSharedMemoryId, kNameOffset,
kInvalidSharedMemoryId, kSharedMemoryOffset,
kNameSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
cmd.Init(client_program_id_,
kSharedMemoryId, kNameOffset,
kSharedMemoryId, kInvalidSharedMemoryOffset,
kNameSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
cmd.Init(client_program_id_,
kSharedMemoryId, kNameOffset,
kSharedMemoryId, kSharedMemoryOffset,
kSharedBufferSize);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformLocationImmediate) {
const uint32 kNameSize = strlen(kUniform2Name);
const char* kNonExistentName = "foobar";
const uint32 kNonExistentNameSize = strlen(kNonExistentName);
typedef GetUniformLocationImmediate::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
*result = -1;
GetUniformLocationImmediate& cmd =
*GetImmediateAs<GetUniformLocationImmediate>();
cmd.Init(client_program_id_, kUniform2Name,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
EXPECT_EQ(kUniform2Location, *result);
*result = -1;
cmd.Init(client_program_id_, kNonExistentName,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNonExistentNameSize));
EXPECT_EQ(-1, *result);
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformLocationImmediateInvalidArgs) {
const uint32 kNameSize = strlen(kUniform2Name);
typedef GetUniformLocationImmediate::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
*result = -1;
GetUniformLocationImmediate& cmd =
*GetImmediateAs<GetUniformLocationImmediate>();
cmd.Init(kInvalidClientId, kUniform2Name,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
EXPECT_EQ(-1, *result);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
*result = -1;
cmd.Init(client_program_id_, kUniform2Name,
kInvalidSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
EXPECT_EQ(-1, *result);
cmd.Init(client_program_id_, kUniform2Name,
kSharedMemoryId, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
EXPECT_EQ(-1, *result);
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformLocationBucket) {
const uint32 kBucketId = 123;
const char* kNonExistentName = "foobar";
typedef GetUniformLocationBucket::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
SetBucketAsCString(kBucketId, kUniform2Name);
*result = -1;
GetUniformLocationBucket cmd;
cmd.Init(client_program_id_, kBucketId,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(kUniform2Location, *result);
SetBucketAsCString(kBucketId, kNonExistentName);
*result = -1;
cmd.Init(client_program_id_, kBucketId,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
}
TEST_F(GLES2DecoderWithShaderTest, GetUniformLocationBucketInvalidArgs) {
const uint32 kBucketId = 123;
typedef GetUniformLocationBucket::Result Result;
Result* result = GetSharedMemoryAs<Result*>();
*result = -1;
GetUniformLocationBucket cmd;
// Check no bucket
cmd.Init(client_program_id_, kBucketId,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
// Check bad program id.
SetBucketAsCString(kBucketId, kUniform2Name);
cmd.Init(kInvalidClientId, kBucketId,
kSharedMemoryId, kSharedMemoryOffset);
*result = -1;
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(-1, *result);
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
// Check bad memory
cmd.Init(client_program_id_, kBucketId,
kInvalidSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(client_program_id_, kBucketId,
kSharedMemoryId, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderWithShaderTest, GetMaxValueInBufferCHROMIUM) {
SetupIndexBuffer();
GetMaxValueInBufferCHROMIUM::Result* result =
static_cast<GetMaxValueInBufferCHROMIUM::Result*>(shared_memory_address_);
*result = 0;
GetMaxValueInBufferCHROMIUM cmd;
cmd.Init(client_element_buffer_id_, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(7u, *result);
EXPECT_EQ(GL_NO_ERROR, GetGLError());
cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1,
GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(100u, *result);
EXPECT_EQ(GL_NO_ERROR, GetGLError());
cmd.Init(kInvalidClientId, kValidIndexRangeCount,
GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(client_element_buffer_id_, kOutOfRangeIndexRangeEnd,
GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1,
GL_UNSIGNED_SHORT,
kOutOfRangeIndexRangeEnd * 2, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1,
GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
cmd.Init(client_buffer_id_, kValidIndexRangeCount + 1,
GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1,
GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2,
kInvalidSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1,
GL_UNSIGNED_SHORT,
kValidIndexRangeStart * 2,
kSharedMemoryId, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, SharedIds) {
GenSharedIdsCHROMIUM gen_cmd;
RegisterSharedIdsCHROMIUM reg_cmd;
DeleteSharedIdsCHROMIUM del_cmd;
const GLuint kNamespaceId = id_namespaces::kTextures;
const GLuint kExpectedId1 = 1;
const GLuint kExpectedId2 = 2;
const GLuint kExpectedId3 = 4;
const GLuint kRegisterId = 3;
GLuint* ids = GetSharedMemoryAs<GLuint*>();
gen_cmd.Init(kNamespaceId, 0, 2, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd));
IdAllocator* id_allocator = GetIdAllocator(kNamespaceId);
ASSERT_TRUE(id_allocator != NULL);
// This check is implementation dependant but it's kind of hard to check
// otherwise.
EXPECT_EQ(kExpectedId1, ids[0]);
EXPECT_EQ(kExpectedId2, ids[1]);
EXPECT_TRUE(id_allocator->InUse(kExpectedId1));
EXPECT_TRUE(id_allocator->InUse(kExpectedId2));
EXPECT_FALSE(id_allocator->InUse(kRegisterId));
EXPECT_FALSE(id_allocator->InUse(kExpectedId3));
ClearSharedMemory();
ids[0] = kRegisterId;
reg_cmd.Init(kNamespaceId, 1, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(reg_cmd));
EXPECT_TRUE(id_allocator->InUse(kExpectedId1));
EXPECT_TRUE(id_allocator->InUse(kExpectedId2));
EXPECT_TRUE(id_allocator->InUse(kRegisterId));
EXPECT_FALSE(id_allocator->InUse(kExpectedId3));
ClearSharedMemory();
gen_cmd.Init(kNamespaceId, 0, 1, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd));
EXPECT_EQ(kExpectedId3, ids[0]);
EXPECT_TRUE(id_allocator->InUse(kExpectedId1));
EXPECT_TRUE(id_allocator->InUse(kExpectedId2));
EXPECT_TRUE(id_allocator->InUse(kRegisterId));
EXPECT_TRUE(id_allocator->InUse(kExpectedId3));
ClearSharedMemory();
ids[0] = kExpectedId1;
ids[1] = kRegisterId;
del_cmd.Init(kNamespaceId, 2, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(del_cmd));
EXPECT_FALSE(id_allocator->InUse(kExpectedId1));
EXPECT_TRUE(id_allocator->InUse(kExpectedId2));
EXPECT_FALSE(id_allocator->InUse(kRegisterId));
EXPECT_TRUE(id_allocator->InUse(kExpectedId3));
ClearSharedMemory();
ids[0] = kExpectedId3;
ids[1] = kExpectedId2;
del_cmd.Init(kNamespaceId, 2, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(del_cmd));
EXPECT_FALSE(id_allocator->InUse(kExpectedId1));
EXPECT_FALSE(id_allocator->InUse(kExpectedId2));
EXPECT_FALSE(id_allocator->InUse(kRegisterId));
EXPECT_FALSE(id_allocator->InUse(kExpectedId3));
// Check passing in an id_offset.
ClearSharedMemory();
const GLuint kOffset = 0xABCDEF;
gen_cmd.Init(kNamespaceId, kOffset, 2, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd));
EXPECT_EQ(kOffset, ids[0]);
EXPECT_EQ(kOffset + 1, ids[1]);
}
TEST_F(GLES2DecoderTest, GenSharedIdsCHROMIUMBadArgs) {
const GLuint kNamespaceId = id_namespaces::kTextures;
GenSharedIdsCHROMIUM cmd;
cmd.Init(kNamespaceId, 0, -1, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(kNamespaceId, 0, 1, kInvalidSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(kNamespaceId, 0, 1, kSharedMemoryId, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, RegisterSharedIdsCHROMIUMBadArgs) {
const GLuint kNamespaceId = id_namespaces::kTextures;
RegisterSharedIdsCHROMIUM cmd;
cmd.Init(kNamespaceId, -1, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(kNamespaceId, 1, kInvalidSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(kNamespaceId, 1, kSharedMemoryId, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, RegisterSharedIdsCHROMIUMDuplicateIds) {
const GLuint kNamespaceId = id_namespaces::kTextures;
const GLuint kRegisterId = 3;
RegisterSharedIdsCHROMIUM cmd;
GLuint* ids = GetSharedMemoryAs<GLuint*>();
ids[0] = kRegisterId;
cmd.Init(kNamespaceId, 1, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
cmd.Init(kNamespaceId, 1, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
}
TEST_F(GLES2DecoderTest, DeleteSharedIdsCHROMIUMBadArgs) {
const GLuint kNamespaceId = id_namespaces::kTextures;
DeleteSharedIdsCHROMIUM cmd;
cmd.Init(kNamespaceId, -1, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(kNamespaceId, 1, kInvalidSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(kNamespaceId, 1, kSharedMemoryId, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, TexSubImage2DValidArgs) {
const int kWidth = 16;
const int kHeight = 8;
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
DoTexImage2D(
GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
0, 0);
EXPECT_CALL(*gl_, TexSubImage2D(
GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
shared_memory_address_))
.Times(1)
.RetiresOnSaturation();
TexSubImage2D cmd;
cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderTest, TexSubImage2DBadArgs) {
const int kWidth = 16;
const int kHeight = 8;
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
DoTexImage2D(
GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
0, 0);
TexSubImage2D cmd;
cmd.Init(GL_TEXTURE0, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_TRUE, GL_UNSIGNED_BYTE,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_INT,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, -1, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 1, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 0, -1, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 0, 1, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth + 1, kHeight, GL_RGBA,
GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight + 1, GL_RGBA,
GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE,
kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA,
GL_UNSIGNED_SHORT_4_4_4_4, kSharedMemoryId, kSharedMemoryOffset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
kInvalidSharedMemoryId, kSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
kSharedMemoryId, kInvalidSharedMemoryOffset);
EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, CopyTexSubImage2DValidArgs) {
const int kWidth = 16;
const int kHeight = 8;
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
DoTexImage2D(
GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
0, 0);
EXPECT_CALL(*gl_, CopyTexSubImage2D(
GL_TEXTURE_2D, 1, 0, 0, 0, 0, kWidth, kHeight))
.Times(1)
.RetiresOnSaturation();
CopyTexSubImage2D cmd;
cmd.Init(GL_TEXTURE_2D, 1, 0, 0, 0, 0, kWidth, kHeight);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
TEST_F(GLES2DecoderTest, CopyTexSubImage2DBadArgs) {
const int kWidth = 16;
const int kHeight = 8;
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
DoTexImage2D(
GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
0, 0);
CopyTexSubImage2D cmd;
cmd.Init(GL_TEXTURE0, 1, 0, 0, 0, 0, kWidth, kHeight);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, -1, 0, 0, 0, kWidth, kHeight);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 1, 0, 0, 0, kWidth, kHeight);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 0, -1, 0, 0, kWidth, kHeight);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 0, 1, 0, 0, kWidth, kHeight);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 0, 0, 0, 0, kWidth + 1, kHeight);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
cmd.Init(GL_TEXTURE_2D, 1, 0, 0, 0, 0, kWidth, kHeight + 1);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
}
// Check that if a renderbuffer is attached and GL returns
// GL_FRAMEBUFFER_COMPLETE that the buffer is cleared and state is restored.
TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearColor) {
DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
kServiceFramebufferId);
ClearColor color_cmd;
ColorMask color_mask_cmd;
Enable enable_cmd;
FramebufferRenderbuffer cmd;
color_cmd.Init(0.1f, 0.2f, 0.3f, 0.4f);
color_mask_cmd.Init(0, 1, 0, 1);
enable_cmd.Init(GL_SCISSOR_TEST);
cmd.Init(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
client_renderbuffer_id_);
InSequence sequence;
EXPECT_CALL(*gl_, ClearColor(0.1f, 0.2f, 0.3f, 0.4f))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, ColorMask(0, 1, 0, 1))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, Enable(GL_SCISSOR_TEST))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
kServiceRenderbufferId))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
SetupExpectationsForFramebufferAttachment(
GL_COLOR_BUFFER_BIT, // clear bits
0.1f, 0.2f, 0.3f, 0.4f, // color
0x0101, // color bits
0, // stencil
-1, // stencil mask back
-1, // stencil mask front
1.0f, // depth
1, // depth mask
true); // scissor test
EXPECT_EQ(error::kNoError, ExecuteCmd(color_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(color_mask_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(enable_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearDepth) {
DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
kServiceFramebufferId);
ClearDepthf depth_cmd;
DepthMask depth_mask_cmd;
FramebufferRenderbuffer cmd;
depth_cmd.Init(0.5f);
depth_mask_cmd.Init(false);
cmd.Init(
GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
client_renderbuffer_id_);
InSequence sequence;
EXPECT_CALL(*gl_, ClearDepth(0.5f))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, DepthMask(0))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
kServiceRenderbufferId))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
SetupExpectationsForFramebufferAttachment(
GL_DEPTH_BUFFER_BIT, // clear bits
0, 0, 0, 0, // color
0x1111, // color bits
0, // stencil
-1, // stencil mask back,
-1, // stencil mask front,
0.5f, // depth
0, // depth mask
false); // scissor test
EXPECT_EQ(error::kNoError, ExecuteCmd(depth_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(depth_mask_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearStencil) {
DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
kServiceFramebufferId);
ClearStencil stencil_cmd;
StencilMaskSeparate stencil_mask_separate_cmd;
FramebufferRenderbuffer cmd;
stencil_cmd.Init(123);
stencil_mask_separate_cmd.Init(GL_BACK, 0x1234u);
cmd.Init(
GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
client_renderbuffer_id_);
InSequence sequence;
EXPECT_CALL(*gl_, ClearStencil(123))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, 0x1234u))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
kServiceRenderbufferId))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
SetupExpectationsForFramebufferAttachment(
GL_STENCIL_BUFFER_BIT, // clear bits
0, 0, 0, 0, // color
0x1111, // color bits
123, // stencil
-1, // stencil mask back,
0x1234u, // stencil mask front,
1.0f, // depth
1, // depth mask
false); // scissor test
EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_mask_separate_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
TEST_F(GLES2DecoderTest, IsBuffer) {
EXPECT_FALSE(DoIsBuffer(client_buffer_id_));
DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
EXPECT_TRUE(DoIsBuffer(client_buffer_id_));
DoDeleteBuffer(client_buffer_id_, kServiceBufferId);
EXPECT_FALSE(DoIsBuffer(client_buffer_id_));
}
TEST_F(GLES2DecoderTest, IsFramebuffer) {
EXPECT_FALSE(DoIsFramebuffer(client_framebuffer_id_));
DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
kServiceFramebufferId);
EXPECT_TRUE(DoIsFramebuffer(client_framebuffer_id_));
DoDeleteFramebuffer(client_framebuffer_id_, kServiceFramebufferId);
EXPECT_FALSE(DoIsFramebuffer(client_framebuffer_id_));
}
TEST_F(GLES2DecoderTest, IsProgram) {
// IsProgram is true as soon as the program is created.
EXPECT_TRUE(DoIsProgram(client_program_id_));
DoDeleteProgram(client_program_id_, kServiceProgramId);
EXPECT_FALSE(DoIsProgram(client_program_id_));
}
TEST_F(GLES2DecoderTest, IsRenderbuffer) {
EXPECT_FALSE(DoIsRenderbuffer(client_renderbuffer_id_));
DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
kServiceRenderbufferId);
EXPECT_TRUE(DoIsRenderbuffer(client_renderbuffer_id_));
DoDeleteRenderbuffer(client_renderbuffer_id_, kServiceRenderbufferId);
EXPECT_FALSE(DoIsRenderbuffer(client_renderbuffer_id_));
}
TEST_F(GLES2DecoderTest, IsShader) {
// IsShader is true as soon as the program is created.
EXPECT_TRUE(DoIsShader(client_shader_id_));
DoDeleteShader(client_shader_id_, kServiceShaderId);
EXPECT_FALSE(DoIsShader(client_shader_id_));
}
TEST_F(GLES2DecoderTest, IsTexture) {
EXPECT_FALSE(DoIsTexture(client_texture_id_));
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
EXPECT_TRUE(DoIsTexture(client_texture_id_));
DoDeleteTexture(client_texture_id_, kServiceTextureId);
EXPECT_FALSE(DoIsTexture(client_texture_id_));
}
#if 0 // Turn this test on once we allow GL_DEPTH_STENCIL_ATTACHMENT
TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearDepthStencil) {
DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
kServiceFramebufferId);
ClearDepthf depth_cmd;
ClearStencil stencil_cmd;
FramebufferRenderbuffer cmd;
depth_cmd.Init(0.5f);
stencil_cmd.Init(123);
cmd.Init(
GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
client_renderbuffer_id_);
InSequence sequence;
EXPECT_CALL(*gl_, ClearDepth(0.5f))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, ClearStencil(123))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
kServiceRenderbufferId))
.Times(1)
.RetiresOnSaturation();
SetupExpectationsForFramebufferAttachment(
GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, // clear bits
0, 0, 0, 0, // color
0x1111, // color bits
123, // stencil
-1, // stencil mask back,
-1, // stencil mask front,
0.5f, // depth
1, // depth mask
false); // scissor test
EXPECT_EQ(error::kNoError, ExecuteCmd(depth_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_cmd));
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
}
#endif
TEST_F(GLES2DecoderWithShaderTest, VertexAttribPointer) {
SetupVertexBuffer();
static const GLenum types[] = {
GL_BYTE,
GL_UNSIGNED_BYTE,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_FLOAT,
GL_FIXED,
GL_INT,
GL_UNSIGNED_INT,
};
static const GLsizei sizes[] = {
1,
1,
2,
2,
4,
4,
4,
4,
};
static const GLuint indices[] = {
0,
1,
kNumVertexAttribs - 1,
kNumVertexAttribs,
};
static const GLsizei offset_mult[] = {
0,
0,
1,
1,
2,
1000,
};
static const GLsizei offset_offset[] = {
0,
1,
0,
1,
0,
0,
};
static const GLsizei stride_mult[] = {
-1,
0,
0,
1,
1,
2,
1000,
};
static const GLsizei stride_offset[] = {
0,
0,
1,
0,
1,
0,
0,
};
for (size_t tt = 0; tt < arraysize(types); ++tt) {
GLenum type = types[tt];
GLsizei num_bytes = sizes[tt];
for (size_t ii = 0; ii < arraysize(indices); ++ii) {
GLuint index = indices[ii];
for (GLint size = 0; size < 5; ++size) {
for (size_t oo = 0; oo < arraysize(offset_mult); ++oo) {
GLuint offset = num_bytes * offset_mult[oo] + offset_offset[oo];
for (size_t ss = 0; ss <= arraysize(stride_mult); ++ss) {
GLsizei stride = num_bytes * stride_mult[ss] + stride_offset[ss];
for (int normalize = 0; normalize < 2; ++normalize) {
bool index_good = index < static_cast<GLuint>(kNumVertexAttribs);
bool size_good = (size > 0 && size < 5);
bool offset_good = (offset % num_bytes == 0);
bool stride_good = (stride % num_bytes == 0) && stride >= 0 &&
stride <= 255;
bool type_good = (type != GL_INT && type != GL_UNSIGNED_INT &&
type != GL_FIXED);
bool good = size_good && offset_good && stride_good &&
type_good && index_good;
bool call = good && (type != GL_FIXED);
if (call) {
EXPECT_CALL(*gl_, VertexAttribPointer(
index, size, type, normalize, stride,
BufferOffset(offset)));
}
VertexAttribPointer cmd;
cmd.Init(index, size, type, normalize, stride, offset);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
if (good) {
EXPECT_EQ(GL_NO_ERROR, GetGLError());
} else if (size_good &&
offset_good &&
stride_good &&
type_good &&
!index_good) {
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
} else if (size_good &&
offset_good &&
stride_good &&
!type_good &&
index_good) {
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
} else if (size_good &&
offset_good &&
!stride_good &&
type_good &&
index_good) {
if (stride < 0 || stride > 255) {
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
} else {
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
} else if (size_good &&
!offset_good &&
stride_good &&
type_good &&
index_good) {
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
} else if (!size_good &&
offset_good &&
stride_good &&
type_good &&
index_good) {
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
} else {
EXPECT_NE(GL_NO_ERROR, GetGLError());
}
}
}
}
}
}
}
}
// TODO(gman): BufferData
// TODO(gman): BufferDataImmediate
// TODO(gman): BufferSubData
// TODO(gman): BufferSubDataImmediate
// TODO(gman): CompressedTexImage2D
// TODO(gman): CompressedTexImage2DImmediate
// TODO(gman): CompressedTexSubImage2DImmediate
// TODO(gman): DeleteProgram
// TODO(gman): DeleteShader
// TODO(gman): PixelStorei
// TODO(gman): TexImage2D
// TODO(gman): TexImage2DImmediate
// TODO(gman): TexSubImage2DImmediate
// TODO(gman): UseProgram
// TODO(gman): SwapBuffers
} // namespace gles2
} // namespace gpu