summaryrefslogtreecommitdiffstats
path: root/chromium/gpu/command_buffer/client/gles2_implementation_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/gpu/command_buffer/client/gles2_implementation_unittest.cc')
-rw-r--r--chromium/gpu/command_buffer/client/gles2_implementation_unittest.cc818
1 files changed, 675 insertions, 143 deletions
diff --git a/chromium/gpu/command_buffer/client/gles2_implementation_unittest.cc b/chromium/gpu/command_buffer/client/gles2_implementation_unittest.cc
index e6e0861d188..a318ab8f33f 100644
--- a/chromium/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/chromium/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -6,6 +6,8 @@
#include "gpu/command_buffer/client/gles2_implementation.h"
+#include <limits>
+
#include <GLES2/gl2ext.h>
#include <GLES2/gl2extchromium.h>
#include "base/compiler_specific.h"
@@ -167,11 +169,11 @@ class MockTransferBuffer : public TransferBufferInterface {
static const int kNumBuffers = 2;
uint8* actual_buffer() const {
- return static_cast<uint8*>(buffers_[actual_buffer_index_].ptr);
+ return static_cast<uint8*>(buffers_[actual_buffer_index_]->memory());
}
uint8* expected_buffer() const {
- return static_cast<uint8*>(buffers_[expected_buffer_index_].ptr);
+ return static_cast<uint8*>(buffers_[expected_buffer_index_]->memory());
}
uint32 AllocateExpectedTransferBuffer(size_t size) {
@@ -214,7 +216,7 @@ class MockTransferBuffer : public TransferBufferInterface {
size_t result_size_;
uint32 alignment_;
int buffer_ids_[kNumBuffers];
- gpu::Buffer buffers_[kNumBuffers];
+ scoped_refptr<Buffer> buffers_[kNumBuffers];
int actual_buffer_index_;
int expected_buffer_index_;
void* last_alloc_;
@@ -297,8 +299,65 @@ void MockTransferBuffer::FreePendingToken(void* p, unsigned int /* token */) {
last_alloc_ = NULL;
}
+// API wrapper for Buffers.
+class GenBuffersAPI {
+ public:
+ static void Gen(GLES2Implementation* gl_impl, GLsizei n, GLuint* ids) {
+ gl_impl->GenBuffers(n, ids);
+ }
+
+ static void Delete(GLES2Implementation* gl_impl,
+ GLsizei n,
+ const GLuint* ids) {
+ gl_impl->DeleteBuffers(n, ids);
+ }
+};
+
+// API wrapper for Framebuffers.
+class GenFramebuffersAPI {
+ public:
+ static void Gen(GLES2Implementation* gl_impl, GLsizei n, GLuint* ids) {
+ gl_impl->GenFramebuffers(n, ids);
+ }
+
+ static void Delete(GLES2Implementation* gl_impl,
+ GLsizei n,
+ const GLuint* ids) {
+ gl_impl->DeleteFramebuffers(n, ids);
+ }
+};
+
+// API wrapper for Renderbuffers.
+class GenRenderbuffersAPI {
+ public:
+ static void Gen(GLES2Implementation* gl_impl, GLsizei n, GLuint* ids) {
+ gl_impl->GenRenderbuffers(n, ids);
+ }
+
+ static void Delete(GLES2Implementation* gl_impl,
+ GLsizei n,
+ const GLuint* ids) {
+ gl_impl->DeleteRenderbuffers(n, ids);
+ }
+};
+
+// API wrapper for Textures.
+class GenTexturesAPI {
+ public:
+ static void Gen(GLES2Implementation* gl_impl, GLsizei n, GLuint* ids) {
+ gl_impl->GenTextures(n, ids);
+ }
+
+ static void Delete(GLES2Implementation* gl_impl,
+ GLsizei n,
+ const GLuint* ids) {
+ gl_impl->DeleteTextures(n, ids);
+ }
+};
+
class GLES2ImplementationTest : public testing::Test {
protected:
+ static const int kNumTestContexts = 2;
static const uint8 kInitialValue = 0xBD;
static const int32 kNumCommandEntries = 500;
static const int32 kCommandBufferSizeBytes =
@@ -319,7 +378,7 @@ class GLES2ImplementationTest : public testing::Test {
static const GLint kNumShaderBinaryFormats = 0;
static const GLuint kStartId = 1024;
static const GLuint kBuffersStartId =
- GLES2Implementation::kClientSideArrayId + 2;
+ GLES2Implementation::kClientSideArrayId + 2 * kNumTestContexts;
static const GLuint kFramebuffersStartId = 1;
static const GLuint kProgramsAndShadersStartId = 1;
static const GLuint kRenderbuffersStartId = 1;
@@ -329,18 +388,130 @@ class GLES2ImplementationTest : public testing::Test {
typedef MockTransferBuffer::ExpectedMemoryInfo ExpectedMemoryInfo;
- GLES2ImplementationTest()
- : commands_(NULL),
- token_(0) {
- }
+ class TestContext {
+ public:
+ TestContext() : commands_(NULL), token_(0) {}
+
+ bool Initialize(ShareGroup* share_group,
+ bool bind_generates_resource,
+ bool lose_context_when_out_of_memory) {
+ command_buffer_.reset(new StrictMock<MockClientCommandBuffer>());
+ if (!command_buffer_->Initialize())
+ return false;
+
+ transfer_buffer_.reset(
+ new MockTransferBuffer(command_buffer_.get(),
+ kTransferBufferSize,
+ GLES2Implementation::kStartingOffset,
+ GLES2Implementation::kAlignment));
+
+ helper_.reset(new GLES2CmdHelper(command_buffer()));
+ helper_->Initialize(kCommandBufferSizeBytes);
+
+ gpu_control_.reset(new StrictMock<MockClientGpuControl>());
+ EXPECT_CALL(*gpu_control_, GetCapabilities())
+ .WillOnce(testing::Return(Capabilities()));
+
+ GLES2Implementation::GLStaticState state;
+ GLES2Implementation::GLStaticState::IntState& int_state = state.int_state;
+ int_state.max_combined_texture_image_units =
+ kMaxCombinedTextureImageUnits;
+ int_state.max_cube_map_texture_size = kMaxCubeMapTextureSize;
+ int_state.max_fragment_uniform_vectors = kMaxFragmentUniformVectors;
+ int_state.max_renderbuffer_size = kMaxRenderbufferSize;
+ int_state.max_texture_image_units = kMaxTextureImageUnits;
+ int_state.max_texture_size = kMaxTextureSize;
+ int_state.max_varying_vectors = kMaxVaryingVectors;
+ int_state.max_vertex_attribs = kMaxVertexAttribs;
+ int_state.max_vertex_texture_image_units = kMaxVertexTextureImageUnits;
+ int_state.max_vertex_uniform_vectors = kMaxVertexUniformVectors;
+ int_state.num_compressed_texture_formats = kNumCompressedTextureFormats;
+ int_state.num_shader_binary_formats = kNumShaderBinaryFormats;
+ int_state.bind_generates_resource_chromium =
+ bind_generates_resource ? 1 : 0;
+
+ // This just happens to work for now because IntState has 1 GLint per
+ // state.
+ // If IntState gets more complicated this code will need to get more
+ // complicated.
+ ExpectedMemoryInfo mem1 = transfer_buffer_->GetExpectedMemory(
+ sizeof(GLES2Implementation::GLStaticState::IntState) * 2 +
+ sizeof(cmds::GetShaderPrecisionFormat::Result) * 12);
+
+ {
+ InSequence sequence;
+
+ EXPECT_CALL(*command_buffer_, OnFlush())
+ .WillOnce(SetMemory(mem1.ptr + sizeof(int_state), int_state))
+ .RetiresOnSaturation();
+ GetNextToken(); // eat the token that starting up will use.
+
+ gl_.reset(new GLES2Implementation(helper_.get(),
+ share_group,
+ transfer_buffer_.get(),
+ bind_generates_resource,
+ lose_context_when_out_of_memory,
+ gpu_control_.get()));
+
+ if (!gl_->Initialize(kTransferBufferSize,
+ kTransferBufferSize,
+ kTransferBufferSize,
+ GLES2Implementation::kNoLimit))
+ return false;
+ }
+
+ EXPECT_CALL(*command_buffer_, OnFlush()).Times(1).RetiresOnSaturation();
+ helper_->CommandBufferHelper::Finish();
+ ::testing::Mock::VerifyAndClearExpectations(gl_.get());
+
+ scoped_refptr<Buffer> ring_buffer = helper_->get_ring_buffer();
+ commands_ = static_cast<CommandBufferEntry*>(ring_buffer->memory()) +
+ command_buffer()->GetLastState().put_offset;
+ ClearCommands();
+ EXPECT_TRUE(transfer_buffer_->InSync());
+
+ ::testing::Mock::VerifyAndClearExpectations(command_buffer());
+ return true;
+ }
+
+ void TearDown() {
+ Mock::VerifyAndClear(gl_.get());
+ EXPECT_CALL(*command_buffer(), OnFlush()).Times(AnyNumber());
+ // For command buffer.
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(AtLeast(1));
+ gl_.reset();
+ }
+
+ MockClientCommandBuffer* command_buffer() const {
+ return command_buffer_.get();
+ }
+
+ int GetNextToken() { return ++token_; }
+
+ void ClearCommands() {
+ scoped_refptr<Buffer> ring_buffer = helper_->get_ring_buffer();
+ memset(ring_buffer->memory(), kInitialValue, ring_buffer->size());
+ }
+
+ scoped_ptr<MockClientCommandBuffer> command_buffer_;
+ scoped_ptr<MockClientGpuControl> gpu_control_;
+ scoped_ptr<GLES2CmdHelper> helper_;
+ scoped_ptr<MockTransferBuffer> transfer_buffer_;
+ scoped_ptr<GLES2Implementation> gl_;
+ CommandBufferEntry* commands_;
+ int token_;
+ };
+
+ GLES2ImplementationTest() : commands_(NULL) {}
virtual void SetUp() OVERRIDE;
virtual void TearDown() OVERRIDE;
bool NoCommandsWritten() {
- Buffer ring_buffer = helper_->get_ring_buffer();
- const uint8* cmds = reinterpret_cast<const uint8*>(ring_buffer.ptr);
- const uint8* end = cmds + ring_buffer.size;
+ scoped_refptr<Buffer> ring_buffer = helper_->get_ring_buffer();
+ const uint8* cmds = reinterpret_cast<const uint8*>(ring_buffer->memory());
+ const uint8* end = cmds + ring_buffer->size();
for (; cmds < end; ++cmds) {
if (*cmds != kInitialValue) {
return false;
@@ -353,97 +524,51 @@ class GLES2ImplementationTest : public testing::Test {
return gl_->query_tracker_->GetQuery(id);
}
- void Initialize(bool bind_generates_resource) {
- command_buffer_.reset(new StrictMock<MockClientCommandBuffer>());
- ASSERT_TRUE(command_buffer_->Initialize());
-
- transfer_buffer_.reset(new MockTransferBuffer(
- command_buffer(),
- kTransferBufferSize,
- GLES2Implementation::kStartingOffset,
- GLES2Implementation::kAlignment));
-
- helper_.reset(new GLES2CmdHelper(command_buffer()));
- helper_->Initialize(kCommandBufferSizeBytes);
-
- gpu_control_.reset(new StrictMock<MockClientGpuControl>());
- EXPECT_CALL(*gpu_control_, GetCapabilities())
- .WillOnce(testing::Return(Capabilities()));
-
- GLES2Implementation::GLStaticState state;
- GLES2Implementation::GLStaticState::IntState& int_state = state.int_state;
- int_state.max_combined_texture_image_units = kMaxCombinedTextureImageUnits;
- int_state.max_cube_map_texture_size = kMaxCubeMapTextureSize;
- int_state.max_fragment_uniform_vectors = kMaxFragmentUniformVectors;
- int_state.max_renderbuffer_size = kMaxRenderbufferSize;
- int_state.max_texture_image_units = kMaxTextureImageUnits;
- int_state.max_texture_size = kMaxTextureSize;
- int_state.max_varying_vectors = kMaxVaryingVectors;
- int_state.max_vertex_attribs = kMaxVertexAttribs;
- int_state.max_vertex_texture_image_units = kMaxVertexTextureImageUnits;
- int_state.max_vertex_uniform_vectors = kMaxVertexUniformVectors;
- int_state.num_compressed_texture_formats = kNumCompressedTextureFormats;
- int_state.num_shader_binary_formats = kNumShaderBinaryFormats;
-
- // This just happens to work for now because IntState has 1 GLint per state.
- // If IntState gets more complicated this code will need to get more
- // complicated.
- ExpectedMemoryInfo mem1 = GetExpectedMemory(
- sizeof(GLES2Implementation::GLStaticState::IntState) * 2 +
- sizeof(cmds::GetShaderPrecisionFormat::Result) * 12);
-
- {
- InSequence sequence;
-
- EXPECT_CALL(*command_buffer(), OnFlush())
- .WillOnce(SetMemory(mem1.ptr + sizeof(int_state), int_state))
- .RetiresOnSaturation();
- GetNextToken(); // eat the token that starting up will use.
-
- gl_.reset(new GLES2Implementation(
- helper_.get(),
- NULL,
- transfer_buffer_.get(),
- bind_generates_resource,
- false /* free_everything_when_invisible */,
- gpu_control_.get()));
- ASSERT_TRUE(gl_->Initialize(
- kTransferBufferSize,
- kTransferBufferSize,
- kTransferBufferSize,
- GLES2Implementation::kNoLimit));
- }
+ struct ContextInitOptions {
+ ContextInitOptions()
+ : bind_generates_resource_client(true),
+ bind_generates_resource_service(true),
+ lose_context_when_out_of_memory(false) {}
- EXPECT_CALL(*command_buffer(), OnFlush())
- .Times(1)
- .RetiresOnSaturation();
- helper_->CommandBufferHelper::Finish();
- ::testing::Mock::VerifyAndClearExpectations(gl_.get());
+ bool bind_generates_resource_client;
+ bool bind_generates_resource_service;
+ bool lose_context_when_out_of_memory;
+ };
- Buffer ring_buffer = helper_->get_ring_buffer();
- commands_ = static_cast<CommandBufferEntry*>(ring_buffer.ptr) +
- command_buffer()->GetState().put_offset;
- ClearCommands();
- EXPECT_TRUE(transfer_buffer_->InSync());
+ bool Initialize(const ContextInitOptions& init_options) {
+ bool success = true;
+ share_group_ = new ShareGroup(init_options.bind_generates_resource_service);
- ::testing::Mock::VerifyAndClearExpectations(command_buffer());
+ for (int i = 0; i < kNumTestContexts; i++) {
+ if (!test_contexts_[i].Initialize(
+ share_group_.get(),
+ init_options.bind_generates_resource_client,
+ init_options.lose_context_when_out_of_memory))
+ success = false;
+ }
+
+ // Default to test context 0.
+ gpu_control_ = test_contexts_[0].gpu_control_.get();
+ helper_ = test_contexts_[0].helper_.get();
+ transfer_buffer_ = test_contexts_[0].transfer_buffer_.get();
+ gl_ = test_contexts_[0].gl_.get();
+ commands_ = test_contexts_[0].commands_;
+ return success;
}
MockClientCommandBuffer* command_buffer() const {
- return command_buffer_.get();
+ return test_contexts_[0].command_buffer_.get();
}
- int GetNextToken() {
- return ++token_;
- }
+ int GetNextToken() { return test_contexts_[0].GetNextToken(); }
const void* GetPut() {
return helper_->GetSpace(0);
}
void ClearCommands() {
- Buffer ring_buffer = helper_->get_ring_buffer();
- memset(ring_buffer.ptr, kInitialValue, ring_buffer.size);
+ scoped_refptr<Buffer> ring_buffer = helper_->get_ring_buffer();
+ memset(ring_buffer->memory(), kInitialValue, ring_buffer->size());
}
size_t MaxTransferBufferSize() {
@@ -473,40 +598,133 @@ class GLES2ImplementationTest : public testing::Test {
return gl_->GetError();
}
+ const std::string& GetLastError() {
+ return gl_->GetLastError();
+ }
+
bool GetBucketContents(uint32 bucket_id, std::vector<int8>* data) {
return gl_->GetBucketContents(bucket_id, data);
}
- Sequence sequence_;
- scoped_ptr<MockClientCommandBuffer> command_buffer_;
- scoped_ptr<MockClientGpuControl> gpu_control_;
- scoped_ptr<GLES2CmdHelper> helper_;
- scoped_ptr<MockTransferBuffer> transfer_buffer_;
- scoped_ptr<GLES2Implementation> gl_;
+ TestContext test_contexts_[kNumTestContexts];
+
+ scoped_refptr<ShareGroup> share_group_;
+ MockClientGpuControl* gpu_control_;
+ GLES2CmdHelper* helper_;
+ MockTransferBuffer* transfer_buffer_;
+ GLES2Implementation* gl_;
CommandBufferEntry* commands_;
- int token_;
};
void GLES2ImplementationTest::SetUp() {
- Initialize(true);
+ ContextInitOptions init_options;
+ ASSERT_TRUE(Initialize(init_options));
}
void GLES2ImplementationTest::TearDown() {
- Mock::VerifyAndClear(gl_.get());
- EXPECT_CALL(*command_buffer(), OnFlush()).Times(AnyNumber());
- // For command buffer.
- EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
- .Times(AtLeast(1));
- gl_.reset();
+ for (int i = 0; i < kNumTestContexts; i++)
+ test_contexts_[i].TearDown();
}
+class GLES2ImplementationManualInitTest : public GLES2ImplementationTest {
+ protected:
+ virtual void SetUp() OVERRIDE {}
+};
+
class GLES2ImplementationStrictSharedTest : public GLES2ImplementationTest {
protected:
virtual void SetUp() OVERRIDE;
+
+ template <class ResApi>
+ void FlushGenerationTest() {
+ GLuint id1, id2, id3;
+
+ // Generate valid id.
+ ResApi::Gen(gl_, 1, &id1);
+ EXPECT_NE(id1, 0u);
+
+ // Delete id1 and generate id2. id1 should not be reused.
+ ResApi::Delete(gl_, 1, &id1);
+ ResApi::Gen(gl_, 1, &id2);
+ EXPECT_NE(id2, 0u);
+ EXPECT_NE(id2, id1);
+
+ // Expect id1 reuse after Flush.
+ gl_->Flush();
+ ResApi::Gen(gl_, 1, &id3);
+ EXPECT_EQ(id3, id1);
+ }
+
+ // Ids should not be reused unless the |Deleting| context does a Flush()
+ // AND triggers a lazy release after that.
+ template <class ResApi>
+ void CrossContextGenerationTest() {
+ GLES2Implementation* gl1 = test_contexts_[0].gl_.get();
+ GLES2Implementation* gl2 = test_contexts_[1].gl_.get();
+ GLuint id1, id2, id3;
+
+ // Delete, no flush on context 1. No reuse.
+ ResApi::Gen(gl1, 1, &id1);
+ ResApi::Delete(gl1, 1, &id1);
+ ResApi::Gen(gl1, 1, &id2);
+ EXPECT_NE(id1, id2);
+
+ // Flush context 2. Still no reuse.
+ gl2->Flush();
+ ResApi::Gen(gl2, 1, &id3);
+ EXPECT_NE(id1, id3);
+ EXPECT_NE(id2, id3);
+
+ // Flush on context 1, but no lazy release. Still no reuse.
+ gl1->Flush();
+ ResApi::Gen(gl2, 1, &id3);
+ EXPECT_NE(id1, id3);
+
+ // Lazy release triggered by another Delete. Should reuse id1.
+ ResApi::Delete(gl1, 1, &id2);
+ ResApi::Gen(gl2, 1, &id3);
+ EXPECT_EQ(id1, id3);
+ }
+
+ // Same as CrossContextGenerationTest(), but triggers an Auto Flush on
+ // the Delete(). Tests an edge case regression.
+ template <class ResApi>
+ void CrossContextGenerationAutoFlushTest() {
+ GLES2Implementation* gl1 = test_contexts_[0].gl_.get();
+ GLES2Implementation* gl2 = test_contexts_[1].gl_.get();
+ GLuint id1, id2, id3;
+
+ // Delete, no flush on context 1. No reuse.
+ // By half filling the buffer, an internal flush is forced on the Delete().
+ ResApi::Gen(gl1, 1, &id1);
+ gl1->helper()->Noop(kNumCommandEntries / 2);
+ ResApi::Delete(gl1, 1, &id1);
+ ResApi::Gen(gl1, 1, &id2);
+ EXPECT_NE(id1, id2);
+
+ // Flush context 2. Still no reuse.
+ gl2->Flush();
+ ResApi::Gen(gl2, 1, &id3);
+ EXPECT_NE(id1, id3);
+ EXPECT_NE(id2, id3);
+
+ // Flush on context 1, but no lazy release. Still no reuse.
+ gl1->Flush();
+ ResApi::Gen(gl2, 1, &id3);
+ EXPECT_NE(id1, id3);
+
+ // Lazy release triggered by another Delete. Should reuse id1.
+ ResApi::Delete(gl1, 1, &id2);
+ ResApi::Gen(gl2, 1, &id3);
+ EXPECT_EQ(id1, id3);
+ }
};
void GLES2ImplementationStrictSharedTest::SetUp() {
- Initialize(false);
+ ContextInitOptions init_options;
+ init_options.bind_generates_resource_client = false;
+ init_options.bind_generates_resource_service = false;
+ ASSERT_TRUE(Initialize(init_options));
}
// GCC requires these declarations, but MSVC requires they not be present
@@ -2091,7 +2309,7 @@ TEST_F(GLES2ImplementationTest, TexImage2D) {
Cmds expected;
expected.tex_image_2d.Init(
- kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+ kTarget, kLevel, kFormat, kWidth, kHeight, kFormat, kType,
mem1.id, mem1.offset);
expected.set_token.Init(GetNextToken());
gl_->TexImage2D(
@@ -2108,7 +2326,7 @@ TEST_F(GLES2ImplementationTest, TexImage2D) {
ExpectedMemoryInfo mem2 = GetExpectedMemory(sizeof(pixels));
Cmds2 expected2;
expected2.tex_image_2d.Init(
- kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+ kTarget, kLevel, kFormat, kWidth, kHeight, kFormat, kType,
mem2.id, mem2.offset);
expected2.set_token.Init(GetNextToken());
const void* commands2 = GetPut();
@@ -2163,7 +2381,7 @@ TEST_F(GLES2ImplementationTest, TexImage2D2Writes) {
Cmds expected;
expected.tex_image_2d.Init(
- kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+ kTarget, kLevel, kFormat, kWidth, kHeight, kFormat, kType,
0, 0);
expected.tex_sub_image_2d1.Init(
kTarget, kLevel, 0, 0, kWidth, kHeight / 2, kFormat, kType,
@@ -2196,7 +2414,7 @@ TEST_F(GLES2ImplementationTest, TexImage2D2Writes) {
ExpectedMemoryInfo mem3 = GetExpectedMemory(half_size);
ExpectedMemoryInfo mem4 = GetExpectedMemory(half_size);
expected.tex_image_2d.Init(
- kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+ kTarget, kLevel, kFormat, kWidth, kHeight, kFormat, kType,
0, 0);
expected.tex_sub_image_2d1.Init(
kTarget, kLevel, 0, kHeight / 2, kWidth, kHeight / 2, kFormat, kType,
@@ -2260,7 +2478,7 @@ TEST_F(GLES2ImplementationTest, TexSubImage2DFlipY) {
Cmds expected;
expected.pixel_store_i1.Init(GL_UNPACK_ALIGNMENT, kPixelStoreUnpackAlignment);
expected.tex_image_2d.Init(
- kTarget, kLevel, kFormat, kTextureWidth, kTextureHeight, kBorder, kFormat,
+ kTarget, kLevel, kFormat, kTextureWidth, kTextureHeight, kFormat,
kType, 0, 0);
expected.pixel_store_i2.Init(GL_UNPACK_FLIP_Y_CHROMIUM, GL_TRUE);
expected.tex_sub_image_2d1.Init(kTarget, kLevel, kSubImageXOffset,
@@ -2355,9 +2573,9 @@ TEST_F(GLES2ImplementationTest, SubImageUnpack) {
const void* commands = GetPut();
gl_->PixelStorei(GL_UNPACK_ALIGNMENT, alignment);
- gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, kSrcWidth);
- gl_->PixelStorei(GL_UNPACK_SKIP_PIXELS, kSrcSubImageX0);
- gl_->PixelStorei(GL_UNPACK_SKIP_ROWS, kSrcSubImageY0);
+ gl_->PixelStorei(GL_UNPACK_ROW_LENGTH_EXT, kSrcWidth);
+ gl_->PixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, kSrcSubImageX0);
+ gl_->PixelStorei(GL_UNPACK_SKIP_ROWS_EXT, kSrcSubImageY0);
gl_->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
if (sub) {
gl_->TexImage2D(
@@ -2372,7 +2590,7 @@ TEST_F(GLES2ImplementationTest, SubImageUnpack) {
texSubImageExpected.pixel_store_i2.Init(
GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
texSubImageExpected.tex_image_2d.Init(
- GL_TEXTURE_2D, kLevel, kFormat, kTexWidth, kTexHeight, kBorder,
+ GL_TEXTURE_2D, kLevel, kFormat, kTexWidth, kTexHeight,
kFormat, kType, 0, 0);
texSubImageExpected.tex_sub_image_2d.Init(
GL_TEXTURE_2D, kLevel, kTexSubXOffset, kTexSubYOffset,
@@ -2390,7 +2608,7 @@ TEST_F(GLES2ImplementationTest, SubImageUnpack) {
GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
texImageExpected.tex_image_2d.Init(
GL_TEXTURE_2D, kLevel, kFormat, kSrcSubImageWidth,
- kSrcSubImageHeight, kBorder, kFormat, kType, mem.id, mem.offset);
+ kSrcSubImageHeight, kFormat, kType, mem.id, mem.offset);
EXPECT_EQ(0, memcmp(
&texImageExpected, commands, sizeof(texImageExpected)));
}
@@ -2413,6 +2631,93 @@ TEST_F(GLES2ImplementationTest, SubImageUnpack) {
}
}
+// Test texture related calls with invalid arguments.
+TEST_F(GLES2ImplementationTest, TextureInvalidArguments) {
+ struct Cmds {
+ cmds::TexImage2D tex_image_2d;
+ cmd::SetToken set_token;
+ };
+ const GLenum kTarget = GL_TEXTURE_2D;
+ const GLint kLevel = 0;
+ const GLenum kFormat = GL_RGB;
+ const GLsizei kWidth = 3;
+ const GLsizei kHeight = 4;
+ const GLint kBorder = 0;
+ const GLint kInvalidBorder = 1;
+ const GLenum kType = GL_UNSIGNED_BYTE;
+ const GLint kPixelStoreUnpackAlignment = 4;
+ static uint8 pixels[] = {
+ 11, 12, 13, 13, 14, 15, 15, 16, 17, 101, 102, 103,
+ 21, 22, 23, 23, 24, 25, 25, 26, 27, 201, 202, 203,
+ 31, 32, 33, 33, 34, 35, 35, 36, 37, 123, 124, 125,
+ 41, 42, 43, 43, 44, 45, 45, 46, 47,
+ };
+
+ // Verify that something works.
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(sizeof(pixels));
+
+ Cmds expected;
+ expected.tex_image_2d.Init(
+ kTarget, kLevel, kFormat, kWidth, kHeight, kFormat, kType,
+ mem1.id, mem1.offset);
+ expected.set_token.Init(GetNextToken());
+ gl_->TexImage2D(
+ kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+ pixels);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(CheckRect(
+ kWidth, kHeight, kFormat, kType, kPixelStoreUnpackAlignment, false,
+ pixels, mem1.ptr));
+
+ ClearCommands();
+
+ // Use invalid border.
+ gl_->TexImage2D(
+ kTarget, kLevel, kFormat, kWidth, kHeight, kInvalidBorder, kFormat, kType,
+ pixels);
+
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(GL_INVALID_VALUE, CheckError());
+
+ ClearCommands();
+
+ gl_->AsyncTexImage2DCHROMIUM(
+ kTarget, kLevel, kFormat, kWidth, kHeight, kInvalidBorder, kFormat, kType,
+ NULL);
+
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(GL_INVALID_VALUE, CheckError());
+
+ ClearCommands();
+
+ // Checking for CompressedTexImage2D argument validation is a bit tricky due
+ // to (runtime-detected) compression formats. Try to infer the error with an
+ // aux check.
+ const GLenum kCompressedFormat = GL_ETC1_RGB8_OES;
+ gl_->CompressedTexImage2D(
+ kTarget, kLevel, kCompressedFormat, kWidth, kHeight, kBorder,
+ arraysize(pixels), pixels);
+
+ // In the above, kCompressedFormat and arraysize(pixels) are possibly wrong
+ // values. First ensure that these do not cause failures at the client. If
+ // this check ever fails, it probably means that client checks more than at
+ // the time of writing of this test. In this case, more code needs to be
+ // written for this test.
+ EXPECT_FALSE(NoCommandsWritten());
+
+ ClearCommands();
+
+ // Changing border to invalid border should make the call fail at the client
+ // checks.
+ gl_->CompressedTexImage2D(
+ kTarget, kLevel, kCompressedFormat, kWidth, kHeight, kInvalidBorder,
+ arraysize(pixels), pixels);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(GL_INVALID_VALUE, CheckError());
+}
+
+
// Binds can not be cached with bind_generates_resource = false because
// our id might not be valid. More specifically if you bind on contextA then
// delete on contextB the resource is still bound on contextA but GetInterger
@@ -2444,32 +2749,56 @@ TEST_F(GLES2ImplementationStrictSharedTest, BindsNotCached) {
}
}
-TEST_F(GLES2ImplementationTest, CreateStreamTextureCHROMIUM) {
- const GLuint kTextureId = 123;
- const GLuint kResult = 456;
-
- struct Cmds {
- cmds::CreateStreamTextureCHROMIUM create_stream;
- };
-
- ExpectedMemoryInfo result1 =
- GetExpectedResultMemory(
- sizeof(cmds::CreateStreamTextureCHROMIUM::Result));
- ExpectedMemoryInfo result2 =
- GetExpectedResultMemory(sizeof(cmds::GetError::Result));
-
- Cmds expected;
- expected.create_stream.Init(kTextureId, result1.id, result1.offset);
+// glGen* Ids must not be reused until glDelete* commands have been
+// flushed by glFlush.
+TEST_F(GLES2ImplementationStrictSharedTest, FlushGenerationTestBuffers) {
+ FlushGenerationTest<GenBuffersAPI>();
+}
+TEST_F(GLES2ImplementationStrictSharedTest, FlushGenerationTestFramebuffers) {
+ FlushGenerationTest<GenFramebuffersAPI>();
+}
+TEST_F(GLES2ImplementationStrictSharedTest, FlushGenerationTestRenderbuffers) {
+ FlushGenerationTest<GenRenderbuffersAPI>();
+}
+TEST_F(GLES2ImplementationStrictSharedTest, FlushGenerationTestTextures) {
+ FlushGenerationTest<GenTexturesAPI>();
+}
- EXPECT_CALL(*command_buffer(), OnFlush())
- .WillOnce(SetMemory(result1.ptr, kResult))
- .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
- .RetiresOnSaturation();
+// glGen* Ids must not be reused cross-context until glDelete* commands are
+// flushed by glFlush, and the Ids are lazily freed after.
+TEST_F(GLES2ImplementationStrictSharedTest, CrossContextGenerationTestBuffers) {
+ CrossContextGenerationTest<GenBuffersAPI>();
+}
+TEST_F(GLES2ImplementationStrictSharedTest,
+ CrossContextGenerationTestFramebuffers) {
+ CrossContextGenerationTest<GenFramebuffersAPI>();
+}
+TEST_F(GLES2ImplementationStrictSharedTest,
+ CrossContextGenerationTestRenderbuffers) {
+ CrossContextGenerationTest<GenRenderbuffersAPI>();
+}
+TEST_F(GLES2ImplementationStrictSharedTest,
+ CrossContextGenerationTestTextures) {
+ CrossContextGenerationTest<GenTexturesAPI>();
+}
- GLuint handle = gl_->CreateStreamTextureCHROMIUM(kTextureId);
- EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
- EXPECT_EQ(handle, kResult);
- EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
+// Test Delete which causes auto flush. Tests a regression case that occurred
+// in testing.
+TEST_F(GLES2ImplementationStrictSharedTest,
+ CrossContextGenerationAutoFlushTestBuffers) {
+ CrossContextGenerationAutoFlushTest<GenBuffersAPI>();
+}
+TEST_F(GLES2ImplementationStrictSharedTest,
+ CrossContextGenerationAutoFlushTestFramebuffers) {
+ CrossContextGenerationAutoFlushTest<GenFramebuffersAPI>();
+}
+TEST_F(GLES2ImplementationStrictSharedTest,
+ CrossContextGenerationAutoFlushTestRenderbuffers) {
+ CrossContextGenerationAutoFlushTest<GenRenderbuffersAPI>();
+}
+TEST_F(GLES2ImplementationStrictSharedTest,
+ CrossContextGenerationAutoFlushTestTextures) {
+ CrossContextGenerationAutoFlushTest<GenTexturesAPI>();
}
TEST_F(GLES2ImplementationTest, GetString) {
@@ -2480,7 +2809,8 @@ TEST_F(GLES2ImplementationTest, GetString) {
const char* expected_str =
"foobar "
"GL_CHROMIUM_flipy "
- "GL_EXT_unpack_subimage";
+ "GL_EXT_unpack_subimage "
+ "GL_CHROMIUM_map_sub";
const char kBad = 0x12;
struct Cmds {
cmd::SetBucketSize set_bucket_size1;
@@ -2668,9 +2998,6 @@ TEST_F(GLES2ImplementationTest, BeginEndQueryEXT) {
EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
- // Test BeginQueryEXT fails if id not GENed.
- // TODO(gman):
-
// Test BeginQueryEXT inserts command.
struct BeginCmds {
cmds::BeginQueryEXT begin_query;
@@ -2724,7 +3051,7 @@ TEST_F(GLES2ImplementationTest, BeginEndQueryEXT) {
EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
// Test 2nd Begin/End increments count.
- uint32 old_submit_count = query->submit_count();
+ base::subtle::Atomic32 old_submit_count = query->submit_count();
gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, id1);
EXPECT_NE(old_submit_count, query->submit_count());
expected_end_cmds.end_query.Init(
@@ -2758,7 +3085,6 @@ TEST_F(GLES2ImplementationTest, BeginEndQueryEXT) {
// Test GetQueryObjectuivEXT CheckResultsAvailable
ClearCommands();
gl_->GetQueryObjectuivEXT(id1, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
- EXPECT_TRUE(NoCommandsWritten());
EXPECT_EQ(0u, available);
}
@@ -2873,6 +3199,212 @@ TEST_F(GLES2ImplementationTest, Enable) {
EXPECT_TRUE(NoCommandsWritten());
}
+TEST_F(GLES2ImplementationTest, ConsumeTextureCHROMIUM) {
+ struct Cmds {
+ cmds::ConsumeTextureCHROMIUMImmediate cmd;
+ GLbyte data[64];
+ };
+
+ Mailbox mailbox = Mailbox::Generate();
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, mailbox.name);
+ gl_->ConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, CreateAndConsumeTextureCHROMIUM) {
+ struct Cmds {
+ cmds::CreateAndConsumeTextureCHROMIUMImmediate cmd;
+ GLbyte data[64];
+ };
+
+ Mailbox mailbox = Mailbox::Generate();
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, kTexturesStartId, mailbox.name);
+ GLuint id = gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(kTexturesStartId, id);
+}
+
+TEST_F(GLES2ImplementationTest, ProduceTextureCHROMIUM) {
+ struct Cmds {
+ cmds::ProduceTextureCHROMIUMImmediate cmd;
+ GLbyte data[64];
+ };
+
+ Mailbox mailbox = Mailbox::Generate();
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, mailbox.name);
+ gl_->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, ProduceTextureDirectCHROMIUM) {
+ struct Cmds {
+ cmds::ProduceTextureDirectCHROMIUMImmediate cmd;
+ GLbyte data[64];
+ };
+
+ Mailbox mailbox = Mailbox::Generate();
+ Cmds expected;
+ expected.cmd.Init(kTexturesStartId, GL_TEXTURE_2D, mailbox.name);
+ gl_->ProduceTextureDirectCHROMIUM(
+ kTexturesStartId, GL_TEXTURE_2D, mailbox.name);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, LimitSizeAndOffsetTo32Bit) {
+ GLsizeiptr size;
+ GLintptr offset;
+ if (sizeof(size) <= 4 || sizeof(offset) <= 4)
+ return;
+ // The below two casts should be no-op, as we return early if
+ // it's 32-bit system.
+ int64 value64 = 0x100000000;
+ size = static_cast<GLsizeiptr>(value64);
+ offset = static_cast<GLintptr>(value64);
+
+ const char kSizeOverflowMessage[] = "size more than 32-bit";
+ const char kOffsetOverflowMessage[] = "offset more than 32-bit";
+
+ const GLfloat buf[] = { 1.0, 1.0, 1.0, 1.0 };
+ const GLubyte indices[] = { 0 };
+
+ const GLuint kClientArrayBufferId = 0x789;
+ const GLuint kClientElementArrayBufferId = 0x790;
+ gl_->BindBuffer(GL_ARRAY_BUFFER, kClientArrayBufferId);
+ gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, kClientElementArrayBufferId);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+ // Call BufferData() should succeed with legal paramaters.
+ gl_->BufferData(GL_ARRAY_BUFFER, sizeof(buf), buf, GL_DYNAMIC_DRAW);
+ gl_->BufferData(
+ GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+ // BufferData: size
+ gl_->BufferData(GL_ARRAY_BUFFER, size, buf, GL_DYNAMIC_DRAW);
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kSizeOverflowMessage, GetLastError().c_str());
+
+ // Call BufferSubData() should succeed with legal paramaters.
+ gl_->BufferSubData(GL_ARRAY_BUFFER, 0, sizeof(buf[0]), buf);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+ // BufferSubData: offset
+ gl_->BufferSubData(GL_ARRAY_BUFFER, offset, 1, buf);
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
+
+ // BufferSubData: size
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+ gl_->BufferSubData(GL_ARRAY_BUFFER, 0, size, buf);
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kSizeOverflowMessage, GetLastError().c_str());
+
+ // Call MapBufferSubDataCHROMIUM() should succeed with legal paramaters.
+ void* mem =
+ gl_->MapBufferSubDataCHROMIUM(GL_ARRAY_BUFFER, 0, 1, GL_WRITE_ONLY);
+ EXPECT_TRUE(NULL != mem);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+ gl_->UnmapBufferSubDataCHROMIUM(mem);
+
+ // MapBufferSubDataCHROMIUM: offset
+ EXPECT_TRUE(NULL == gl_->MapBufferSubDataCHROMIUM(
+ GL_ARRAY_BUFFER, offset, 1, GL_WRITE_ONLY));
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
+
+ // MapBufferSubDataCHROMIUM: size
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+ EXPECT_TRUE(NULL == gl_->MapBufferSubDataCHROMIUM(
+ GL_ARRAY_BUFFER, 0, size, GL_WRITE_ONLY));
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kSizeOverflowMessage, GetLastError().c_str());
+
+ // Call DrawElements() should succeed with legal paramaters.
+ gl_->DrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, NULL);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+ // DrawElements: offset
+ gl_->DrawElements(
+ GL_POINTS, 1, GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
+
+ // Call DrawElementsInstancedANGLE() should succeed with legal paramaters.
+ gl_->DrawElementsInstancedANGLE(GL_POINTS, 1, GL_UNSIGNED_BYTE, NULL, 1);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+ // DrawElementsInstancedANGLE: offset
+ gl_->DrawElementsInstancedANGLE(
+ GL_POINTS, 1, GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset), 1);
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
+
+ // Call VertexAttribPointer() should succeed with legal paramaters.
+ const GLuint kAttribIndex = 1;
+ const GLsizei kStride = 4;
+ gl_->VertexAttribPointer(
+ kAttribIndex, 1, GL_FLOAT, GL_FALSE, kStride, NULL);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+ // VertexAttribPointer: offset
+ gl_->VertexAttribPointer(
+ kAttribIndex, 1, GL_FLOAT, GL_FALSE, kStride,
+ reinterpret_cast<void*>(offset));
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
+}
+
+TEST_F(GLES2ImplementationManualInitTest, LoseContextOnOOM) {
+ ContextInitOptions init_options;
+ init_options.lose_context_when_out_of_memory = true;
+ ASSERT_TRUE(Initialize(init_options));
+
+ struct Cmds {
+ cmds::LoseContextCHROMIUM cmd;
+ };
+
+ GLsizei max = std::numeric_limits<GLsizei>::max();
+ EXPECT_CALL(*gpu_control_, CreateGpuMemoryBuffer(max, max, _, _, _))
+ .WillOnce(Return(static_cast<gfx::GpuMemoryBuffer*>(NULL)));
+ gl_->CreateImageCHROMIUM(max, max, 0, GL_IMAGE_MAP_CHROMIUM);
+ // The context should be lost.
+ Cmds expected;
+ expected.cmd.Init(GL_GUILTY_CONTEXT_RESET_ARB, GL_UNKNOWN_CONTEXT_RESET_ARB);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationManualInitTest, NoLoseContextOnOOM) {
+ ContextInitOptions init_options;
+ ASSERT_TRUE(Initialize(init_options));
+
+ struct Cmds {
+ cmds::LoseContextCHROMIUM cmd;
+ };
+
+ GLsizei max = std::numeric_limits<GLsizei>::max();
+ EXPECT_CALL(*gpu_control_, CreateGpuMemoryBuffer(max, max, _, _, _))
+ .WillOnce(Return(static_cast<gfx::GpuMemoryBuffer*>(NULL)));
+ gl_->CreateImageCHROMIUM(max, max, 0, GL_IMAGE_MAP_CHROMIUM);
+ // The context should not be lost.
+ EXPECT_TRUE(NoCommandsWritten());
+}
+
+TEST_F(GLES2ImplementationManualInitTest, FailInitOnBGRMismatch1) {
+ ContextInitOptions init_options;
+ init_options.bind_generates_resource_client = false;
+ init_options.bind_generates_resource_service = true;
+ EXPECT_FALSE(Initialize(init_options));
+}
+
+TEST_F(GLES2ImplementationManualInitTest, FailInitOnBGRMismatch2) {
+ ContextInitOptions init_options;
+ init_options.bind_generates_resource_client = true;
+ init_options.bind_generates_resource_service = false;
+ EXPECT_FALSE(Initialize(init_options));
+}
#include "gpu/command_buffer/client/gles2_implementation_unittest_autogen.h"