summaryrefslogtreecommitdiffstats
path: root/gpu/command_buffer/service
diff options
context:
space:
mode:
authorgman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-05 05:04:28 +0000
committergman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-05 05:04:28 +0000
commita6eb5232d2608cd0773bbe559757bd52c7f53670 (patch)
treea2ab7e129ab4a9105d70f067983bcd1c24bfa839 /gpu/command_buffer/service
parentc620060371fe1832017570351139046ff8205fb4 (diff)
downloadchromium_src-a6eb5232d2608cd0773bbe559757bd52c7f53670.zip
chromium_src-a6eb5232d2608cd0773bbe559757bd52c7f53670.tar.gz
chromium_src-a6eb5232d2608cd0773bbe559757bd52c7f53670.tar.bz2
Implements index validation for DrawElements.
(note: I also forgot to check in the changes to build_gles2_cmd_buffer.py from my last CL so that's in here as well) TEST=various unit tests BUG=26101 Review URL: http://codereview.chromium.org/668131 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40713 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu/command_buffer/service')
-rw-r--r--gpu/command_buffer/service/buffer_manager.cc95
-rw-r--r--gpu/command_buffer/service/buffer_manager.h79
-rw-r--r--gpu/command_buffer/service/buffer_manager_unittest.cc83
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc112
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_autogen.h4
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc47
6 files changed, 339 insertions, 81 deletions
diff --git a/gpu/command_buffer/service/buffer_manager.cc b/gpu/command_buffer/service/buffer_manager.cc
index 2dfbc15..9b58e42 100644
--- a/gpu/command_buffer/service/buffer_manager.cc
+++ b/gpu/command_buffer/service/buffer_manager.cc
@@ -4,6 +4,7 @@
#include "gpu/command_buffer/service/buffer_manager.h"
#include "base/logging.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
namespace gpu {
@@ -31,10 +32,96 @@ void BufferManager::RemoveBufferInfo(GLuint buffer_id) {
}
}
-GLuint BufferManager::BufferInfo::GetMaxValueForRange(
- GLuint offset, GLsizei count, GLenum type) {
- // TODO(gman): Scan the values in the given range and cache their results.
- return 0u;
+void BufferManager::BufferInfo::SetSize(GLsizeiptr size) {
+ DCHECK(!IsDeleted());
+ if (size != size_) {
+ size_ = size;
+ ClearCache();
+ if (target_ == GL_ELEMENT_ARRAY_BUFFER) {
+ shadow_.reset(new int8[size]);
+ memset(shadow_.get(), 0, size);
+ }
+ }
+}
+
+bool BufferManager::BufferInfo::SetRange(
+ GLintptr offset, GLsizeiptr size, const GLvoid * data) {
+ DCHECK(!IsDeleted());
+ if (offset + size < offset ||
+ offset + size > size_) {
+ return false;
+ }
+ if (target_ == GL_ELEMENT_ARRAY_BUFFER) {
+ memcpy(shadow_.get() + offset, data, size);
+ ClearCache();
+ }
+ return true;
+}
+
+void BufferManager::BufferInfo::ClearCache() {
+ range_set_.clear();
+}
+
+template <typename T>
+GLuint GetMaxValue(const void* data, GLuint offset, GLsizei count) {
+ GLuint max_value = 0;
+ const T* element = reinterpret_cast<const T*>(
+ static_cast<const int8*>(data) + offset);
+ const T* end = element + count;
+ for (; element < end; ++element) {
+ if (*element > max_value) {
+ max_value = *element;
+ }
+ }
+ return max_value;
+}
+
+bool BufferManager::BufferInfo::GetMaxValueForRange(
+ GLuint offset, GLsizei count, GLenum type, GLuint* max_value) {
+ DCHECK_EQ(target_, static_cast<GLenum>(GL_ELEMENT_ARRAY_BUFFER));
+ DCHECK(!IsDeleted());
+ Range range(offset, count, type);
+ RangeToMaxValueMap::iterator it = range_set_.find(range);
+ if (it != range_set_.end()) {
+ *max_value = it->second;
+ return true;
+ }
+
+ uint32 size;
+ if (!SafeMultiplyUint32(
+ count, GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type), &size)) {
+ return false;
+ }
+
+ if (!SafeAddUint32(offset, size, &size)) {
+ return false;
+ }
+
+ if (size > static_cast<uint32>(size_)) {
+ return false;
+ }
+
+ // Scan the range for the max value and store
+ GLuint max_v = 0;
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ max_v = GetMaxValue<uint8>(shadow_.get(), offset, count);
+ 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>(shadow_.get(), offset, count);
+ break;
+ default:
+ NOTREACHED(); // should never get here by validation.
+ break;
+ }
+ std::pair<RangeToMaxValueMap::iterator, bool> result =
+ range_set_.insert(std::make_pair(range, max_v));
+ *max_value = max_v;
+ return true;
}
} // namespace gles2
diff --git a/gpu/command_buffer/service/buffer_manager.h b/gpu/command_buffer/service/buffer_manager.h
index e278a85..4afdaa0 100644
--- a/gpu/command_buffer/service/buffer_manager.h
+++ b/gpu/command_buffer/service/buffer_manager.h
@@ -7,7 +7,9 @@
#include <map>
#include "base/basictypes.h"
+#include "base/logging.h"
#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
#include "gpu/command_buffer/service/gl_utils.h"
namespace gpu {
@@ -27,6 +29,7 @@ class BufferManager {
explicit BufferInfo(GLuint buffer_id)
: buffer_id_(buffer_id),
+ target_(0),
size_(0) {
}
@@ -34,17 +37,32 @@ class BufferManager {
return buffer_id_;
}
+ GLenum target() const {
+ return target_;
+ }
+
+ void set_target(GLenum target) {
+ DCHECK_EQ(target_, 0u); // you can only set this once.
+ target_ = target;
+ }
+
GLsizeiptr size() const {
return size_;
}
- void set_size(GLsizeiptr size) {
- size_ = size;
- }
+ void SetSize(GLsizeiptr size);
+
+ // Sets a range of data for this buffer. Returns false if the offset or size
+ // is out of range.
+ bool SetRange(
+ GLintptr offset, GLsizeiptr size, const GLvoid * data);
- // Returns the maximum value in the buffer for the given range
- // interpreted as the given type.
- GLuint GetMaxValueForRange(GLuint offset, GLsizei count, GLenum type);
+ // Gets the maximum value in the buffer for the given range interpreted as
+ // the given type. Returns false if offset and count are out of range.
+ // offset is in bytes.
+ // count is in elements of type.
+ bool GetMaxValueForRange(GLuint offset, GLsizei count, GLenum type,
+ GLuint* max_value);
bool IsDeleted() {
return buffer_id_ == 0;
@@ -54,14 +72,63 @@ class BufferManager {
friend class BufferManager;
friend class base::RefCounted<BufferInfo>;
+ // Represents a range in a buffer.
+ class Range {
+ public:
+ Range(GLuint offset, GLsizei count, GLenum type)
+ : offset_(offset),
+ count_(count),
+ type_(type) {
+ }
+
+ // A less functor provided for std::map so it can find ranges.
+ struct Less {
+ bool operator() (const Range& lhs, const Range& rhs) {
+ if (lhs.offset_ != rhs.offset_) {
+ return lhs.offset_ < rhs.offset_;
+ }
+ if (lhs.count_ != rhs.count_) {
+ return lhs.count_ < rhs.count_;
+ }
+ return lhs.type_ < rhs.type_;
+ }
+ };
+
+ private:
+ GLuint offset_;
+ GLsizei count_;
+ GLenum type_;
+ };
+
~BufferInfo() { }
void MarkAsDeleted() {
buffer_id_ = 0;
+ shadow_.reset();
+ ClearCache();
}
+ // Clears any cache of index ranges.
+ void ClearCache();
+
+ // Service side buffer id.
GLuint buffer_id_;
+
+ // The type of buffer. 0 = unset, GL_BUFFER_ARRAY = vertex data,
+ // GL_ELEMENT_BUFFER_ARRAY = index data.
+ // Once set a buffer can not be used for something else.
+ GLenum target_;
+
+ // Size of buffer.
GLsizeiptr size_;
+
+ // A copy of the data in the buffer. This data is only kept if the target
+ // is GL_ELEMENT_BUFFER_ARRAY
+ scoped_array<int8> shadow_;
+
+ // A map of ranges to the highest value in that range of a certain type.
+ typedef std::map<Range, GLuint, Range::Less> RangeToMaxValueMap;
+ RangeToMaxValueMap range_set_;
};
BufferManager() { }
diff --git a/gpu/command_buffer/service/buffer_manager_unittest.cc b/gpu/command_buffer/service/buffer_manager_unittest.cc
index 2b121d8..df58915 100644
--- a/gpu/command_buffer/service/buffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/buffer_manager_unittest.cc
@@ -32,8 +32,14 @@ TEST_F(BufferManagerTest, Basic) {
// Check buffer got created.
BufferManager::BufferInfo* info1 = manager_.GetBufferInfo(kBuffer1Id);
ASSERT_TRUE(info1 != NULL);
+ EXPECT_EQ(0u, info1->target());
+ EXPECT_EQ(0, info1->size());
+ EXPECT_FALSE(info1->IsDeleted());
+ EXPECT_EQ(kBuffer1Id, info1->buffer_id());
+ info1->set_target(GL_ELEMENT_ARRAY_BUFFER);
+ EXPECT_EQ(GL_ELEMENT_ARRAY_BUFFER, info1->target());
// Check we and set its size.
- info1->set_size(kBuffer1Size);
+ info1->SetSize(kBuffer1Size);
EXPECT_EQ(kBuffer1Size, info1->size());
// Check we get nothing for a non-existent buffer.
EXPECT_TRUE(manager_.GetBufferInfo(kBuffer2Id) == NULL);
@@ -44,7 +50,80 @@ TEST_F(BufferManagerTest, Basic) {
EXPECT_TRUE(manager_.GetBufferInfo(kBuffer1Id) == NULL);
}
-// TODO(gman): Test GetMaxValueForRange.
+TEST_F(BufferManagerTest, SetRange) {
+ const GLuint kBufferId = 1;
+ const uint8 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ const uint8 new_data[] = {100, 120, 110};
+ manager_.CreateBufferInfo(kBufferId);
+ BufferManager::BufferInfo* info = manager_.GetBufferInfo(kBufferId);
+ ASSERT_TRUE(info != NULL);
+ info->set_target(GL_ELEMENT_ARRAY_BUFFER);
+ info->SetSize(sizeof(data));
+ EXPECT_TRUE(info->SetRange(0, sizeof(data), data));
+ EXPECT_TRUE(info->SetRange(sizeof(data), 0, data));
+ EXPECT_FALSE(info->SetRange(sizeof(data), 1, data));
+ EXPECT_FALSE(info->SetRange(0, sizeof(data) + 1, data));
+}
+
+TEST_F(BufferManagerTest, GetMaxValueForRangeUint8) {
+ const GLuint kBufferId = 1;
+ const uint8 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ const uint8 new_data[] = {100, 120, 110};
+ manager_.CreateBufferInfo(kBufferId);
+ BufferManager::BufferInfo* info = manager_.GetBufferInfo(kBufferId);
+ ASSERT_TRUE(info != NULL);
+ info->set_target(GL_ELEMENT_ARRAY_BUFFER);
+ info->SetSize(sizeof(data));
+ EXPECT_TRUE(info->SetRange(0, sizeof(data), data));
+ GLuint max_value;
+ // Check entire range succeeds.
+ EXPECT_TRUE(info->GetMaxValueForRange(0, 10, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_EQ(10u, max_value);
+ // Check sub range succeeds.
+ EXPECT_TRUE(info->GetMaxValueForRange(4, 3, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_EQ(6u, max_value);
+ // Check changing sub range succeeds.
+ EXPECT_TRUE(info->SetRange(4, sizeof(new_data), new_data));
+ EXPECT_TRUE(info->GetMaxValueForRange(4, 3, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_EQ(120u, max_value);
+ max_value = 0;
+ EXPECT_TRUE(info->GetMaxValueForRange(0, 10, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_EQ(120u, max_value);
+ // Check out of range fails.
+ EXPECT_FALSE(info->GetMaxValueForRange(0, 11, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_FALSE(info->GetMaxValueForRange(10, 1, GL_UNSIGNED_BYTE, &max_value));
+}
+
+TEST_F(BufferManagerTest, GetMaxValueForRangeUint16) {
+ const GLuint kBufferId = 1;
+ const uint16 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ const uint16 new_data[] = {100, 120, 110};
+ manager_.CreateBufferInfo(kBufferId);
+ BufferManager::BufferInfo* info = manager_.GetBufferInfo(kBufferId);
+ ASSERT_TRUE(info != NULL);
+ info->set_target(GL_ELEMENT_ARRAY_BUFFER);
+ info->SetSize(sizeof(data));
+ EXPECT_TRUE(info->SetRange(0, sizeof(data), data));
+ GLuint max_value;
+ // Check entire range succeeds.
+ EXPECT_TRUE(info->GetMaxValueForRange(0, 10, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_EQ(10u, max_value);
+ // Check odd offset fails for GL_UNSIGNED_SHORT.
+ EXPECT_FALSE(info->GetMaxValueForRange(1, 10, GL_UNSIGNED_SHORT, &max_value));
+ // Check sub range succeeds.
+ EXPECT_TRUE(info->GetMaxValueForRange(8, 3, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_EQ(6u, max_value);
+ // Check changing sub range succeeds.
+ EXPECT_TRUE(info->SetRange(8, sizeof(new_data), new_data));
+ EXPECT_TRUE(info->GetMaxValueForRange(8, 3, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_EQ(120u, max_value);
+ max_value = 0;
+ EXPECT_TRUE(info->GetMaxValueForRange(0, 10, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_EQ(120u, max_value);
+ // Check out of range fails.
+ EXPECT_FALSE(info->GetMaxValueForRange(0, 11, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_FALSE(info->GetMaxValueForRange(20, 1, GL_UNSIGNED_SHORT, &max_value));
+}
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 54cef89..dbb49e9 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -434,6 +434,14 @@ class GLES2DecoderImpl : public GLES2Decoder {
// Wrapper for glBindTexture since we need to track the current targets.
void DoBindTexture(GLenum target, GLuint texture);
+ // Wrapper for BufferData.
+ void DoBufferData(
+ GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage);
+
+ // Wrapper for BufferSubData.
+ void DoBufferSubData(
+ GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data);
+
// Wrapper for glCompileShader.
void DoCompileShader(GLuint shader);
@@ -1503,10 +1511,15 @@ void GLES2DecoderImpl::DoBindBuffer(GLenum target, GLuint buffer) {
BufferManager::BufferInfo* info = NULL;
if (buffer) {
info = GetBufferInfo(buffer);
- if (!info) {
+ // Check the buffer exists
+ // Check that we are not trying to bind it to a different target.
+ if (!info || (info->target() != 0 && info->target() != target)) {
SetGLError(GL_INVALID_OPERATION);
return;
}
+ if (info->target() == 0) {
+ info->set_target(target);
+ }
}
switch (target) {
case GL_ARRAY_BUFFER:
@@ -1919,28 +1932,19 @@ error::Error GLES2DecoderImpl::HandleDrawElements(
!ValidateGLenumIndexType(type)) {
SetGLError(GL_INVALID_ENUM);
} else {
- GLsizeiptr buffer_size = bound_element_array_buffer_->size();
- if (offset > buffer_size) {
+ GLuint max_vertex_accessed;
+ if (!bound_element_array_buffer_->GetMaxValueForRange(
+ offset, count, type, &max_vertex_accessed)) {
SetGLError(GL_INVALID_OPERATION);
} else {
- GLsizei usable_size = buffer_size - offset;
- GLsizei num_elements =
- usable_size / GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type);
- if (count > num_elements) {
- SetGLError(GL_INVALID_OPERATION);
- } else {
+ if (IsDrawValid(max_vertex_accessed)) {
+ bool has_non_renderable_textures;
+ SetBlackTextureForNonRenderableTextures(
+ &has_non_renderable_textures);
const GLvoid* indices = reinterpret_cast<const GLvoid*>(offset);
- GLuint max_vertex_accessed =
- bound_element_array_buffer_->GetMaxValueForRange(
- offset, count, type);
- if (IsDrawValid(max_vertex_accessed)) {
- bool has_non_renderable_textures;
- SetBlackTextureForNonRenderableTextures(
- &has_non_renderable_textures);
- glDrawElements(mode, count, type, indices);
- if (has_non_renderable_textures) {
- RestoreStateForNonRenderableTextures();
- }
+ glDrawElements(mode, count, type, indices);
+ if (has_non_renderable_textures) {
+ RestoreStateForNonRenderableTextures();
}
}
}
@@ -2272,33 +2276,21 @@ error::Error GLES2DecoderImpl::HandleGetString(
return error::kNoError;
}
-error::Error GLES2DecoderImpl::HandleBufferData(
- uint32 immediate_data_size, const gles2::BufferData& c) {
- GLenum target = static_cast<GLenum>(c.target);
- GLsizeiptr size = static_cast<GLsizeiptr>(c.size);
- uint32 data_shm_id = static_cast<uint32>(c.data_shm_id);
- uint32 data_shm_offset = static_cast<uint32>(c.data_shm_offset);
- GLenum usage = static_cast<GLenum>(c.usage);
- const void* data = NULL;
- if (data_shm_id != 0 || data_shm_offset != 0) {
- data = GetSharedMemoryAs<const void*>(data_shm_id, data_shm_offset, size);
- if (!data) {
- return error::kOutOfBounds;
- }
- }
+void GLES2DecoderImpl::DoBufferData(
+ GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage) {
if (!ValidateGLenumBufferTarget(target) ||
!ValidateGLenumBufferUsage(usage)) {
SetGLError(GL_INVALID_ENUM);
- return error::kNoError;
+ return;
}
if (size < 0) {
SetGLError(GL_INVALID_VALUE);
- return error::kNoError;
+ DoBufferData(target, size, data, usage);
}
BufferManager::BufferInfo* info = GetBufferInfoForTarget(target);
if (!info) {
SetGLError(GL_INVALID_OPERATION);
- return error::kNoError;
+ DoBufferData(target, size, data, usage);
}
// Clear the buffer to 0 if no initial data was passed in.
scoped_array<int8> zero;
@@ -2313,8 +2305,26 @@ error::Error GLES2DecoderImpl::HandleBufferData(
if (error != GL_NO_ERROR) {
SetGLError(error);
} else {
- info->set_size(size);
+ info->SetSize(size);
+ info->SetRange(0, size, data);
}
+}
+
+error::Error GLES2DecoderImpl::HandleBufferData(
+ uint32 immediate_data_size, const gles2::BufferData& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLsizeiptr size = static_cast<GLsizeiptr>(c.size);
+ uint32 data_shm_id = static_cast<uint32>(c.data_shm_id);
+ uint32 data_shm_offset = static_cast<uint32>(c.data_shm_offset);
+ GLenum usage = static_cast<GLenum>(c.usage);
+ const void* data = NULL;
+ if (data_shm_id != 0 || data_shm_offset != 0) {
+ data = GetSharedMemoryAs<const void*>(data_shm_id, data_shm_offset, size);
+ if (!data) {
+ return error::kOutOfBounds;
+ }
+ }
+ DoBufferData(target, size, data, usage);
return error::kNoError;
}
@@ -2328,29 +2338,21 @@ error::Error GLES2DecoderImpl::HandleBufferDataImmediate(
return error::kOutOfBounds;
}
GLenum usage = static_cast<GLenum>(c.usage);
- if (!ValidateGLenumBufferTarget(target) ||
- !ValidateGLenumBufferUsage(usage)) {
- SetGLError(GL_INVALID_ENUM);
- return error::kNoError;
- }
- if (size < 0) {
- SetGLError(GL_INVALID_VALUE);
- return error::kNoError;
- }
+ DoBufferData(target, size, data, usage);
+ return error::kNoError;
+}
+
+void GLES2DecoderImpl::DoBufferSubData(
+ GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data) {
BufferManager::BufferInfo* info = GetBufferInfoForTarget(target);
if (!info) {
SetGLError(GL_INVALID_OPERATION);
- return error::kNoError;
}
- CopyRealGLErrorsToWrapper();
- glBufferData(target, size, data, usage);
- GLenum error = glGetError();
- if (error != GL_NO_ERROR) {
- SetGLError(error);
+ if (!info->SetRange(offset, size, data)) {
+ SetGLError(GL_INVALID_VALUE);
} else {
- info->set_size(size);
+ glBufferSubData(target, offset, size, data);
}
- return error::kNoError;
}
error::Error GLES2DecoderImpl::DoCompressedTexImage2D(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 025e0b3..eb66e7f 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -231,7 +231,7 @@ error::Error GLES2DecoderImpl::HandleBufferSubData(
if (data == NULL) {
return error::kOutOfBounds;
}
- glBufferSubData(target, offset, size, data);
+ DoBufferSubData(target, offset, size, data);
return error::kNoError;
}
@@ -254,7 +254,7 @@ error::Error GLES2DecoderImpl::HandleBufferSubDataImmediate(
if (data == NULL) {
return error::kOutOfBounds;
}
- glBufferSubData(target, offset, size, data);
+ DoBufferSubData(target, offset, size, data);
return error::kNoError;
}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 5f96cd5..9228165 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -194,12 +194,12 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsNoAttributesSucceeds) {
SetupIndexBuffer();
EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount,
GL_UNSIGNED_SHORT,
- BufferOffset(kValidIndexRangeStart)))
+ BufferOffset(kValidIndexRangeStart * 2)))
.Times(1)
.RetiresOnSaturation();
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
- kValidIndexRangeStart);
+ kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
@@ -212,7 +212,7 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsMissingAttributesFails) {
.Times(0);
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
- kValidIndexRangeStart);
+ kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
@@ -225,12 +225,12 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsValidAttributesSucceeds) {
EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount,
GL_UNSIGNED_SHORT,
- BufferOffset(kValidIndexRangeStart)))
+ BufferOffset(kValidIndexRangeStart * 2)))
.Times(1)
.RetiresOnSaturation();
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
- kValidIndexRangeStart);
+ kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
@@ -245,7 +245,7 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsDeletedBufferFails) {
.Times(0);
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
- kValidIndexRangeStart);
+ kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
@@ -260,7 +260,7 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsDeletedProgramSucceedsNoGLCall) {
.Times(0);
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
- kValidIndexRangeStart);
+ kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
@@ -274,7 +274,7 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsWithInvalidModeFails) {
.Times(0);
DrawElements cmd;
cmd.Init(GL_QUADS, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
- kValidIndexRangeStart);
+ kValidIndexRangeStart * 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
cmd.Init(GL_POLYGON, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
@@ -291,7 +291,7 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsInvalidCountFails) {
// Try start > 0
EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
DrawElements cmd;
- cmd.Init(GL_TRIANGLES, kNumIndices, GL_UNSIGNED_SHORT, 1);
+ cmd.Init(GL_TRIANGLES, kNumIndices, GL_UNSIGNED_SHORT, 2);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
EXPECT_EQ(GL_NO_ERROR, GetGLError());
@@ -303,7 +303,6 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsInvalidCountFails) {
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
-#if 0 // TODO(gman): Turn on this test once buffer validation is in
TEST_F(GLES2DecoderWithShaderTest, DrawElementsOutOfRangeIndicesFails) {
SetupVertexBuffer();
SetupIndexBuffer();
@@ -312,12 +311,24 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsOutOfRangeIndicesFails) {
EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
DrawElements cmd;
cmd.Init(GL_TRIANGLES, kInvalidIndexRangeCount, GL_UNSIGNED_SHORT,
- kInvalidIndexRangeStart);
+ kInvalidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsOddOffsetForUint16Fails) {
+ SetupVertexBuffer();
+ SetupIndexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kInvalidIndexRangeCount, GL_UNSIGNED_SHORT, 1);
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
-#endif
TEST_F(GLES2DecoderWithShaderTest, GetVertexAttribPointervSucceeds) {
const float dummy = 0;
@@ -990,6 +1001,18 @@ TEST_F(GLES2DecoderWithShaderTest, Uniform1ivImmediateValidArgs) {
ExecuteImmediateCmd(cmd, sizeof(temp)));
}
+TEST_F(GLES2DecoderWithShaderTest, BindBufferToDifferentTargetFails) {
+ // Bind the buffer to GL_ARRAY_BUFFER
+ DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
+ // Attempt to rebind to GL_ELEMENT_ARRAY_BUFFER
+ // NOTE: Real GLES2 does not have this restriction but WebGL and we do.
+ EXPECT_CALL(*gl_, BindBuffer(_, _))
+ .Times(0);
+ BindBuffer cmd;
+ cmd.Init(GL_ELEMENT_ARRAY_BUFFER, client_buffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
// TODO(gman): BindAttribLocation