summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorjbauman@chromium.org <jbauman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-14 03:31:42 +0000
committerjbauman@chromium.org <jbauman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-14 03:31:42 +0000
commitc6aef90f9f927ac75bb99d6d77782fc33c37769d (patch)
treea9e1c0067cba88556eff8541dfd87b09acd0a16c /gpu
parent2e3d9e4cd2b473f6f6a53999c6af0b1e50c3fa5d (diff)
downloadchromium_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')
-rwxr-xr-xgpu/command_buffer/build_gles2_cmd_buffer.py21
-rw-r--r--gpu/command_buffer/client/gles2_c_lib_autogen.h14
-rw-r--r--gpu/command_buffer/client/gles2_cmd_helper_autogen.h27
-rw-r--r--gpu/command_buffer/client/gles2_implementation.cc151
-rw-r--r--gpu/command_buffer/client/gles2_implementation_autogen.h9
-rw-r--r--gpu/command_buffer/client/gles2_implementation_unittest.cc159
-rw-r--r--gpu/command_buffer/client/gles2_implementation_unittest_autogen.h22
-rw-r--r--gpu/command_buffer/cmd_buffer_functions.txt3
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_autogen.h141
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_test_autogen.h55
-rw-r--r--gpu/command_buffer/common/gles2_cmd_ids_autogen.h3
-rw-r--r--gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h57
-rw-r--r--gpu/command_buffer/service/feature_info.cc10
-rw-r--r--gpu/command_buffer/service/feature_info.h4
-rw-r--r--gpu/command_buffer/service/gl_utils.h5
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc199
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc546
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h3
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc11
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h1
-rw-r--r--gpu/command_buffer/service/vertex_attrib_manager.cc3
-rw-r--r--gpu/command_buffer/service/vertex_attrib_manager.h26
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: