diff options
author | jbauman@chromium.org <jbauman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-14 03:31:42 +0000 |
---|---|---|
committer | jbauman@chromium.org <jbauman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-14 03:31:42 +0000 |
commit | c6aef90f9f927ac75bb99d6d77782fc33c37769d (patch) | |
tree | a9e1c0067cba88556eff8541dfd87b09acd0a16c /gpu | |
parent | 2e3d9e4cd2b473f6f6a53999c6af0b1e50c3fa5d (diff) | |
download | chromium_src-c6aef90f9f927ac75bb99d6d77782fc33c37769d.zip chromium_src-c6aef90f9f927ac75bb99d6d77782fc33c37769d.tar.gz chromium_src-c6aef90f9f927ac75bb99d6d77782fc33c37769d.tar.bz2 |
Add support for ANGLE_instanced_arrays
We require ARB_instanced_arrays or ANGLE_intanced_arrays to support this.
BUG=93148
TEST=
Review URL: http://codereview.chromium.org/9374006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@121838 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
22 files changed, 1416 insertions, 54 deletions
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index b2128fc..3c88826 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -1492,6 +1492,27 @@ _FUNCTION_INFO = { 'extension': True, 'decoder_func': 'DoTexStorage2DEXT', }, + 'DrawArraysInstancedANGLE': { + 'type': 'Manual', + 'cmd_args': 'GLenumDrawMode mode, GLint first, GLsizei count, ' + 'GLsizei primcount', + 'extension': True, + 'unit_test': False, + }, + 'DrawElementsInstancedANGLE': { + 'type': 'Manual', + 'cmd_args': 'GLenumDrawMode mode, GLsizei count, ' + 'GLenumIndexType type, GLuint index_offset, GLsizei primcount', + 'extension': True, + 'unit_test': False, + 'client_test': False, + }, + 'VertexAttribDivisorANGLE': { + 'type': 'Manual', + 'cmd_args': 'GLuint index, GLuint divisor', + 'extension': True, + 'unit_test': False, + }, } diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h index 9cef90b..f4f7e11 100644 --- a/gpu/command_buffer/client/gles2_c_lib_autogen.h +++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h @@ -601,6 +601,20 @@ void GLES2TexImageIOSurface2DCHROMIUM( gles2::GetGLContext()->TexImageIOSurface2DCHROMIUM( target, width, height, ioSurfaceId, plane); } +void GLES2DrawArraysInstancedANGLE( + GLenum mode, GLint first, GLsizei count, GLsizei primcount) { + gles2::GetGLContext()->DrawArraysInstancedANGLE( + mode, first, count, primcount); +} +void GLES2DrawElementsInstancedANGLE( + GLenum mode, GLsizei count, GLenum type, const void* indices, + GLsizei primcount) { + gles2::GetGLContext()->DrawElementsInstancedANGLE( + mode, count, type, indices, primcount); +} +void GLES2VertexAttribDivisorANGLE(GLuint index, GLuint divisor) { + gles2::GetGLContext()->VertexAttribDivisorANGLE(index, divisor); +} #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_C_LIB_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h index e01be22..abaca98 100644 --- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h +++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h @@ -1667,5 +1667,32 @@ } } + void DrawArraysInstancedANGLE( + GLenum mode, GLint first, GLsizei count, GLsizei primcount) { + gles2::DrawArraysInstancedANGLE* c = + GetCmdSpace<gles2::DrawArraysInstancedANGLE>(); + if (c) { + c->Init(mode, first, count, primcount); + } + } + + void DrawElementsInstancedANGLE( + GLenum mode, GLsizei count, GLenum type, GLuint index_offset, + GLsizei primcount) { + gles2::DrawElementsInstancedANGLE* c = + GetCmdSpace<gles2::DrawElementsInstancedANGLE>(); + if (c) { + c->Init(mode, count, type, index_offset, primcount); + } + } + + void VertexAttribDivisorANGLE(GLuint index, GLuint divisor) { + gles2::VertexAttribDivisorANGLE* c = + GetCmdSpace<gles2::VertexAttribDivisorANGLE>(); + if (c) { + c->Init(index, divisor); + } + } + #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 8f1e415..c58b38c 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -264,7 +264,8 @@ class ClientSideBufferHelper { type_(GL_FLOAT), normalized_(GL_FALSE), pointer_(NULL), - gl_stride_(0) { + gl_stride_(0), + divisor_(0) { } bool enabled() const { @@ -303,6 +304,10 @@ class ClientSideBufferHelper { return buffer_id_ == 0; } + GLuint divisor() const { + return divisor_; + } + void SetInfo( GLuint buffer_id, GLint size, @@ -318,6 +323,10 @@ class ClientSideBufferHelper { pointer_ = pointer; } + void SetDivisor(GLuint divisor) { + divisor_ = divisor; + } + private: // Whether or not this attribute is enabled. bool enabled_; @@ -340,6 +349,9 @@ class ClientSideBufferHelper { // The stride that will be used to access the buffer. This is the bogus GL // stride where 0 = compute the stride based on size and type. GLsizei gl_stride_; + + // Divisor, for geometry instancing. + GLuint divisor_; }; ClientSideBufferHelper(GLuint max_vertex_attribs, @@ -390,6 +402,14 @@ class ClientSideBufferHelper { } } + void SetAttribDivisor(GLuint index, GLuint divisor) { + if (index < max_vertex_attribs_) { + VertexAttribInfo& info = vertex_attrib_infos_[index]; + + info.SetDivisor(divisor); + } + } + // Gets the Attrib pointer for an attrib but only if it's a client side // pointer. Returns true if it got the pointer. bool GetAttribPointer(GLuint index, GLenum pname, void** ptr) const { @@ -436,7 +456,8 @@ class ClientSideBufferHelper { void SetupSimulatedClientSideBuffers( GLES2Implementation* gl, GLES2CmdHelper* gl_helper, - GLsizei num_elements) { + GLsizei num_elements, + GLsizei primcount) { GLsizei total_size = 0; // Compute the size of the buffer we need. for (GLuint ii = 0; ii < max_vertex_attribs_; ++ii) { @@ -445,8 +466,10 @@ class ClientSideBufferHelper { size_t bytes_per_element = GLES2Util::GetGLTypeSizeForTexturesAndBuffers(info.type()) * info.size(); + GLsizei elements = (primcount && info.divisor() > 0) ? + ((primcount - 1) / info.divisor() + 1) : num_elements; total_size += RoundUpToMultipleOf4( - bytes_per_element * num_elements); + bytes_per_element * elements); } } gl_helper->BindBuffer(GL_ARRAY_BUFFER, array_buffer_id_); @@ -463,8 +486,10 @@ class ClientSideBufferHelper { info.size(); GLsizei real_stride = info.stride() ? info.stride() : static_cast<GLsizei>(bytes_per_element); + GLsizei elements = (primcount && info.divisor() > 0) ? + ((primcount - 1) / info.divisor() + 1) : num_elements; GLsizei bytes_collected = CollectData( - info.pointer(), bytes_per_element, real_stride, num_elements); + info.pointer(), bytes_per_element, real_stride, elements); gl->BufferSubDataHelper( GL_ARRAY_BUFFER, array_buffer_offset_, bytes_collected, collection_buffer_.get()); @@ -1057,7 +1082,7 @@ void GLES2Implementation::DrawElements( } if (have_client_side) { client_side_buffer_helper_->SetupSimulatedClientSideBuffers( - this, helper_, num_elements); + this, helper_, num_elements, 0); } helper_->DrawElements(mode, count, type, offset); if (have_client_side) { @@ -1417,6 +1442,19 @@ void GLES2Implementation::VertexAttribPointer( #endif // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) } +void GLES2Implementation::VertexAttribDivisorANGLE( + GLuint index, GLuint divisor) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << this << "] glVertexAttribDivisorANGLE(" + << index << ", " + << divisor << ") "); +#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) + // Record the info on the client side. + client_side_buffer_helper_->SetAttribDivisor(index, divisor); +#endif // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) + helper_->VertexAttribDivisorANGLE(index, divisor); +} + void GLES2Implementation::ShaderSource( GLuint shader, GLsizei count, const char** source, const GLint* length) { GPU_CLIENT_SINGLE_THREAD_CHECK(); @@ -2464,7 +2502,7 @@ void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) { client_side_buffer_helper_->HaveEnabledClientSideBuffers(); if (have_client_side) { client_side_buffer_helper_->SetupSimulatedClientSideBuffers( - this, helper_, first + count); + this, helper_, first + count, 0); } #endif helper_->DrawArrays(mode, first, count); @@ -2931,5 +2969,106 @@ void GLES2Implementation::PostSubBufferCHROMIUM( } } +void GLES2Implementation::DrawArraysInstancedANGLE( + GLenum mode, GLint first, GLsizei count, GLsizei primcount) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << this << "] glDrawArraysInstancedANGLE(" + << GLES2Util::GetStringDrawMode(mode) << ", " + << first << ", " << count << ", " << primcount << ")"); + if (count < 0) { + SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE: count < 0"); + return; + } + if (primcount < 0) { + SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE: primcount < 0"); + return; + } + if (primcount == 0) { + return; + } +#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) + bool have_client_side = + client_side_buffer_helper_->HaveEnabledClientSideBuffers(); + if (have_client_side) { + client_side_buffer_helper_->SetupSimulatedClientSideBuffers( + this, helper_, first + count, primcount); + } +#endif + helper_->DrawArraysInstancedANGLE(mode, first, count, primcount); +#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) + if (have_client_side) { + // Restore the user's current binding. + helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_); + } +#endif +} + +void GLES2Implementation::DrawElementsInstancedANGLE( + GLenum mode, GLsizei count, GLenum type, const void* indices, + GLsizei primcount) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << this << "] glDrawElementsInstancedANGLE(" + << GLES2Util::GetStringDrawMode(mode) << ", " + << count << ", " + << GLES2Util::GetStringIndexType(type) << ", " + << static_cast<const void*>(indices) << ", " + << primcount << ")"); + if (count < 0) { + SetGLError(GL_INVALID_VALUE, + "glDrawElementsInstancedANGLE: count less than 0."); + return; + } + if (count == 0) { + return; + } + if (primcount < 0) { + SetGLError(GL_INVALID_VALUE, + "glDrawElementsInstancedANGLE: primcount < 0"); + return; + } + if (primcount == 0) { + return; + } +#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) + bool have_client_side = + client_side_buffer_helper_->HaveEnabledClientSideBuffers(); + GLsizei num_elements = 0; + GLuint offset = ToGLuint(indices); + if (bound_element_array_buffer_id_ == 0) { + // Index buffer is client side array. + // Copy to buffer, scan for highest index. + num_elements = client_side_buffer_helper_->SetupSimulatedIndexBuffer( + this, helper_, count, type, indices); + offset = 0; + } else { + // Index buffer is GL buffer. Ask the service for the highest vertex + // that will be accessed. Note: It doesn't matter if another context + // changes the contents of any of the buffers. The service will still + // validate the indices. We just need to know how much to copy across. + if (have_client_side) { + num_elements = GetMaxValueInBufferCHROMIUMHelper( + bound_element_array_buffer_id_, count, type, ToGLuint(indices)) + 1; + } + } + if (have_client_side) { + client_side_buffer_helper_->SetupSimulatedClientSideBuffers( + this, helper_, num_elements, primcount); + } + helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount); + if (have_client_side) { + // Restore the user's current binding. + helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_); + } + if (bound_element_array_buffer_id_ == 0) { + // Restore the element array binding. + helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } +#else + helper_->DrawElementsInstancedANGLE( + mode, count, type, ToGLuint(indices), primcount); +#endif +} + + } // namespace gles2 } // namespace gpu diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index 6686a0a..abf2d5b 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h @@ -1499,5 +1499,14 @@ void TexImageIOSurface2DCHROMIUM( target, width, height, ioSurfaceId, plane); } +void DrawArraysInstancedANGLE( + GLenum mode, GLint first, GLsizei count, GLsizei primcount); + +void DrawElementsInstancedANGLE( + GLenum mode, GLsizei count, GLenum type, const void* indices, + GLsizei primcount); + +void VertexAttribDivisorANGLE(GLuint index, GLuint divisor); + #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index c354e9e..feeebbb 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc @@ -671,6 +671,76 @@ TEST_F(GLES2ImplementationTest, DrawArraysClientSideBuffers) { EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } +TEST_F(GLES2ImplementationTest, DrawArraysInstancedANGLEClientSideBuffers) { + static const float verts[][4] = { + { 12.0f, 23.0f, 34.0f, 45.0f, }, + { 56.0f, 67.0f, 78.0f, 89.0f, }, + { 13.0f, 24.0f, 35.0f, 46.0f, }, + }; + struct Cmds { + EnableVertexAttribArray enable1; + EnableVertexAttribArray enable2; + VertexAttribDivisorANGLE divisor; + BindBuffer bind_to_emu; + BufferData set_size; + BufferSubData copy_data1; + cmd::SetToken set_token1; + VertexAttribPointer set_pointer1; + BufferSubData copy_data2; + cmd::SetToken set_token2; + VertexAttribPointer set_pointer2; + DrawArraysInstancedANGLE draw; + BindBuffer restore; + }; + const GLuint kEmuBufferId = GLES2Implementation::kClientSideArrayId; + const GLuint kAttribIndex1 = 1; + const GLuint kAttribIndex2 = 3; + const GLint kNumComponents1 = 3; + const GLint kNumComponents2 = 2; + const GLsizei kClientStride = sizeof(verts[0]); + const GLint kFirst = 1; + const GLsizei kCount = 2; + const GLuint kDivisor = 1; + const GLsizei kSize1 = + arraysize(verts) * kNumComponents1 * sizeof(verts[0][0]); + const GLsizei kSize2 = + 1 * kNumComponents2 * sizeof(verts[0][0]); + const GLsizei kEmuOffset1 = 0; + const GLsizei kEmuOffset2 = kSize1; + const GLsizei kTotalSize = kSize1 + kSize2; + + ExpectedMemoryInfo mem1 = GetExpectedMemory(kSize1); + ExpectedMemoryInfo mem2 = GetExpectedMemory(kSize2); + + Cmds expected; + expected.enable1.Init(kAttribIndex1); + expected.enable2.Init(kAttribIndex2); + expected.divisor.Init(kAttribIndex2, kDivisor); + expected.bind_to_emu.Init(GL_ARRAY_BUFFER, kEmuBufferId); + expected.set_size.Init(GL_ARRAY_BUFFER, kTotalSize, 0, 0, GL_DYNAMIC_DRAW); + expected.copy_data1.Init( + GL_ARRAY_BUFFER, kEmuOffset1, kSize1, mem1.id, mem1.offset); + expected.set_token1.Init(GetNextToken()); + expected.set_pointer1.Init( + kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, 0, kEmuOffset1); + expected.copy_data2.Init( + GL_ARRAY_BUFFER, kEmuOffset2, kSize2, mem2.id, mem2.offset); + expected.set_token2.Init(GetNextToken()); + expected.set_pointer2.Init( + kAttribIndex2, kNumComponents2, GL_FLOAT, GL_FALSE, 0, kEmuOffset2); + expected.draw.Init(GL_POINTS, kFirst, kCount, 1); + expected.restore.Init(GL_ARRAY_BUFFER, 0); + gl_->EnableVertexAttribArray(kAttribIndex1); + gl_->EnableVertexAttribArray(kAttribIndex2); + gl_->VertexAttribPointer( + kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, kClientStride, verts); + gl_->VertexAttribPointer( + kAttribIndex2, kNumComponents2, GL_FLOAT, GL_FALSE, kClientStride, verts); + gl_->VertexAttribDivisorANGLE(kAttribIndex2, kDivisor); + gl_->DrawArraysInstancedANGLE(GL_POINTS, kFirst, kCount, 1); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + TEST_F(GLES2ImplementationTest, DrawElementsClientSideBuffers) { static const float verts[][4] = { { 12.0f, 23.0f, 34.0f, 45.0f, }, @@ -838,6 +908,95 @@ TEST_F(GLES2ImplementationTest, EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } +TEST_F(GLES2ImplementationTest, DrawElementsInstancedANGLEClientSideBuffers) { + static const float verts[][4] = { + { 12.0f, 23.0f, 34.0f, 45.0f, }, + { 56.0f, 67.0f, 78.0f, 89.0f, }, + { 13.0f, 24.0f, 35.0f, 46.0f, }, + }; + static const uint16 indices[] = { + 1, 2, + }; + struct Cmds { + EnableVertexAttribArray enable1; + EnableVertexAttribArray enable2; + VertexAttribDivisorANGLE divisor; + BindBuffer bind_to_index_emu; + BufferData set_index_size; + BufferSubData copy_data0; + cmd::SetToken set_token0; + BindBuffer bind_to_emu; + BufferData set_size; + BufferSubData copy_data1; + cmd::SetToken set_token1; + VertexAttribPointer set_pointer1; + BufferSubData copy_data2; + cmd::SetToken set_token2; + VertexAttribPointer set_pointer2; + DrawElementsInstancedANGLE draw; + BindBuffer restore; + BindBuffer restore_element; + }; + const GLsizei kIndexSize = sizeof(indices); + const GLuint kEmuBufferId = GLES2Implementation::kClientSideArrayId; + const GLuint kEmuIndexBufferId = + GLES2Implementation::kClientSideElementArrayId; + const GLuint kAttribIndex1 = 1; + const GLuint kAttribIndex2 = 3; + const GLint kNumComponents1 = 3; + const GLint kNumComponents2 = 2; + const GLsizei kClientStride = sizeof(verts[0]); + const GLsizei kCount = 2; + const GLsizei kSize1 = + arraysize(verts) * kNumComponents1 * sizeof(verts[0][0]); + const GLsizei kSize2 = + 1 * kNumComponents2 * sizeof(verts[0][0]); + const GLuint kDivisor = 1; + const GLsizei kEmuOffset1 = 0; + const GLsizei kEmuOffset2 = kSize1; + const GLsizei kTotalSize = kSize1 + kSize2; + + ExpectedMemoryInfo mem1 = GetExpectedMemory(kIndexSize); + ExpectedMemoryInfo mem2 = GetExpectedMemory(kSize1); + ExpectedMemoryInfo mem3 = GetExpectedMemory(kSize2); + + Cmds expected; + expected.enable1.Init(kAttribIndex1); + expected.enable2.Init(kAttribIndex2); + expected.divisor.Init(kAttribIndex2, kDivisor); + expected.bind_to_index_emu.Init(GL_ELEMENT_ARRAY_BUFFER, kEmuIndexBufferId); + expected.set_index_size.Init( + GL_ELEMENT_ARRAY_BUFFER, kIndexSize, 0, 0, GL_DYNAMIC_DRAW); + expected.copy_data0.Init( + GL_ELEMENT_ARRAY_BUFFER, 0, kIndexSize, mem1.id, mem1.offset); + expected.set_token0.Init(GetNextToken()); + expected.bind_to_emu.Init(GL_ARRAY_BUFFER, kEmuBufferId); + expected.set_size.Init(GL_ARRAY_BUFFER, kTotalSize, 0, 0, GL_DYNAMIC_DRAW); + expected.copy_data1.Init( + GL_ARRAY_BUFFER, kEmuOffset1, kSize1, mem2.id, mem2.offset); + expected.set_token1.Init(GetNextToken()); + expected.set_pointer1.Init( + kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, 0, kEmuOffset1); + expected.copy_data2.Init( + GL_ARRAY_BUFFER, kEmuOffset2, kSize2, mem3.id, mem3.offset); + expected.set_token2.Init(GetNextToken()); + expected.set_pointer2.Init(kAttribIndex2, kNumComponents2, + GL_FLOAT, GL_FALSE, 0, kEmuOffset2); + expected.draw.Init(GL_POINTS, kCount, GL_UNSIGNED_SHORT, 0, 1); + expected.restore.Init(GL_ARRAY_BUFFER, 0); + expected.restore_element.Init(GL_ELEMENT_ARRAY_BUFFER, 0); + gl_->EnableVertexAttribArray(kAttribIndex1); + gl_->EnableVertexAttribArray(kAttribIndex2); + gl_->VertexAttribPointer(kAttribIndex1, kNumComponents1, + GL_FLOAT, GL_FALSE, kClientStride, verts); + gl_->VertexAttribPointer(kAttribIndex2, kNumComponents2, + GL_FLOAT, GL_FALSE, kClientStride, verts); + gl_->VertexAttribDivisorANGLE(kAttribIndex2, kDivisor); + gl_->DrawElementsInstancedANGLE( + GL_POINTS, kCount, GL_UNSIGNED_SHORT, indices, 1); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + TEST_F(GLES2ImplementationTest, GetVertexBufferPointerv) { static const float verts[1] = { 0.0f, }; const GLuint kAttribIndex1 = 1; diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h index fae58d97..8b6bdb1 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h @@ -1602,5 +1602,27 @@ TEST_F(GLES2ImplementationTest, TexImageIOSurface2DCHROMIUM) { gl_->TexImageIOSurface2DCHROMIUM(GL_TEXTURE_2D, 2, 3, 4, 5); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } + +TEST_F(GLES2ImplementationTest, DrawArraysInstancedANGLE) { + struct Cmds { + DrawArraysInstancedANGLE cmd; + }; + Cmds expected; + expected.cmd.Init(GL_POINTS, 2, 3, 4); + + gl_->DrawArraysInstancedANGLE(GL_POINTS, 2, 3, 4); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +TEST_F(GLES2ImplementationTest, VertexAttribDivisorANGLE) { + struct Cmds { + VertexAttribDivisorANGLE cmd; + }; + Cmds expected; + expected.cmd.Init(1, 2); + + gl_->VertexAttribDivisorANGLE(1, 2); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_UNITTEST_AUTOGEN_H_ diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt index 26484ec..4713e11 100644 --- a/gpu/command_buffer/cmd_buffer_functions.txt +++ b/gpu/command_buffer/cmd_buffer_functions.txt @@ -171,4 +171,7 @@ GL_APICALL void GL_APIENTRY glDestroyStreamTextureCHROMIUM (GLuint textu GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLidShader shader, GLsizeiNotNegative bufsize, GLsizei* length, char* source); GL_APICALL void GL_APIENTRY glPostSubBufferCHROMIUM (GLint x, GLint y, GLint width, GLint height); GL_APICALL void GL_APIENTRY glTexImageIOSurface2DCHROMIUM (GLenumTextureBindTarget target, GLsizei width, GLsizei height, GLuint ioSurfaceId, GLuint plane); +GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE (GLenumDrawMode mode, GLint first, GLsizei count, GLsizei primcount); +GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE (GLenumDrawMode mode, GLsizei count, GLenumIndexType type, const void* indices, GLsizei primcount); +GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE (GLuint index, GLuint divisor); diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h index 34d266c..c3f4c4d 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h @@ -9261,6 +9261,147 @@ COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, ioSurfaceId) == 16, COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, plane) == 20, OffsetOf_TexImageIOSurface2DCHROMIUM_plane_not_20); +struct DrawArraysInstancedANGLE { + typedef DrawArraysInstancedANGLE ValueType; + static const CommandId kCmdId = kDrawArraysInstancedANGLE; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + + static uint32 ComputeSize() { + return static_cast<uint32>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { + header.SetCmd<ValueType>(); + } + + void Init(GLenum _mode, GLint _first, GLsizei _count, GLsizei _primcount) { + SetHeader(); + mode = _mode; + first = _first; + count = _count; + primcount = _primcount; + } + + void* Set( + void* cmd, GLenum _mode, GLint _first, GLsizei _count, + GLsizei _primcount) { + static_cast<ValueType*>(cmd)->Init(_mode, _first, _count, _primcount); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32 mode; + int32 first; + int32 count; + int32 primcount; +}; + +COMPILE_ASSERT(sizeof(DrawArraysInstancedANGLE) == 20, + Sizeof_DrawArraysInstancedANGLE_is_not_20); +COMPILE_ASSERT(offsetof(DrawArraysInstancedANGLE, header) == 0, + OffsetOf_DrawArraysInstancedANGLE_header_not_0); +COMPILE_ASSERT(offsetof(DrawArraysInstancedANGLE, mode) == 4, + OffsetOf_DrawArraysInstancedANGLE_mode_not_4); +COMPILE_ASSERT(offsetof(DrawArraysInstancedANGLE, first) == 8, + OffsetOf_DrawArraysInstancedANGLE_first_not_8); +COMPILE_ASSERT(offsetof(DrawArraysInstancedANGLE, count) == 12, + OffsetOf_DrawArraysInstancedANGLE_count_not_12); +COMPILE_ASSERT(offsetof(DrawArraysInstancedANGLE, primcount) == 16, + OffsetOf_DrawArraysInstancedANGLE_primcount_not_16); + +struct DrawElementsInstancedANGLE { + typedef DrawElementsInstancedANGLE ValueType; + static const CommandId kCmdId = kDrawElementsInstancedANGLE; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + + static uint32 ComputeSize() { + return static_cast<uint32>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { + header.SetCmd<ValueType>(); + } + + void Init( + GLenum _mode, GLsizei _count, GLenum _type, GLuint _index_offset, + GLsizei _primcount) { + SetHeader(); + mode = _mode; + count = _count; + type = _type; + index_offset = _index_offset; + primcount = _primcount; + } + + void* Set( + void* cmd, GLenum _mode, GLsizei _count, GLenum _type, + GLuint _index_offset, GLsizei _primcount) { + static_cast<ValueType*>( + cmd)->Init(_mode, _count, _type, _index_offset, _primcount); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32 mode; + int32 count; + uint32 type; + uint32 index_offset; + int32 primcount; +}; + +COMPILE_ASSERT(sizeof(DrawElementsInstancedANGLE) == 24, + Sizeof_DrawElementsInstancedANGLE_is_not_24); +COMPILE_ASSERT(offsetof(DrawElementsInstancedANGLE, header) == 0, + OffsetOf_DrawElementsInstancedANGLE_header_not_0); +COMPILE_ASSERT(offsetof(DrawElementsInstancedANGLE, mode) == 4, + OffsetOf_DrawElementsInstancedANGLE_mode_not_4); +COMPILE_ASSERT(offsetof(DrawElementsInstancedANGLE, count) == 8, + OffsetOf_DrawElementsInstancedANGLE_count_not_8); +COMPILE_ASSERT(offsetof(DrawElementsInstancedANGLE, type) == 12, + OffsetOf_DrawElementsInstancedANGLE_type_not_12); +COMPILE_ASSERT(offsetof(DrawElementsInstancedANGLE, index_offset) == 16, + OffsetOf_DrawElementsInstancedANGLE_index_offset_not_16); +COMPILE_ASSERT(offsetof(DrawElementsInstancedANGLE, primcount) == 20, + OffsetOf_DrawElementsInstancedANGLE_primcount_not_20); + +struct VertexAttribDivisorANGLE { + typedef VertexAttribDivisorANGLE ValueType; + static const CommandId kCmdId = kVertexAttribDivisorANGLE; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + + static uint32 ComputeSize() { + return static_cast<uint32>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { + header.SetCmd<ValueType>(); + } + + void Init(GLuint _index, GLuint _divisor) { + SetHeader(); + index = _index; + divisor = _divisor; + } + + void* Set(void* cmd, GLuint _index, GLuint _divisor) { + static_cast<ValueType*>(cmd)->Init(_index, _divisor); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32 index; + uint32 divisor; +}; + +COMPILE_ASSERT(sizeof(VertexAttribDivisorANGLE) == 12, + Sizeof_VertexAttribDivisorANGLE_is_not_12); +COMPILE_ASSERT(offsetof(VertexAttribDivisorANGLE, header) == 0, + OffsetOf_VertexAttribDivisorANGLE_header_not_0); +COMPILE_ASSERT(offsetof(VertexAttribDivisorANGLE, index) == 4, + OffsetOf_VertexAttribDivisorANGLE_index_not_4); +COMPILE_ASSERT(offsetof(VertexAttribDivisorANGLE, divisor) == 8, + OffsetOf_VertexAttribDivisorANGLE_divisor_not_8); + #endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_AUTOGEN_H_ diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h index 7e3efb8..5b0dceb 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h @@ -3599,5 +3599,60 @@ TEST_F(GLES2FormatTest, TexImageIOSurface2DCHROMIUM) { next_cmd, sizeof(cmd)); } +TEST_F(GLES2FormatTest, DrawArraysInstancedANGLE) { + DrawArraysInstancedANGLE& cmd = *GetBufferAs<DrawArraysInstancedANGLE>(); + void* next_cmd = cmd.Set( + &cmd, + static_cast<GLenum>(11), + static_cast<GLint>(12), + static_cast<GLsizei>(13), + static_cast<GLsizei>(14)); + EXPECT_EQ(static_cast<uint32>(DrawArraysInstancedANGLE::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLenum>(11), cmd.mode); + EXPECT_EQ(static_cast<GLint>(12), cmd.first); + EXPECT_EQ(static_cast<GLsizei>(13), cmd.count); + EXPECT_EQ(static_cast<GLsizei>(14), cmd.primcount); + CheckBytesWrittenMatchesExpectedSize( + next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, DrawElementsInstancedANGLE) { + DrawElementsInstancedANGLE& cmd = *GetBufferAs<DrawElementsInstancedANGLE>(); + void* next_cmd = cmd.Set( + &cmd, + static_cast<GLenum>(11), + static_cast<GLsizei>(12), + static_cast<GLenum>(13), + static_cast<GLuint>(14), + static_cast<GLsizei>(15)); + EXPECT_EQ(static_cast<uint32>(DrawElementsInstancedANGLE::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLenum>(11), cmd.mode); + EXPECT_EQ(static_cast<GLsizei>(12), cmd.count); + EXPECT_EQ(static_cast<GLenum>(13), cmd.type); + EXPECT_EQ(static_cast<GLuint>(14), cmd.index_offset); + EXPECT_EQ(static_cast<GLsizei>(15), cmd.primcount); + CheckBytesWrittenMatchesExpectedSize( + next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, VertexAttribDivisorANGLE) { + VertexAttribDivisorANGLE& cmd = *GetBufferAs<VertexAttribDivisorANGLE>(); + void* next_cmd = cmd.Set( + &cmd, + static_cast<GLuint>(11), + static_cast<GLuint>(12)); + EXPECT_EQ(static_cast<uint32>(VertexAttribDivisorANGLE::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLuint>(11), cmd.index); + EXPECT_EQ(static_cast<GLuint>(12), cmd.divisor); + CheckBytesWrittenMatchesExpectedSize( + next_cmd, sizeof(cmd)); +} + #endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_TEST_AUTOGEN_H_ diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h index a57c0cd..5d64dcf 100644 --- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h @@ -212,6 +212,9 @@ OP(GetTranslatedShaderSourceANGLE) /* 455 */ \ OP(PostSubBufferCHROMIUM) /* 456 */ \ OP(TexImageIOSurface2DCHROMIUM) /* 457 */ \ + OP(DrawArraysInstancedANGLE) /* 458 */ \ + OP(DrawElementsInstancedANGLE) /* 459 */ \ + OP(VertexAttribDivisorANGLE) /* 460 */ \ enum CommandId { kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this. diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h index 2a660eb..f652a3f 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h @@ -12,17 +12,20 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x8825, "GL_DRAW_BUFFER0_NV", }, { 0x0BC1, "GL_ALPHA_TEST_FUNC_QCOM", }, - { 0x0BC0, "GL_ALPHA_TEST_QCOM", }, + { 0x884C, "GL_TEXTURE_COMPARE_MODE_EXT", }, { 0x0BC2, "GL_ALPHA_TEST_REF_QCOM", }, + { 0x884D, "GL_TEXTURE_COMPARE_FUNC_EXT", }, + { 0x884E, "GL_COMPARE_REF_TO_TEXTURE_EXT", }, { 0x1E01, "GL_REPLACE", }, { 0, "GL_FALSE", }, { 0x00400000, "GL_STENCIL_BUFFER_BIT6_QCOM", }, { 0x9130, "GL_SGX_PROGRAM_BINARY_IMG", }, - { 0x9133, "GL_RENDERBUFFER_SAMPLES_IMG", }, - { 0x9135, "GL_MAX_SAMPLES_IMG", }, - { 0x9134, "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG", }, + { 0x9133, "GL_RENDERBUFFER_SAMPLES_EXT", }, + { 0x9135, "GL_MAX_SAMPLES_EXT", }, + { 0x9134, "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT", }, { 0x9136, "GL_TEXTURE_SAMPLES_IMG", }, { 0x00000020, "GL_COLOR_BUFFER_BIT5_QCOM", }, + { 0x0BC0, "GL_ALPHA_TEST_QCOM", }, { 0x0006, "GL_TRIANGLE_FAN", }, { 0x0004, "GL_TRIANGLES", }, { 0x0005, "GL_TRIANGLE_STRIP", }, @@ -32,6 +35,8 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x0001, "GL_LINES", }, { 0x88B8, "GL_READ_ONLY", }, { 0x88B9, "GL_WRITE_ONLY_OES", }, + { 0x8211, "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT", }, + { 0x8210, "GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT", }, { 0x8741, "GL_PROGRAM_BINARY_LENGTH_OES", }, { 0x8740, "GL_Z400_BINARY_AMD", }, { 0x8192, "GL_GENERATE_MIPMAP_HINT", }, @@ -54,6 +59,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x806A, "GL_TEXTURE_BINDING_3D_OES", }, { 0x8CE3, "GL_COLOR_ATTACHMENT3_NV", }, { 0x8069, "GL_TEXTURE_BINDING_2D", }, + { 0x8261, "GL_NO_RESET_NOTIFICATION_EXT", }, { 0x8DFA, "GL_SHADER_COMPILER", }, { 0x8DFB, "GL_MAX_VERTEX_UNIFORM_VECTORS", }, { 0x8DFC, "GL_MAX_VARYING_VECTORS", }, @@ -72,6 +78,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x0C11, "GL_SCISSOR_TEST", }, { 0x80000000, "GL_MULTISAMPLE_BUFFER_BIT7_QCOM", }, { 0x02000000, "GL_MULTISAMPLE_BUFFER_BIT1_QCOM", }, + { 0x8C2F, "GL_ANY_SAMPLES_PASSED_EXT", }, { 0x8BD2, "GL_TEXTURE_WIDTH_QCOM", }, { 0x8BD3, "GL_TEXTURE_HEIGHT_QCOM", }, { 0x8BD4, "GL_TEXTURE_DEPTH_QCOM", }, @@ -113,9 +120,13 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x81A5, "GL_DEPTH_COMPONENT16", }, { 0x81A6, "GL_DEPTH_COMPONENT24_OES", }, { 0x81A7, "GL_DEPTH_COMPONENT32_OES", }, + { 0x88FE, "GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE", }, { 0x8DFD, "GL_MAX_FRAGMENT_UNIFORM_VECTORS", }, { 0x8F60, "GL_MALI_SHADER_BINARY_ARM", }, { 0x87EE, "GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD", }, + { 0x822B, "GL_RG8_EXT", }, + { 0x822F, "GL_RG16F_EXT", }, + { 0x822D, "GL_R16F_EXT", }, { 1, "GL_ES_VERSION_2_0", }, { 0x84F9, "GL_DEPTH_STENCIL_OES", }, { 0x8368, "GL_UNSIGNED_INT_2_10_10_10_REV_EXT", }, @@ -135,6 +146,9 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x84FE, "GL_TEXTURE_MAX_ANISOTROPY_EXT", }, { 0x0901, "GL_CCW", }, { 0x0900, "GL_CW", }, + { 0x8229, "GL_R8_EXT", }, + { 0x8227, "GL_RG_EXT", }, + { 0x8B62, "GL_SAMPLER_2D_SHADOW_EXT", }, { 0x8B63, "GL_SAMPLER_2D_RECT_ARB", }, { 0x8B60, "GL_SAMPLER_CUBE", }, { 0x00001000, "GL_DEPTH_BUFFER_BIT4_QCOM", }, @@ -164,6 +178,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x0302, "GL_SRC_ALPHA", }, { 0x0308, "GL_SRC_ALPHA_SATURATE", }, { 0x2A00, "GL_POLYGON_OFFSET_UNITS", }, + { 0xFFFFFFFF, "GL_ALL_SHADER_BITS_EXT", }, { 0x00800000, "GL_STENCIL_BUFFER_BIT7_QCOM", }, { 0x00020000, "GL_STENCIL_BUFFER_BIT1_QCOM", }, { 0x8D00, "GL_DEPTH_ATTACHMENT", }, @@ -173,13 +188,17 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x84F3, "GL_FENCE_STATUS_NV", }, { 0x8CDD, "GL_FRAMEBUFFER_UNSUPPORTED", }, { 0x8CDF, "GL_MAX_COLOR_ATTACHMENTS_NV", }, + { 0x90F3, "GL_CONTEXT_ROBUST_ACCESS_EXT", }, { 0x803C, "GL_ALPHA8_EXT", }, { 0x84F5, "GL_TEXTURE_RECTANGLE_ARB", }, { 0x882A, "GL_DRAW_BUFFER5_NV", }, { 0x80AA, "GL_SAMPLE_COVERAGE_VALUE", }, { 0x84F6, "GL_TEXTURE_BINDING_RECTANGLE_ARB", }, { 0x80AB, "GL_SAMPLE_COVERAGE_INVERT", }, + { 0x8FC4, "GL_SHADER_BINARY_VIV", }, { 0x882B, "GL_DRAW_BUFFER6_NV", }, + { 0x8C17, "GL_UNSIGNED_NORMALIZED_EXT", }, + { 0x8A4F, "GL_PROGRAM_PIPELINE_OBJECT_EXT", }, { 0x882C, "GL_DRAW_BUFFER7_NV", }, { 0x84FF, "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT", }, { 0x0B74, "GL_DEPTH_FUNC", }, @@ -248,8 +267,11 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x886A, "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED", }, { 0x9250, "GL_SHADER_BINARY_DMP", }, { 0x10000000, "GL_MULTISAMPLE_BUFFER_BIT4_QCOM", }, - { 0x00000002, "GL_COLOR_BUFFER_BIT1_QCOM", }, - { 0x00000001, "GL_COLOR_BUFFER_BIT0_QCOM", }, + { 0x9154, "GL_VERTEX_ARRAY_OBJECT_EXT", }, + { 0x9153, "GL_QUERY_OBJECT_EXT", }, + { 0x9151, "GL_BUFFER_OBJECT_EXT", }, + { 0x00000002, "GL_FRAGMENT_SHADER_BIT_EXT", }, + { 0x00000001, "GL_VERTEX_SHADER_BIT_EXT", }, { 0x00000004, "GL_COLOR_BUFFER_BIT2_QCOM", }, { 0x1702, "GL_TEXTURE", }, { 0x00000008, "GL_COLOR_BUFFER_BIT3_QCOM", }, @@ -384,12 +406,19 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x84DA, "GL_TEXTURE26", }, { 0x882F, "GL_DRAW_BUFFER10_NV", }, { 0x8645, "GL_VERTEX_ATTRIB_ARRAY_POINTER", }, + { 0x8865, "GL_CURRENT_QUERY_EXT", }, + { 0x8866, "GL_QUERY_RESULT_EXT", }, + { 0x8867, "GL_QUERY_RESULT_AVAILABLE_EXT", }, { 0x300E, "GL_CONTEXT_LOST", }, { 0x2600, "GL_NEAREST", }, { 0x84C4, "GL_TEXTURE4", }, { 0x85B5, "GL_VERTEX_ARRAY_BINDING_OES", }, - { 0x8253, "GL_GUILTY_CONTEXT_RESET_ARB", }, - { 0x8FC4, "GL_SHADER_BINARY_VIV", }, + { 0x8D6A, "GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT", }, + { 0x8D6C, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT", }, + { 0x8252, "GL_LOSE_CONTEXT_ON_RESET_EXT", }, + { 0x8C40, "GL_SRGB_EXT", }, + { 0x8C43, "GL_SRGB8_ALPHA8_EXT", }, + { 0x8C42, "GL_SRGB_ALPHA_EXT", }, { 0x00200000, "GL_STENCIL_BUFFER_BIT5_QCOM", }, { 0x8D68, "GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES", }, { 0x85BB, "GL_UNSIGNED_SHORT_8_8_REV_APPLE", }, @@ -433,6 +462,8 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x0B95, "GL_STENCIL_PASS_DEPTH_FAIL", }, { 0x2700, "GL_NEAREST_MIPMAP_NEAREST", }, { 0x0B98, "GL_STENCIL_WRITEMASK", }, + { 0x8B40, "GL_PROGRAM_OBJECT_EXT", }, + { 0x8B48, "GL_SHADER_OBJECT_EXT", }, { 0x912F, "GL_TEXTURE_IMMUTABLE_FORMAT_EXT", }, { 0x20000000, "GL_MULTISAMPLE_BUFFER_BIT5_QCOM", }, { 0x0DE1, "GL_TEXTURE_2D", }, @@ -464,6 +495,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x80CA, "GL_BLEND_DST_ALPHA", }, { 0x8CE4, "GL_COLOR_ATTACHMENT4_NV", }, { 0x8CD6, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT", }, + { 0x8253, "GL_GUILTY_CONTEXT_RESET_EXT", }, { 0x8872, "GL_MAX_TEXTURE_IMAGE_UNITS", }, { 0x8508, "GL_DECR_WRAP", }, { 0x8507, "GL_INCR_WRAP", }, @@ -483,8 +515,11 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x8625, "GL_VERTEX_ATTRIB_ARRAY_TYPE", }, { 0x8622, "GL_VERTEX_ATTRIB_ARRAY_ENABLED", }, { 0x8623, "GL_VERTEX_ATTRIB_ARRAY_SIZE", }, - { 0x8255, "GL_UNKNOWN_CONTEXT_RESET_ARB", }, - { 0x8254, "GL_INNOCENT_CONTEXT_RESET_ARB", }, + { 0x8259, "GL_ACTIVE_PROGRAM_EXT", }, + { 0x8258, "GL_PROGRAM_SEPARABLE_EXT", }, + { 0x8256, "GL_RESET_NOTIFICATION_STRATEGY_EXT", }, + { 0x8255, "GL_UNKNOWN_CONTEXT_RESET_EXT", }, + { 0x8254, "GL_INNOCENT_CONTEXT_RESET_EXT", }, { 0x1100, "GL_DONT_CARE", }, { 0x1101, "GL_FASTEST", }, { 0x1102, "GL_NICEST", }, @@ -503,6 +538,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x8CAA, "GL_READ_FRAMEBUFFER_BINDING_ANGLE", }, { 0x40000000, "GL_MULTISAMPLE_BUFFER_BIT6_QCOM", }, { 0x00000800, "GL_DEPTH_BUFFER_BIT3_QCOM", }, + { 0x1903, "GL_RED_EXT", }, { 0x8CE2, "GL_COLOR_ATTACHMENT2_NV", }, { 0x8BC1, "GL_COUNTER_RANGE_AMD", }, { 0x8CE0, "GL_COLOR_ATTACHMENT0", }, @@ -516,6 +552,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = { { 0x0C23, "GL_COLOR_WRITEMASK", }, { 0x0C22, "GL_COLOR_CLEAR_VALUE", }, { 0x8824, "GL_MAX_DRAW_BUFFERS_NV", }, + { 0x825A, "GL_PROGRAM_PIPELINE_BINDING_EXT", }, { 0x1909, "GL_LUMINANCE", }, { 0x0D3A, "GL_MAX_VIEWPORT_DIMS", }, { 0x809E, "GL_SAMPLE_ALPHA_TO_COVERAGE", }, diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index c85c252..16bde3c 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc @@ -437,6 +437,16 @@ void FeatureInfo::AddFeatures(const char* desired_features) { GL_LUMINANCE_ALPHA16F_EXT); } } + + if (ext.Desire("GL_ANGLE_instanced_arrays") && + (ext.Have("GL_ANGLE_instanced_arrays") || + (ext.Have("GL_ARB_instanced_arrays") && + ext.Have("GL_ARB_draw_instanced")))) { + AddExtensionString("GL_ANGLE_instanced_arrays"); + feature_flags_.angle_instanced_arrays = true; + validators_.vertex_attribute.AddValue(GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE); + } + } void FeatureInfo::AddExtensionString(const std::string& str) { diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h index 8e47f5e..3fcf3c9 100644 --- a/gpu/command_buffer/service/feature_info.h +++ b/gpu/command_buffer/service/feature_info.h @@ -30,7 +30,8 @@ class FeatureInfo : public base::RefCounted<FeatureInfo> { chromium_stream_texture(false), angle_translated_shader_source(false), angle_pack_reverse_row_order(false), - arb_texture_rectangle(false) { + arb_texture_rectangle(false), + angle_instanced_arrays(false) { } bool chromium_framebuffer_multisample; @@ -44,6 +45,7 @@ class FeatureInfo : public base::RefCounted<FeatureInfo> { bool angle_translated_shader_source; bool angle_pack_reverse_row_order; bool arb_texture_rectangle; + bool angle_instanced_arrays; }; FeatureInfo(); diff --git a/gpu/command_buffer/service/gl_utils.h b/gpu/command_buffer/service/gl_utils.h index d58e812..bf7f946 100644 --- a/gpu/command_buffer/service/gl_utils.h +++ b/gpu/command_buffer/service/gl_utils.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -66,6 +66,9 @@ #define GL_LUMINANCE_ALPHA16F_EXT 0x881F #define GL_BGRA8_EXT 0x93A1 +// GL_ANGLE_instanced_arrays +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE + #define GL_GLEXT_PROTOTYPES 1 // Define this for extra GL error debugging (slower). diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 7f00f02..b437f4c 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -1210,11 +1210,12 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, void ClearRealGLErrors(); // Checks if the current program and vertex attributes are valid for drawing. - bool IsDrawValid(GLuint max_vertex_accessed); + bool IsDrawValid(GLuint max_vertex_accessed, GLsizei primcount); // Returns true if successful, simulated will be true if attrib0 was // simulated. - bool SimulateAttrib0(GLuint max_vertex_accessed, bool* simulated); + bool SimulateAttrib0( + GLuint max_vertex_accessed, bool* simulated); void RestoreStateForSimulatedAttrib0(); // Returns true if textures were set. @@ -1222,9 +1223,19 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, void RestoreStateForNonRenderableTextures(); // Returns true if GL_FIXED attribs were simulated. - bool SimulateFixedAttribs(GLuint max_vertex_accessed, bool* simulated); + bool SimulateFixedAttribs( + GLuint max_vertex_accessed, bool* simulated, GLsizei primcount); void RestoreStateForSimulatedFixedAttribs(); + // Handle DrawArrays and DrawElements for both instanced and non-instanced + // cases (primcount is 0 for non-instanced). + error::Error DoDrawArrays( + bool instanced, GLenum mode, GLint first, GLsizei count, + GLsizei primcount); + error::Error DoDrawElements( + bool instanced, GLenum mode, GLsizei count, GLenum type, + int32 offset, GLsizei primcount); + // Gets the buffer id for a given target. BufferManager::BufferInfo* GetBufferInfoForTarget(GLenum target) { DCHECK(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER); @@ -4856,7 +4867,8 @@ bool GLES2DecoderImpl::ClearUnclearedTextures() { return true; } -bool GLES2DecoderImpl::IsDrawValid(GLuint max_vertex_accessed) { +bool GLES2DecoderImpl::IsDrawValid( + GLuint max_vertex_accessed, GLsizei primcount) { // NOTE: We specifically do not check current_program->IsValid() because // it could never be invalid since glUseProgram would have failed. While // glLinkProgram could later mark the program as invalid the previous @@ -4866,6 +4878,9 @@ bool GLES2DecoderImpl::IsDrawValid(GLuint max_vertex_accessed) { // But GL says no ERROR. return false; } + + // true if any enabled, used divisor is zero + bool divisor0 = false; // Validate all attribs currently enabled. If they are used by the current // program then check that they have enough elements to handle the draw call. // If they are not used by the current program check that they have a buffer @@ -4878,8 +4893,10 @@ bool GLES2DecoderImpl::IsDrawValid(GLuint max_vertex_accessed) { const ProgramManager::ProgramInfo::VertexAttribInfo* attrib_info = current_program_->GetAttribInfoByLocation(info->index()); if (attrib_info) { + divisor0 |= (info->divisor() == 0); + GLuint count = info->MaxVertexAccessed(primcount, max_vertex_accessed); // This attrib is used in the current program. - if (!info->CanAccess(max_vertex_accessed)) { + if (!info->CanAccess(count)) { SetGLError(GL_INVALID_OPERATION, "glDrawXXX: attempt to access out of range vertices"); return false; @@ -4895,6 +4912,15 @@ bool GLES2DecoderImpl::IsDrawValid(GLuint max_vertex_accessed) { } } } + + if (primcount && !divisor0) { + SetGLError( + GL_INVALID_OPERATION, + "glDrawXXX: attempt instanced render with all attributes having " + "non-zero divisors"); + return false; + } + return true; } @@ -4957,6 +4983,9 @@ bool GLES2DecoderImpl::SimulateAttrib0( glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL); + if (info->divisor()) + glVertexAttribDivisorANGLE(0, 0); + *simulated = true; return true; } @@ -4970,12 +4999,14 @@ void GLES2DecoderImpl::RestoreStateForSimulatedAttrib0() { glVertexAttribPointer( 0, info->size(), info->type(), info->normalized(), info->gl_stride(), ptr); + if (info->divisor()) + glVertexAttribDivisorANGLE(0, info->divisor()); glBindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_ ? bound_array_buffer_->service_id() : 0); } bool GLES2DecoderImpl::SimulateFixedAttribs( - GLuint max_vertex_accessed, bool* simulated) { + GLuint max_vertex_accessed, bool* simulated, GLsizei primcount) { DCHECK(simulated); *simulated = false; if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) @@ -4991,13 +5022,6 @@ bool GLES2DecoderImpl::SimulateFixedAttribs( // to be used normally. It's just here to pass that OpenGL ES 2.0 conformance // tests so we just add to the buffer attrib used. - // Compute the number of elements needed. - GLuint num_vertices = max_vertex_accessed + 1; - if (num_vertices == 0) { - SetGLError(GL_OUT_OF_MEMORY, "glDrawXXX: Simulating attrib 0"); - return false; - } - GLuint elements_needed = 0; const VertexAttribManager::VertexAttribInfoList& infos = vertex_attrib_manager_->GetEnabledVertexAttribInfos(); @@ -5006,8 +5030,15 @@ bool GLES2DecoderImpl::SimulateFixedAttribs( const VertexAttribManager::VertexAttribInfo* info = *it; const ProgramManager::ProgramInfo::VertexAttribInfo* attrib_info = current_program_->GetAttribInfoByLocation(info->index()); + GLuint max_accessed = info->MaxVertexAccessed(primcount, + max_vertex_accessed); + GLuint num_vertices = max_accessed + 1; + if (num_vertices == 0) { + SetGLError(GL_OUT_OF_MEMORY, "glDrawXXX: Simulating attrib 0"); + return false; + } if (attrib_info && - info->CanAccess(max_vertex_accessed) && + info->CanAccess(max_accessed) && info->type() == GL_FIXED) { GLuint elements_used = 0; if (!SafeMultiply(num_vertices, @@ -5046,8 +5077,15 @@ bool GLES2DecoderImpl::SimulateFixedAttribs( const VertexAttribManager::VertexAttribInfo* info = *it; const ProgramManager::ProgramInfo::VertexAttribInfo* attrib_info = current_program_->GetAttribInfoByLocation(info->index()); + GLuint max_accessed = info->MaxVertexAccessed(primcount, + max_vertex_accessed); + GLuint num_vertices = max_accessed + 1; + if (num_vertices == 0) { + SetGLError(GL_OUT_OF_MEMORY, "glDrawXXX: Simulating attrib 0"); + return false; + } if (attrib_info && - info->CanAccess(max_vertex_accessed) && + info->CanAccess(max_accessed) && info->type() == GL_FIXED) { int num_elements = info->size() * kSizeOfFloat; int size = num_elements * num_vertices; @@ -5077,11 +5115,11 @@ void GLES2DecoderImpl::RestoreStateForSimulatedFixedAttribs() { bound_array_buffer_ ? bound_array_buffer_->service_id() : 0); } -error::Error GLES2DecoderImpl::HandleDrawArrays( - uint32 immediate_data_size, const gles2::DrawArrays& c) { - GLenum mode = static_cast<GLenum>(c.mode); - GLint first = static_cast<GLint>(c.first); - GLsizei count = static_cast<GLsizei>(c.count); +error::Error GLES2DecoderImpl::DoDrawArrays(bool instanced, + GLenum mode, + GLint first, + GLsizei count, + GLsizei primcount) { if (!validators_->draw_mode.IsValid(mode)) { SetGLError(GL_INVALID_ENUM, "glDrawArrays: mode GL_INVALID_ENUM"); return error::kNoError; @@ -5090,6 +5128,10 @@ error::Error GLES2DecoderImpl::HandleDrawArrays( SetGLError(GL_INVALID_VALUE, "glDrawArrays: count < 0"); return error::kNoError; } + if (primcount < 0) { + SetGLError(GL_INVALID_VALUE, "glDrawArrays: primcount < 0"); + return error::kNoError; + } if (!CheckBoundFramebuffersValid("glDrawArrays")) { return error::kNoError; } @@ -5100,12 +5142,12 @@ error::Error GLES2DecoderImpl::HandleDrawArrays( return error::kNoError; } - if (count == 0) { + if (count == 0 || (instanced && primcount == 0)) { return error::kNoError; } GLuint max_vertex_accessed = first + count - 1; - if (IsDrawValid(max_vertex_accessed)) { + if (IsDrawValid(max_vertex_accessed, primcount)) { if (!ClearUnclearedTextures()) { SetGLError(GL_INVALID_VALUE, "glDrawArrays: out of memory"); return error::kNoError; @@ -5115,10 +5157,15 @@ error::Error GLES2DecoderImpl::HandleDrawArrays( return error::kNoError; } bool simulated_fixed_attribs = false; - if (SimulateFixedAttribs(max_vertex_accessed, &simulated_fixed_attribs)) { + if (SimulateFixedAttribs(max_vertex_accessed, &simulated_fixed_attribs, + primcount)) { bool textures_set = SetBlackTextureForNonRenderableTextures(); ApplyDirtyState(); - glDrawArrays(mode, first, count); + if (!instanced) { + glDrawArrays(mode, first, count); + } else { + glDrawArraysInstancedANGLE(mode, first, count, primcount); + } if (textures_set) { RestoreStateForNonRenderableTextures(); } @@ -5137,18 +5184,41 @@ error::Error GLES2DecoderImpl::HandleDrawArrays( return error::kNoError; } -error::Error GLES2DecoderImpl::HandleDrawElements( - uint32 immediate_data_size, const gles2::DrawElements& c) { +error::Error GLES2DecoderImpl::HandleDrawArrays( + uint32 immediate_data_size, const gles2::DrawArrays& c) { + return DoDrawArrays(false, + static_cast<GLenum>(c.mode), + static_cast<GLint>(c.first), + static_cast<GLsizei>(c.count), + 0); +} + +error::Error GLES2DecoderImpl::HandleDrawArraysInstancedANGLE( + uint32 immediate_data_size, const gles2::DrawArraysInstancedANGLE& c) { + if (!feature_info_->feature_flags().angle_instanced_arrays) { + SetGLError(GL_INVALID_OPERATION, + "glDrawArraysInstancedANGLE: function not available"); + return error::kNoError; + } + return DoDrawArrays(true, + static_cast<GLenum>(c.mode), + static_cast<GLint>(c.first), + static_cast<GLsizei>(c.count), + static_cast<GLsizei>(c.primcount)); +} + +error::Error GLES2DecoderImpl::DoDrawElements(bool instanced, + GLenum mode, + GLsizei count, + GLenum type, + int32 offset, + GLsizei primcount) { if (!bound_element_array_buffer_) { SetGLError(GL_INVALID_OPERATION, "glDrawElements: No element array buffer bound"); return error::kNoError; } - GLenum mode = c.mode; - GLsizei count = c.count; - GLenum type = c.type; - int32 offset = c.index_offset; if (count < 0) { SetGLError(GL_INVALID_VALUE, "glDrawElements: count < 0"); return error::kNoError; @@ -5165,12 +5235,16 @@ error::Error GLES2DecoderImpl::HandleDrawElements( SetGLError(GL_INVALID_ENUM, "glDrawElements: type GL_INVALID_ENUM"); return error::kNoError; } + if (primcount < 0) { + SetGLError(GL_INVALID_VALUE, "glDrawElements: primcount < 0"); + return error::kNoError; + } if (!CheckBoundFramebuffersValid("glDrawElements")) { return error::kNoError; } - if (count == 0) { + if (count == 0 || (instanced && primcount == 0)) { return error::kNoError; } @@ -5182,7 +5256,7 @@ error::Error GLES2DecoderImpl::HandleDrawElements( return error::kNoError; } - if (IsDrawValid(max_vertex_accessed)) { + if (IsDrawValid(max_vertex_accessed, primcount)) { if (!ClearUnclearedTextures()) { SetGLError(GL_INVALID_VALUE, "glDrawElements: out of memory"); return error::kNoError; @@ -5192,11 +5266,16 @@ error::Error GLES2DecoderImpl::HandleDrawElements( return error::kNoError; } bool simulated_fixed_attribs = false; - if (SimulateFixedAttribs(max_vertex_accessed, &simulated_fixed_attribs)) { + if (SimulateFixedAttribs(max_vertex_accessed, &simulated_fixed_attribs, + primcount)) { bool textures_set = SetBlackTextureForNonRenderableTextures(); ApplyDirtyState(); const GLvoid* indices = reinterpret_cast<const GLvoid*>(offset); - glDrawElements(mode, count, type, indices); + if (!instanced) { + glDrawElements(mode, count, type, indices); + } else { + glDrawElementsInstancedANGLE(mode, count, type, indices, primcount); + } if (textures_set) { RestoreStateForNonRenderableTextures(); } @@ -5215,6 +5294,31 @@ error::Error GLES2DecoderImpl::HandleDrawElements( return error::kNoError; } +error::Error GLES2DecoderImpl::HandleDrawElements( + uint32 immediate_data_size, const gles2::DrawElements& c) { + return DoDrawElements(false, + static_cast<GLenum>(c.mode), + static_cast<GLsizei>(c.count), + static_cast<GLenum>(c.type), + static_cast<int32>(c.index_offset), + 0); +} + +error::Error GLES2DecoderImpl::HandleDrawElementsInstancedANGLE( + uint32 immediate_data_size, const gles2::DrawElementsInstancedANGLE& c) { + if (!feature_info_->feature_flags().angle_instanced_arrays) { + SetGLError(GL_INVALID_OPERATION, + "glDrawElementsInstancedANGLE: function not available"); + return error::kNoError; + } + return DoDrawElements(true, + static_cast<GLenum>(c.mode), + static_cast<GLsizei>(c.count), + static_cast<GLenum>(c.type), + static_cast<int32>(c.index_offset), + static_cast<GLsizei>(c.primcount)); +} + GLuint GLES2DecoderImpl::DoGetMaxValueInBufferCHROMIUM( GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) { GLuint max_vertex_accessed = 0; @@ -5562,6 +5666,9 @@ void GLES2DecoderImpl::DoGetVertexAttribfv( params[2] = info->value().v[2]; params[3] = info->value().v[3]; break; + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: + *params = static_cast<GLfloat>(info->divisor()); + break; default: NOTREACHED(); break; @@ -5601,6 +5708,9 @@ void GLES2DecoderImpl::DoGetVertexAttribiv( case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: *params = static_cast<GLint>(info->normalized()); break; + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: + *params = info->divisor(); + break; case GL_CURRENT_VERTEX_ATTRIB: params[0] = static_cast<GLint>(info->value().v[0]); params[1] = static_cast<GLint>(info->value().v[1]); @@ -5814,6 +5924,27 @@ error::Error GLES2DecoderImpl::HandleVertexAttribPointer( return error::kNoError; } +error::Error GLES2DecoderImpl::HandleVertexAttribDivisorANGLE( + uint32 immediate_data_size, const gles2::VertexAttribDivisorANGLE& c) { + if (!feature_info_->feature_flags().angle_instanced_arrays) { + SetGLError(GL_INVALID_OPERATION, + "glVertexAttribDivisorANGLE: function not available"); + } + GLuint index = c.index; + GLuint divisor = c.divisor; + if (index >= group_->max_vertex_attribs()) { + SetGLError(GL_INVALID_VALUE, + "glVertexAttribDivisorANGLE: index out of range"); + return error::kNoError; + } + + vertex_attrib_manager_->SetDivisor( + index, + divisor); + glVertexAttribDivisorANGLE(index, divisor); + return error::kNoError; +} + error::Error GLES2DecoderImpl::HandleReadPixels( uint32 immediate_data_size, const gles2::ReadPixels& c) { GLint x = c.x; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index bd14308..64869b0 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -73,6 +73,26 @@ class GLES2DecoderWithShaderTest : public GLES2DecoderWithShaderTestBase { void CheckRenderbufferChangesMarkFBOAsNotComplete(bool bound_fbo); }; +class GLES2DecoderGeometryInstancingTest : public GLES2DecoderWithShaderTest { + public: + GLES2DecoderGeometryInstancingTest() + : GLES2DecoderWithShaderTest() { + } + + virtual void SetUp() { + InitDecoder( + "GL_ANGLE_instanced_arrays", // extensions + true, // has alpha + true, // has depth + false, // has stencil + true, // request alpha + true, // request depth + false, // request stencil + true); // bind generates resource + SetupDefaultProgram(); + } +}; + class GLES2DecoderRGBBackbufferTest : public GLES2DecoderWithShaderTest { public: GLES2DecoderRGBBackbufferTest() { } @@ -312,6 +332,239 @@ TEST_F(GLES2DecoderWithShaderTest, DrawArraysInvalidCountFails) { EXPECT_EQ(GL_NO_ERROR, GetGLError()); } +TEST_F(GLES2DecoderWithShaderTest, DrawArraysInstancedANGLEFails) { + SetupTexture(); + SetupVertexBuffer(); + DoEnableVertexAttribArray(1); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) + .Times(0) + .RetiresOnSaturation(); + DrawArraysInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawArraysInstancedANGLENoAttributesFails) { + SetupTexture(); + + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) + .Times(0) + .RetiresOnSaturation(); + DrawArraysInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawArraysInstancedANGLESimulatedAttrib0) { + SetupTexture(); + SetupVertexBuffer(); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId); + SetupExpectationsForApplyingDefaultDirtyState(); + + DoVertexAttribDivisorANGLE(0, 1); + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, 3)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 1)) + .Times(1) + .RetiresOnSaturation(); + DrawArraysInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, 0, kNumVertices, 3); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawArraysInstancedANGLEMissingAttributesFails) { + DoEnableVertexAttribArray(1); + + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) + .Times(0); + DrawArraysInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawArraysInstancedANGLEMissingAttributesZeroCountSucceeds) { + DoEnableVertexAttribArray(1); + + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) + .Times(0); + DrawArraysInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, 0, 0, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawArraysInstancedANGLEValidAttributesSucceeds) { + SetupTexture(); + SetupVertexBuffer(); + DoEnableVertexAttribArray(1); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId); + SetupExpectationsForApplyingDefaultDirtyState(); + + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, 1)) + .Times(1) + .RetiresOnSaturation(); + DrawArraysInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawArraysInstancedANGLEWithInvalidModeFails) { + SetupVertexBuffer(); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) + .Times(0); + DrawArraysInstancedANGLE cmd; + cmd.Init(GL_QUADS, 0, 1, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); + cmd.Init(GL_POLYGON, 0, 1, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawArraysInstancedANGLEInvalidPrimcountFails) { + SetupVertexBuffer(); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) + .Times(0); + DrawArraysInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, 0, 1, -1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); +} + +// Per-instance data is twice as large, but number of instances is half +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawArraysInstancedANGLELargeInstanceSucceeds) { + SetupTexture(); + SetupVertexBuffer(); + SetupExpectationsForApplyingDefaultDirtyState(); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + DoEnableVertexAttribArray(0); + DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0); + DoVertexAttribDivisorANGLE(0, 1); + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, + kNumVertices / 2)) + .Times(1) + .RetiresOnSaturation(); + DrawArraysInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, 0, kNumVertices, kNumVertices / 2); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +// Per-instance data is twice as large, but divisor is twice +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawArraysInstancedANGLELargeDivisorSucceeds) { + SetupTexture(); + SetupVertexBuffer(); + SetupExpectationsForApplyingDefaultDirtyState(); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + DoEnableVertexAttribArray(0); + DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0); + DoVertexAttribDivisorANGLE(0, 2); + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, + kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + DrawArraysInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, 0, kNumVertices, kNumVertices); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, DrawArraysInstancedANGLELargeFails) { + SetupTexture(); + SetupVertexBuffer(); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + DoEnableVertexAttribArray(0); + DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); + DoVertexAttribDivisorANGLE(0, 1); + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) + .Times(0) + .RetiresOnSaturation(); + DrawArraysInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, 0, kNumVertices, kNumVertices + 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) + .Times(0) + .RetiresOnSaturation(); + cmd.Init(GL_TRIANGLES, 0, kNumVertices + 1, kNumVertices); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +// Per-index data is twice as large, but number of indices is half +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawArraysInstancedANGLELargeIndexSucceeds) { + SetupTexture(); + SetupVertexBuffer(); + SetupExpectationsForApplyingDefaultDirtyState(); + DoVertexAttribPointer(1, 4, GL_FLOAT, 0, 0); + + DoEnableVertexAttribArray(0); + DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); + DoVertexAttribDivisorANGLE(0, 1); + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices / 2, + kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + DrawArraysInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, 0, kNumVertices / 2, kNumVertices); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawArraysInstancedANGLENoDivisor0Fails) { + SetupTexture(); + SetupVertexBuffer(); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + DoEnableVertexAttribArray(0); + DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); + DoVertexAttribDivisorANGLE(0, 1); + DoVertexAttribDivisorANGLE(1, 1); + EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)) + .Times(0) + .RetiresOnSaturation(); + DrawArraysInstancedANGLE cmd; + 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()); +} + TEST_F(GLES2DecoderWithShaderTest, DrawElementsNoAttributesSucceeds) { SetupTexture(); SetupIndexBuffer(); @@ -485,6 +738,299 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsOddOffsetForUint16Fails) { EXPECT_EQ(GL_NO_ERROR, GetGLError()); } +TEST_F(GLES2DecoderWithShaderTest, DrawElementsInstancedANGLEFails) { + SetupTexture(); + SetupVertexBuffer(); + SetupIndexBuffer(); + DoEnableVertexAttribArray(1); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) + .Times(0) + .RetiresOnSaturation(); + DrawElementsInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawElementsInstancedANGLENoAttributesFails) { + SetupTexture(); + SetupIndexBuffer(); + + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) + .Times(0) + .RetiresOnSaturation(); + DrawElementsInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawElementsInstancedANGLESimulatedAttrib0) { + SetupTexture(); + SetupVertexBuffer(); + SetupIndexBuffer(); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, kServiceBufferId); + SetupExpectationsForApplyingDefaultDirtyState(); + + DoVertexAttribDivisorANGLE(0, 1); + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE( + GL_TRIANGLES, + kValidIndexRangeCount, + GL_UNSIGNED_SHORT, + BufferOffset(kValidIndexRangeStart * 2), + 3)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 1)) + .Times(1) + .RetiresOnSaturation(); + DrawElementsInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, 3); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawElementsInstancedANGLEMissingAttributesFails) { + SetupIndexBuffer(); + DoEnableVertexAttribArray(1); + + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) + .Times(0); + DrawElementsInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawElementsInstancedANGLEMissingAttributesZeroCountSucceeds) { + SetupIndexBuffer(); + DoEnableVertexAttribArray(1); + + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) + .Times(0); + DrawElementsInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawElementsInstancedANGLEValidAttributesSucceeds) { + SetupIndexBuffer(); + SetupTexture(); + SetupVertexBuffer(); + DoEnableVertexAttribArray(1); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, kServiceBufferId); + SetupExpectationsForApplyingDefaultDirtyState(); + + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE( + GL_TRIANGLES, + kValidIndexRangeCount, + GL_UNSIGNED_SHORT, + BufferOffset(kValidIndexRangeStart * 2), + 1)) + .Times(1) + .RetiresOnSaturation(); + DrawElementsInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawElementsInstancedANGLEWithInvalidModeFails) { + SetupIndexBuffer(); + SetupVertexBuffer(); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) + .Times(0); + DrawElementsInstancedANGLE cmd; + cmd.Init(GL_QUADS, kValidIndexRangeCount, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); + cmd.Init(GL_INVALID_ENUM, kValidIndexRangeCount, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); +} + +// Per-instance data is twice as large, but number of instances is half +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawElementsInstancedANGLELargeInstanceSucceeds) { + SetupTexture(); + SetupIndexBuffer(); + SetupVertexBuffer(); + SetupExpectationsForApplyingDefaultDirtyState(); + //Add offset so we're sure we're accessing data near the end of the buffer. + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, + (kNumVertices - kMaxValidIndex - 1) * 2 * + sizeof(GLfloat)); + + DoEnableVertexAttribArray(0); + DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0); + DoVertexAttribDivisorANGLE(0, 1); + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE( + GL_TRIANGLES, + kValidIndexRangeCount, + GL_UNSIGNED_SHORT, + BufferOffset(kValidIndexRangeStart * 2), + kNumVertices / 2)) + .Times(1) + .RetiresOnSaturation(); + DrawElementsInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, kNumVertices / 2); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +// Per-instance data is twice as large, but divisor is twice +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawElementsInstancedANGLELargeDivisorSucceeds) { + SetupTexture(); + SetupIndexBuffer(); + SetupVertexBuffer(); + SetupExpectationsForApplyingDefaultDirtyState(); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + DoEnableVertexAttribArray(0); + DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0); + DoVertexAttribDivisorANGLE(0, 2); + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE( + GL_TRIANGLES, + kValidIndexRangeCount, + GL_UNSIGNED_SHORT, + BufferOffset(kValidIndexRangeStart * 2), + kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + DrawElementsInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, kNumVertices); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawElementsInstancedANGLELargeFails) { + SetupTexture(); + SetupIndexBuffer(); + SetupVertexBuffer(); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + DoEnableVertexAttribArray(0); + DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); + DoVertexAttribDivisorANGLE(0, 1); + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) + .Times(0) + .RetiresOnSaturation(); + DrawElementsInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, kNumVertices + 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) + .Times(0) + .RetiresOnSaturation(); + cmd.Init(GL_TRIANGLES, kInvalidIndexRangeCount, GL_UNSIGNED_SHORT, + kInvalidIndexRangeStart * 2, kNumVertices); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawElementsInstancedANGLEInvalidPrimcountFails) { + SetupTexture(); + SetupIndexBuffer(); + SetupVertexBuffer(); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + DoEnableVertexAttribArray(0); + DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); + DoVertexAttribDivisorANGLE(0, 1); + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) + .Times(0) + .RetiresOnSaturation(); + DrawElementsInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, -1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +// Per-index data is twice as large, but values of indices are smaller +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawElementsInstancedANGLELargeIndexSucceeds) { + SetupTexture(); + SetupIndexBuffer(); + SetupVertexBuffer(); + SetupExpectationsForApplyingDefaultDirtyState(); + DoVertexAttribPointer(1, 4, GL_FLOAT, 0, 0); + + DoEnableVertexAttribArray(0); + DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); + DoVertexAttribDivisorANGLE(0, 1); + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE( + GL_TRIANGLES, + kValidIndexRangeCount, + GL_UNSIGNED_SHORT, + BufferOffset(kValidIndexRangeStart * 2), + kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + DrawElementsInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, kNumVertices); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderGeometryInstancingTest, + DrawElementsInstancedANGLENoDivisor0Fails) { + SetupTexture(); + SetupIndexBuffer(); + SetupVertexBuffer(); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + + DoEnableVertexAttribArray(0); + DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); + DoVertexAttribDivisorANGLE(0, 1); + DoVertexAttribDivisorANGLE(1, 1); + EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)) + .Times(0) + .RetiresOnSaturation(); + DrawElementsInstancedANGLE cmd; + cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, + kValidIndexRangeStart * 2, kNumVertices); + 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; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h index 0a694a3..b26f7f1 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h @@ -19,5 +19,8 @@ // TODO(gman): GetTranslatedShaderSourceANGLE // TODO(gman): PostSubBufferCHROMIUM // TODO(gman): TexImageIOSurface2DCHROMIUM +// TODO(gman): DrawArraysInstancedANGLE +// TODO(gman): DrawElementsInstancedANGLE +// TODO(gman): VertexAttribDivisorANGLE #endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_ diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index f94aa68..7f1f6e7 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -763,6 +763,17 @@ void GLES2DecoderTestBase::DoVertexAttribPointer( EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); } +void GLES2DecoderTestBase::DoVertexAttribDivisorANGLE( + GLuint index, GLuint divisor) { + EXPECT_CALL(*gl_, + VertexAttribDivisorANGLE(index, divisor)) + .Times(1) + .RetiresOnSaturation(); + VertexAttribDivisorANGLE cmd; + cmd.Init(index, divisor); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); +} + // GCC requires these declarations, but MSVC requires they not be present #ifndef COMPILER_MSVC const GLint GLES2DecoderTestBase::kMaxTextureSize; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h index bc726a6..e0c8b46 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h @@ -307,6 +307,7 @@ class GLES2DecoderTestBase : public testing::Test { GLint level, GLenum error); void DoVertexAttribPointer( GLuint index, GLint size, GLenum type, GLsizei stride, GLuint offset); + void DoVertexAttribDivisorANGLE(GLuint index, GLuint divisor); void DoEnableVertexAttribArray(GLint index); diff --git a/gpu/command_buffer/service/vertex_attrib_manager.cc b/gpu/command_buffer/service/vertex_attrib_manager.cc index 9df444c..4a07bf9 100644 --- a/gpu/command_buffer/service/vertex_attrib_manager.cc +++ b/gpu/command_buffer/service/vertex_attrib_manager.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -26,6 +26,7 @@ VertexAttribManager::VertexAttribInfo::VertexAttribInfo() normalized_(GL_FALSE), gl_stride_(0), real_stride_(16), + divisor_(0), list_(NULL) { value_.v[0] = 0.0f; value_.v[1] = 0.0f; diff --git a/gpu/command_buffer/service/vertex_attrib_manager.h b/gpu/command_buffer/service/vertex_attrib_manager.h index 9cbc18f..cd24abd 100644 --- a/gpu/command_buffer/service/vertex_attrib_manager.h +++ b/gpu/command_buffer/service/vertex_attrib_manager.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -59,6 +59,10 @@ class VertexAttribManager { return gl_stride_; } + GLuint divisor() const { + return divisor_; + } + bool enabled() const { return enabled_; } @@ -71,6 +75,13 @@ class VertexAttribManager { return value_; } + // Find the maximum vertex accessed, accounting for instancing. + GLuint MaxVertexAccessed(GLsizei primcount, + GLuint max_vertex_accessed) const { + return (primcount && divisor_) ? ((primcount - 1) / divisor_) : + max_vertex_accessed; + } + private: friend class VertexAttribManager; @@ -111,6 +122,10 @@ class VertexAttribManager { offset_ = offset; } + void SetDivisor(GLsizei divisor) { + divisor_ = divisor; + } + void Unbind(BufferManager::BufferInfo* buffer) { if (buffer_ == buffer) { buffer_ = NULL; @@ -142,6 +157,8 @@ class VertexAttribManager { // of 0. GLsizei real_stride_; + GLsizei divisor_; + // The current value of the attrib. Vec4 value_; @@ -201,6 +218,13 @@ class VertexAttribManager { } } + void SetDivisor(GLuint index, GLuint divisor) { + VertexAttribInfo* info = GetVertexAttribInfo(index); + if (info) { + info->SetDivisor(divisor); + } + } + void Unbind(BufferManager::BufferInfo* buffer); private: |