diff options
author | kbr <kbr@chromium.org> | 2016-03-21 20:23:24 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-22 03:27:25 +0000 |
commit | 0b677e15ebe36546b0d946af78657be3d8b3f0b0 (patch) | |
tree | cdb825a924f399e8a33c042f4cd3da18ae874248 /gpu | |
parent | a5595a6ee340e5f83e4b86141672ce07a66f8cf1 (diff) | |
download | chromium_src-0b677e15ebe36546b0d946af78657be3d8b3f0b0.zip chromium_src-0b677e15ebe36546b0d946af78657be3d8b3f0b0.tar.gz chromium_src-0b677e15ebe36546b0d946af78657be3d8b3f0b0.tar.bz2 |
Fix PRIMITIVE_RESTART_FIXED_INDEX handling in command buffer and WebGL 2.0.
Adapted from yunchao.he@intel.com's
https://codereview.chromium.org/1783763002 .
This fixes the command buffer's index validation and WebGL 2.0's
implicit enabling of this capability. Emulation of this feature on top
of earlier desktop OpenGL versions will be implemented in a later CL.
BUG=594021, 295792
TEST=deqp/functional/gles3/primitiverestart.html
CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_optional_gpu_tests_rel
Review URL: https://codereview.chromium.org/1813163003
Cr-Commit-Position: refs/heads/master@{#382497}
Diffstat (limited to 'gpu')
-rw-r--r-- | gpu/command_buffer/service/buffer_manager.cc | 59 | ||||
-rw-r--r-- | gpu/command_buffer/service/buffer_manager.h | 14 | ||||
-rw-r--r-- | gpu/command_buffer/service/buffer_manager_unittest.cc | 285 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 16 |
4 files changed, 247 insertions, 127 deletions
diff --git a/gpu/command_buffer/service/buffer_manager.cc b/gpu/command_buffer/service/buffer_manager.cc index 914d9b0..c6f3880 100644 --- a/gpu/command_buffer/service/buffer_manager.cc +++ b/gpu/command_buffer/service/buffer_manager.cc @@ -199,13 +199,17 @@ void Buffer::ClearCache() { } template <typename T> -GLuint GetMaxValue(const void* data, GLuint offset, GLsizei count) { +GLuint GetMaxValue(const void* data, GLuint offset, GLsizei count, + GLuint primitive_restart_index) { GLuint max_value = 0; const T* element = reinterpret_cast<const T*>(static_cast<const int8_t*>(data) + offset); const T* end = element + count; for (; element < end; ++element) { if (*element > max_value) { + if (*element == primitive_restart_index) { + continue; + } max_value = *element; } } @@ -213,13 +217,53 @@ GLuint GetMaxValue(const void* data, GLuint offset, GLsizei count) { } bool Buffer::GetMaxValueForRange( - GLuint offset, GLsizei count, GLenum type, GLuint* max_value) { - Range range(offset, count, type); + GLuint offset, GLsizei count, GLenum type, bool primitive_restart_enabled, + GLuint* max_value) { + GLuint primitive_restart_index = 0; + if (primitive_restart_enabled) { + switch (type) { + case GL_UNSIGNED_BYTE: + primitive_restart_index = 0xFF; + break; + case GL_UNSIGNED_SHORT: + primitive_restart_index = 0xFFFF; + break; + case GL_UNSIGNED_INT: + primitive_restart_index = 0xFFFFFFFF; + break; + default: + NOTREACHED(); // should never get here by validation. + break; + } + } + + Range range(offset, count, type, primitive_restart_enabled); RangeToMaxValueMap::iterator it = range_set_.find(range); if (it != range_set_.end()) { *max_value = it->second; return true; } + // Optimization. If: + // - primitive restart is enabled + // - we don't have an entry in the range set for these parameters + // for the situation when primitive restart is enabled + // - we do have an entry in the range set for these parameters for + // the situation when primitive restart is disabled + // - this entry is less than the primitive restart index + // Then we can repurpose this entry for the situation when primitive + // restart is enabled. Otherwise, we need to compute the max index + // from scratch. + if (primitive_restart_enabled) { + Range disabled_range(offset, count, type, false); + RangeToMaxValueMap::iterator it = range_set_.find(disabled_range); + if (it != range_set_.end() && it->second < primitive_restart_index) { + // This reuses the max value for the case where primitive + // restart is enabled. + range_set_.insert(std::make_pair(range, it->second)); + *max_value = it->second; + return true; + } + } uint32_t size; if (!SafeMultiplyUint32( @@ -243,21 +287,24 @@ bool Buffer::GetMaxValueForRange( GLuint max_v = 0; switch (type) { case GL_UNSIGNED_BYTE: - max_v = GetMaxValue<uint8_t>(shadow_.get(), offset, count); + max_v = GetMaxValue<uint8_t>(shadow_.get(), offset, count, + primitive_restart_index); break; case GL_UNSIGNED_SHORT: // Check we are not accessing an odd byte for a 2 byte value. if ((offset & 1) != 0) { return false; } - max_v = GetMaxValue<uint16_t>(shadow_.get(), offset, count); + max_v = GetMaxValue<uint16_t>(shadow_.get(), offset, count, + primitive_restart_index); break; case GL_UNSIGNED_INT: // Check we are not accessing a non aligned address for a 4 byte value. if ((offset & 3) != 0) { return false; } - max_v = GetMaxValue<uint32_t>(shadow_.get(), offset, count); + max_v = GetMaxValue<uint32_t>(shadow_.get(), offset, count, + primitive_restart_index); break; default: NOTREACHED(); // should never get here by validation. diff --git a/gpu/command_buffer/service/buffer_manager.h b/gpu/command_buffer/service/buffer_manager.h index 33df818..5e2c60c 100644 --- a/gpu/command_buffer/service/buffer_manager.h +++ b/gpu/command_buffer/service/buffer_manager.h @@ -63,7 +63,7 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> { // offset is in bytes. // count is in elements of type. bool GetMaxValueForRange(GLuint offset, GLsizei count, GLenum type, - GLuint* max_value); + bool primitive_restart_enabled, GLuint* max_value); // Returns a pointer to shadowed data. const void* GetRange(GLintptr offset, GLsizeiptr size) const; @@ -101,10 +101,12 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> { // Represents a range in a buffer. class Range { public: - Range(GLuint offset, GLsizei count, GLenum type) + Range(GLuint offset, GLsizei count, GLenum type, + bool primitive_restart_enabled) : offset_(offset), count_(count), - type_(type) { + type_(type), + primitive_restart_enabled_(primitive_restart_enabled) { } // A less functor provided for std::map so it can find ranges. @@ -116,7 +118,10 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> { if (lhs.count_ != rhs.count_) { return lhs.count_ < rhs.count_; } - return lhs.type_ < rhs.type_; + if (lhs.type_ != rhs.type_) { + return lhs.type_ < rhs.type_; + } + return lhs.primitive_restart_enabled_ < rhs.primitive_restart_enabled_; } }; @@ -124,6 +129,7 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> { GLuint offset_; GLsizei count_; GLenum type_; + bool primitive_restart_enabled_; }; ~Buffer(); diff --git a/gpu/command_buffer/service/buffer_manager_unittest.cc b/gpu/command_buffer/service/buffer_manager_unittest.cc index 4c6707a..45e08c8 100644 --- a/gpu/command_buffer/service/buffer_manager_unittest.cc +++ b/gpu/command_buffer/service/buffer_manager_unittest.cc @@ -74,6 +74,158 @@ class BufferManagerTestBase : public GpuServiceTest { return success; } + void RunGetMaxValueForRangeUint8Test(bool enable_primitive_restart) + { + const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; + const GLuint kClientBufferId = 1; + const GLuint kServiceBufferId = 11; + const uint8_t data[] = {10, 9, 8, 7, 6, 0xFFu, 4, 3, 2, 1}; + const uint8_t new_data[] = {100, 120, 110}; + manager_->CreateBuffer(kClientBufferId, kServiceBufferId); + Buffer* buffer = manager_->GetBuffer(kClientBufferId); + ASSERT_TRUE(buffer != NULL); + manager_->SetTarget(buffer, kTarget); + DoBufferData( + buffer, kTarget, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR); + EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 0, sizeof(data), data)); + GLuint max_value; + // Check entire range succeeds. + EXPECT_TRUE(buffer->GetMaxValueForRange( + 0, 10, GL_UNSIGNED_BYTE, enable_primitive_restart, &max_value)); + if (enable_primitive_restart) { + EXPECT_EQ(10u, max_value); + } else { + EXPECT_EQ(0xFFu, max_value); + } + // Check sub range succeeds. + EXPECT_TRUE(buffer->GetMaxValueForRange( + 4, 3, GL_UNSIGNED_BYTE, enable_primitive_restart, &max_value)); + if (enable_primitive_restart) { + EXPECT_EQ(6u, max_value); + } else { + EXPECT_EQ(0xFFu, max_value); + } + // Check changing sub range succeeds. + EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 4, sizeof(new_data), + new_data)); + EXPECT_TRUE(buffer->GetMaxValueForRange( + 4, 3, GL_UNSIGNED_BYTE, enable_primitive_restart, &max_value)); + EXPECT_EQ(120u, max_value); + max_value = 0; + EXPECT_TRUE(buffer->GetMaxValueForRange( + 0, 10, GL_UNSIGNED_BYTE, enable_primitive_restart, &max_value)); + EXPECT_EQ(120u, max_value); + // Check out of range fails. + EXPECT_FALSE(buffer->GetMaxValueForRange( + 0, 11, GL_UNSIGNED_BYTE, enable_primitive_restart, &max_value)); + EXPECT_FALSE(buffer->GetMaxValueForRange( + 10, 1, GL_UNSIGNED_BYTE, enable_primitive_restart, &max_value)); + } + + void RunGetMaxValueForRangeUint16Test(bool enable_primitive_restart) { + const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; + const GLuint kClientBufferId = 1; + const GLuint kServiceBufferId = 11; + const uint16_t data[] = {10, 9, 8, 7, 6, 0xFFFF, 4, 3, 2, 1}; + const uint16_t new_data[] = {100, 120, 110}; + manager_->CreateBuffer(kClientBufferId, kServiceBufferId); + Buffer* buffer = manager_->GetBuffer(kClientBufferId); + ASSERT_TRUE(buffer != NULL); + manager_->SetTarget(buffer, kTarget); + DoBufferData( + buffer, kTarget, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR); + EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 0, sizeof(data), data)); + GLuint max_value; + // Check entire range succeeds. + EXPECT_TRUE(buffer->GetMaxValueForRange( + 0, 10, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); + if (enable_primitive_restart) { + EXPECT_EQ(10u, max_value); + } else { + EXPECT_EQ(0xFFFFu, max_value); + } + // Check odd offset fails for GL_UNSIGNED_SHORT. + EXPECT_FALSE(buffer->GetMaxValueForRange( + 1, 10, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); + // Check sub range succeeds. + EXPECT_TRUE(buffer->GetMaxValueForRange( + 8, 3, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); + if (enable_primitive_restart) { + EXPECT_EQ(6u, max_value); + } else { + EXPECT_EQ(0xFFFFu, max_value); + } + // Check changing sub range succeeds. + EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 8, sizeof(new_data), + new_data)); + EXPECT_TRUE(buffer->GetMaxValueForRange( + 8, 3, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); + EXPECT_EQ(120u, max_value); + max_value = 0; + EXPECT_TRUE(buffer->GetMaxValueForRange( + 0, 10, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); + EXPECT_EQ(120u, max_value); + // Check out of range fails. + EXPECT_FALSE(buffer->GetMaxValueForRange( + 0, 11, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); + EXPECT_FALSE(buffer->GetMaxValueForRange( + 20, 1, GL_UNSIGNED_SHORT, enable_primitive_restart, &max_value)); + } + + void RunGetMaxValueForRangeUint32Test(bool enable_primitive_restart) { + const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; + const GLuint kClientBufferId = 1; + const GLuint kServiceBufferId = 11; + const uint32_t data[] = {10, 9, 8, 7, 6, 0xFFFFFFFFu, 4, 3, 2, 1}; + const uint32_t new_data[] = {100, 120, 110}; + manager_->CreateBuffer(kClientBufferId, kServiceBufferId); + Buffer* buffer = manager_->GetBuffer(kClientBufferId); + ASSERT_TRUE(buffer != NULL); + manager_->SetTarget(buffer, kTarget); + DoBufferData( + buffer, kTarget, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR); + EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 0, sizeof(data), data)); + GLuint max_value; + // Check entire range succeeds. + EXPECT_TRUE(buffer->GetMaxValueForRange( + 0, 10, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); + if (enable_primitive_restart) { + EXPECT_EQ(10u, max_value); + } else { + EXPECT_EQ(0xFFFFFFFFu, max_value); + } + // Check non aligned offsets fails for GL_UNSIGNED_INT. + EXPECT_FALSE(buffer->GetMaxValueForRange( + 1, 10, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); + EXPECT_FALSE(buffer->GetMaxValueForRange( + 2, 10, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); + EXPECT_FALSE(buffer->GetMaxValueForRange( + 3, 10, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); + // Check sub range succeeds. + EXPECT_TRUE(buffer->GetMaxValueForRange( + 16, 3, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); + if (enable_primitive_restart) { + EXPECT_EQ(6u, max_value); + } else { + EXPECT_EQ(0xFFFFFFFFu, max_value); + } + // Check changing sub range succeeds. + EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 16, sizeof(new_data), + new_data)); + EXPECT_TRUE(buffer->GetMaxValueForRange( + 16, 3, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); + EXPECT_EQ(120u, max_value); + max_value = 0; + EXPECT_TRUE(buffer->GetMaxValueForRange( + 0, 10, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); + EXPECT_EQ(120u, max_value); + // Check out of range fails. + EXPECT_FALSE(buffer->GetMaxValueForRange( + 0, 11, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); + EXPECT_FALSE(buffer->GetMaxValueForRange( + 40, 1, GL_UNSIGNED_INT, enable_primitive_restart, &max_value)); + } + scoped_ptr<BufferManager> manager_; scoped_ptr<MockErrorState> error_state_; }; @@ -243,124 +395,27 @@ TEST_F(BufferManagerTest, GetRange) { } TEST_F(BufferManagerTest, GetMaxValueForRangeUint8) { - const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; - const GLuint kClientBufferId = 1; - const GLuint kServiceBufferId = 11; - const uint8_t data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; - const uint8_t new_data[] = {100, 120, 110}; - manager_->CreateBuffer(kClientBufferId, kServiceBufferId); - Buffer* buffer = manager_->GetBuffer(kClientBufferId); - ASSERT_TRUE(buffer != NULL); - manager_->SetTarget(buffer, kTarget); - DoBufferData( - buffer, kTarget, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR); - EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 0, sizeof(data), data)); - GLuint max_value; - // Check entire range succeeds. - EXPECT_TRUE(buffer->GetMaxValueForRange( - 0, 10, GL_UNSIGNED_BYTE, &max_value)); - EXPECT_EQ(10u, max_value); - // Check sub range succeeds. - EXPECT_TRUE(buffer->GetMaxValueForRange( - 4, 3, GL_UNSIGNED_BYTE, &max_value)); - EXPECT_EQ(6u, max_value); - // Check changing sub range succeeds. - EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 4, sizeof(new_data), new_data)); - EXPECT_TRUE(buffer->GetMaxValueForRange( - 4, 3, GL_UNSIGNED_BYTE, &max_value)); - EXPECT_EQ(120u, max_value); - max_value = 0; - EXPECT_TRUE(buffer->GetMaxValueForRange( - 0, 10, GL_UNSIGNED_BYTE, &max_value)); - EXPECT_EQ(120u, max_value); - // Check out of range fails. - EXPECT_FALSE(buffer->GetMaxValueForRange( - 0, 11, GL_UNSIGNED_BYTE, &max_value)); - EXPECT_FALSE(buffer->GetMaxValueForRange( - 10, 1, GL_UNSIGNED_BYTE, &max_value)); + RunGetMaxValueForRangeUint8Test(false); +} + +TEST_F(BufferManagerTest, GetMaxValueForRangeUint8PrimitiveRestart) { + RunGetMaxValueForRangeUint8Test(true); } TEST_F(BufferManagerTest, GetMaxValueForRangeUint16) { - const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; - const GLuint kClientBufferId = 1; - const GLuint kServiceBufferId = 11; - const uint16_t data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; - const uint16_t new_data[] = {100, 120, 110}; - manager_->CreateBuffer(kClientBufferId, kServiceBufferId); - Buffer* buffer = manager_->GetBuffer(kClientBufferId); - ASSERT_TRUE(buffer != NULL); - manager_->SetTarget(buffer, kTarget); - DoBufferData( - buffer, kTarget, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR); - EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 0, sizeof(data), data)); - GLuint max_value; - // Check entire range succeeds. - EXPECT_TRUE(buffer->GetMaxValueForRange( - 0, 10, GL_UNSIGNED_SHORT, &max_value)); - EXPECT_EQ(10u, max_value); - // Check odd offset fails for GL_UNSIGNED_SHORT. - EXPECT_FALSE(buffer->GetMaxValueForRange( - 1, 10, GL_UNSIGNED_SHORT, &max_value)); - // Check sub range succeeds. - EXPECT_TRUE(buffer->GetMaxValueForRange( - 8, 3, GL_UNSIGNED_SHORT, &max_value)); - EXPECT_EQ(6u, max_value); - // Check changing sub range succeeds. - EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 8, sizeof(new_data), new_data)); - EXPECT_TRUE(buffer->GetMaxValueForRange( - 8, 3, GL_UNSIGNED_SHORT, &max_value)); - EXPECT_EQ(120u, max_value); - max_value = 0; - EXPECT_TRUE(buffer->GetMaxValueForRange( - 0, 10, GL_UNSIGNED_SHORT, &max_value)); - EXPECT_EQ(120u, max_value); - // Check out of range fails. - EXPECT_FALSE(buffer->GetMaxValueForRange( - 0, 11, GL_UNSIGNED_SHORT, &max_value)); - EXPECT_FALSE(buffer->GetMaxValueForRange( - 20, 1, GL_UNSIGNED_SHORT, &max_value)); + RunGetMaxValueForRangeUint16Test(false); +} + +TEST_F(BufferManagerTest, GetMaxValueForRangeUint16PrimitiveRestart) { + RunGetMaxValueForRangeUint16Test(true); } TEST_F(BufferManagerTest, GetMaxValueForRangeUint32) { - const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER; - const GLuint kClientBufferId = 1; - const GLuint kServiceBufferId = 11; - const uint32_t data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; - const uint32_t new_data[] = {100, 120, 110}; - manager_->CreateBuffer(kClientBufferId, kServiceBufferId); - Buffer* buffer = manager_->GetBuffer(kClientBufferId); - ASSERT_TRUE(buffer != NULL); - manager_->SetTarget(buffer, kTarget); - DoBufferData( - buffer, kTarget, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR); - EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 0, sizeof(data), data)); - GLuint max_value; - // Check entire range succeeds. - EXPECT_TRUE( - buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, &max_value)); - EXPECT_EQ(10u, max_value); - // Check non aligned offsets fails for GL_UNSIGNED_INT. - EXPECT_FALSE( - buffer->GetMaxValueForRange(1, 10, GL_UNSIGNED_INT, &max_value)); - EXPECT_FALSE( - buffer->GetMaxValueForRange(2, 10, GL_UNSIGNED_INT, &max_value)); - EXPECT_FALSE( - buffer->GetMaxValueForRange(3, 10, GL_UNSIGNED_INT, &max_value)); - // Check sub range succeeds. - EXPECT_TRUE(buffer->GetMaxValueForRange(16, 3, GL_UNSIGNED_INT, &max_value)); - EXPECT_EQ(6u, max_value); - // Check changing sub range succeeds. - EXPECT_TRUE(DoBufferSubData(buffer, kTarget, 16, sizeof(new_data), new_data)); - EXPECT_TRUE(buffer->GetMaxValueForRange(16, 3, GL_UNSIGNED_INT, &max_value)); - EXPECT_EQ(120u, max_value); - max_value = 0; - EXPECT_TRUE(buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, &max_value)); - EXPECT_EQ(120u, max_value); - // Check out of range fails. - EXPECT_FALSE( - buffer->GetMaxValueForRange(0, 11, GL_UNSIGNED_INT, &max_value)); - EXPECT_FALSE( - buffer->GetMaxValueForRange(40, 1, GL_UNSIGNED_INT, &max_value)); + RunGetMaxValueForRangeUint32Test(false); +} + +TEST_F(BufferManagerTest, GetMaxValueForRangeUint32PrimitiveRestart) { + RunGetMaxValueForRangeUint32Test(true); } TEST_F(BufferManagerTest, UseDeletedBuffer) { @@ -420,7 +475,7 @@ TEST_F(BufferManagerTest, MaxValueCacheClearedCorrectly) { DoBufferData( buffer, kTarget, sizeof(data1), GL_STATIC_DRAW, data1, GL_NO_ERROR); EXPECT_TRUE( - buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, &max_value)); + buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, false, &max_value)); EXPECT_EQ(10u, max_value); // Check that any cached values are invalidated if the buffer is reloaded // with the same amount of data (but different content) @@ -428,7 +483,7 @@ TEST_F(BufferManagerTest, MaxValueCacheClearedCorrectly) { DoBufferData( buffer, kTarget, sizeof(data2), GL_STATIC_DRAW, data2, GL_NO_ERROR); EXPECT_TRUE( - buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, &max_value)); + buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, false, &max_value)); EXPECT_EQ(20u, max_value); // Check that any cached values are invalidated if the buffer is reloaded // with entirely different content. @@ -436,7 +491,7 @@ TEST_F(BufferManagerTest, MaxValueCacheClearedCorrectly) { DoBufferData( buffer, kTarget, sizeof(data3), GL_STATIC_DRAW, data3, GL_NO_ERROR); EXPECT_TRUE( - buffer->GetMaxValueForRange(0, 3, GL_UNSIGNED_INT, &max_value)); + buffer->GetMaxValueForRange(0, 3, GL_UNSIGNED_INT, false, &max_value)); EXPECT_EQ(30u, max_value); } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 7ecd8d5..92accd6 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -8343,7 +8343,9 @@ error::Error GLES2DecoderImpl::DoDrawElements(const char* function_name, state_.vertex_attrib_manager->element_array_buffer(); if (!element_array_buffer->GetMaxValueForRange( - offset, count, type, &max_vertex_accessed)) { + offset, count, type, + state_.enable_flags.primitive_restart_fixed_index, + &max_vertex_accessed)) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, function_name, "range out of bounds for buffer"); return error::kNoError; @@ -8440,8 +8442,18 @@ GLuint GLES2DecoderImpl::DoGetMaxValueInBufferCHROMIUM( LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "GetMaxValueInBufferCHROMIUM", "unknown buffer"); } else { + // The max value is used here to emulate client-side vertex + // arrays, by uploading enough vertices into buffer objects to + // cover the DrawElements call. Baking the primitive restart bit + // into this result isn't strictly correct in all cases; the + // client side code should pass down the bit and decide how to use + // the result. However, the only caller makes the draw call + // immediately afterward, so the state won't change between this + // query and the draw call. if (!buffer->GetMaxValueForRange( - offset, count, type, &max_vertex_accessed)) { + offset, count, type, + state_.enable_flags.primitive_restart_fixed_index, + &max_vertex_accessed)) { // TODO(gman): Should this be a GL error or a command buffer error? LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, |