summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorgman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-18 18:43:40 +0000
committergman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-18 18:43:40 +0000
commit8fbedc0f80187f0244b952979ee32396d84d4823 (patch)
treea584f7ac105bf685b4a3e91d5930e718a3ab7aae /gpu
parentedb22cfd39987c08be44997d9f2bc75f7721ce13 (diff)
downloadchromium_src-8fbedc0f80187f0244b952979ee32396d84d4823.zip
chromium_src-8fbedc0f80187f0244b952979ee32396d84d4823.tar.gz
chromium_src-8fbedc0f80187f0244b952979ee32396d84d4823.tar.bz2
Adds support for GL_FIXED vertex attributes.
Similar to sharing VBOs for both index buffers and vertex buffers this support is off by default but is turned on in the OpenGL ES 2.0 conformance tests (another CL) We can decide how/if to expose it to Pepper later if we want to claim Pepper is Open GL ES 2.0 conformant. TEST=The GL_FIXED OpenGL ES 2.0 conformance tests passes BUG=none Review URL: http://codereview.chromium.org/5026003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66649 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rw-r--r--gpu/GLES2/gles2_command_buffer.h2
-rw-r--r--gpu/command_buffer/common/gles2_cmd_utils.cc2
-rw-r--r--gpu/command_buffer/service/buffer_manager.cc11
-rw-r--r--gpu/command_buffer/service/buffer_manager.h3
-rw-r--r--gpu/command_buffer/service/buffer_manager_unittest.cc18
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc237
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc19
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h1
8 files changed, 249 insertions, 44 deletions
diff --git a/gpu/GLES2/gles2_command_buffer.h b/gpu/GLES2/gles2_command_buffer.h
index 3f6b39d..30bc7a7 100644
--- a/gpu/GLES2/gles2_command_buffer.h
+++ b/gpu/GLES2/gles2_command_buffer.h
@@ -11,6 +11,8 @@
// constants for CommandBufferEnable command.
#define PEPPER3D_ALLOW_BUFFERS_ON_MULTIPLE_TARGETS \
"pepper3d_allow_buffers_on_multiple_targets"
+#define PEPPER3D_SUPPORT_FIXED_ATTRIBS \
+ "pepper3d_support_fixed_attribs"
// TODO(gman): remove this
#define PEPPER3D_SKIP_GLSL_TRANSLATION \
"pepper3d_skip_glsl_translation"
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc
index b9806ab..e4f9c8c 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -444,6 +444,8 @@ size_t GLES2Util::GetGLTypeSizeForTexturesAndBuffers(uint32 type) {
return sizeof(GLuint); // NOLINT
case GL_FLOAT:
return sizeof(GLfloat); // NOLINT
+ case GL_FIXED:
+ return sizeof(GLfixed); // NOLINT
default:
return 0;
}
diff --git a/gpu/command_buffer/service/buffer_manager.cc b/gpu/command_buffer/service/buffer_manager.cc
index 70c5ccb..07a9753 100644
--- a/gpu/command_buffer/service/buffer_manager.cc
+++ b/gpu/command_buffer/service/buffer_manager.cc
@@ -79,8 +79,7 @@ void BufferManager::BufferInfo::SetSize(GLsizeiptr size, bool shadow) {
bool BufferManager::BufferInfo::SetRange(
GLintptr offset, GLsizeiptr size, const GLvoid * data) {
DCHECK(!IsDeleted());
- if (offset + size < offset ||
- offset + size > size_) {
+ if (offset + size < offset || offset + size > size_) {
return false;
}
if (shadowed_) {
@@ -90,6 +89,14 @@ bool BufferManager::BufferInfo::SetRange(
return true;
}
+const void* BufferManager::BufferInfo::GetRange(
+ GLintptr offset, GLsizeiptr size) const {
+ if (!shadowed_ || (offset + size < offset || offset + size > size_)) {
+ return NULL;
+ }
+ return shadow_.get() + offset;
+}
+
void BufferManager::BufferInfo::ClearCache() {
range_set_.clear();
}
diff --git a/gpu/command_buffer/service/buffer_manager.h b/gpu/command_buffer/service/buffer_manager.h
index 86f6bb8..81ad2af 100644
--- a/gpu/command_buffer/service/buffer_manager.h
+++ b/gpu/command_buffer/service/buffer_manager.h
@@ -49,6 +49,9 @@ class BufferManager {
bool GetMaxValueForRange(GLuint offset, GLsizei count, GLenum type,
GLuint* max_value);
+ // Returns a pointer to shadowed data.
+ const void* GetRange(GLintptr offset, GLsizeiptr size) const;
+
bool IsDeleted() {
return service_id_ == 0;
}
diff --git a/gpu/command_buffer/service/buffer_manager_unittest.cc b/gpu/command_buffer/service/buffer_manager_unittest.cc
index 3f4a66b..37bd00f 100644
--- a/gpu/command_buffer/service/buffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/buffer_manager_unittest.cc
@@ -101,6 +101,24 @@ TEST_F(BufferManagerTest, SetRange) {
EXPECT_FALSE(info->SetRange(0, sizeof(data) + 1, data));
}
+TEST_F(BufferManagerTest, GetRange) {
+ const GLuint kClientBufferId = 1;
+ const GLuint kServiceBufferId = 11;
+ const uint8 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ manager_.CreateBufferInfo(kClientBufferId, kServiceBufferId);
+ BufferManager::BufferInfo* info = manager_.GetBufferInfo(kClientBufferId);
+ ASSERT_TRUE(info != NULL);
+ manager_.SetTarget(info, GL_ELEMENT_ARRAY_BUFFER);
+ manager_.SetSize(info, sizeof(data));
+ const char* buf = static_cast<const char*>(info->GetRange(0, sizeof(data)));
+ ASSERT_TRUE(buf != NULL);
+ const char* buf1 =
+ static_cast<const char*>(info->GetRange(1, sizeof(data) - 1));
+ EXPECT_EQ(buf + 1, buf1);
+ EXPECT_TRUE(info->GetRange(sizeof(data), 1) == NULL);
+ EXPECT_TRUE(info->GetRange(0, sizeof(data) + 1) == NULL);
+}
+
TEST_F(BufferManagerTest, GetMaxValueForRangeUint8) {
const GLuint kClientBufferId = 1;
const GLuint kServiceBufferId = 11;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index c8883af..5927914 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -448,28 +448,6 @@ class VertexAttribManager {
return gl_stride_;
}
- void SetInfo(
- BufferManager::BufferInfo* buffer,
- GLint size,
- GLenum type,
- GLboolean normalized,
- GLsizei gl_stride,
- GLsizei real_stride,
- GLsizei offset) {
- DCHECK_GT(real_stride, 0);
- buffer_ = buffer;
- size_ = size;
- type_ = type;
- normalized_ = normalized;
- gl_stride_ = gl_stride;
- real_stride_ = real_stride;
- offset_ = offset;
- }
-
- void ClearBuffer() {
- buffer_ = NULL;
- }
-
bool enabled() const {
return enabled_;
}
@@ -504,6 +482,24 @@ class VertexAttribManager {
list_ = new_list;
}
+ void SetInfo(
+ BufferManager::BufferInfo* buffer,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei gl_stride,
+ GLsizei real_stride,
+ GLsizei offset) {
+ DCHECK_GT(real_stride, 0);
+ buffer_ = buffer;
+ size_ = size;
+ type_ = type;
+ normalized_ = normalized;
+ gl_stride_ = gl_stride;
+ real_stride_ = real_stride;
+ offset_ = offset;
+ }
+
// The index of this attrib.
GLuint index_;
@@ -545,13 +541,18 @@ class VertexAttribManager {
typedef std::list<VertexAttribInfo*> VertexAttribInfoList;
VertexAttribManager()
- : max_vertex_attribs_(0) {
+ : max_vertex_attribs_(0),
+ num_fixed_attribs_(0) {
}
void Initialize(uint32 num_vertex_attribs);
bool Enable(GLuint index, bool enable);
+ bool HaveFixedAttribs() const {
+ return num_fixed_attribs_ != 0;
+ }
+
const VertexAttribInfoList& GetEnabledVertexAttribInfos() const {
return enabled_vertex_attribs_;
}
@@ -563,9 +564,35 @@ class VertexAttribManager {
return NULL;
}
+ void SetAttribInfo(
+ GLuint index,
+ BufferManager::BufferInfo* buffer,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei gl_stride,
+ GLsizei real_stride,
+ GLsizei offset) {
+ VertexAttribInfo* info = GetVertexAttribInfo(index);
+ if (info) {
+ if (info->type() == GL_FIXED) {
+ --num_fixed_attribs_;
+ }
+ if (type == GL_FIXED) {
+ ++num_fixed_attribs_;
+ }
+ info->SetInfo(
+ buffer, size, type, normalized, gl_stride, real_stride, offset);
+ }
+ }
+
+
private:
uint32 max_vertex_attribs_;
+ // number of attribs using type GL_FIXED.
+ int num_fixed_attribs_;
+
// Info for each vertex attribute saved so we can check at glDrawXXX time
// if it is safe to draw.
scoped_array<VertexAttribInfo> vertex_attrib_infos_;
@@ -1204,6 +1231,10 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
bool SetBlackTextureForNonRenderableTextures();
void RestoreStateForNonRenderableTextures();
+ // Returns true if GL_FIXED attribs were simulated.
+ bool SimulateFixedAttribs(GLuint max_vertex_accessed, bool* simulated);
+ void RestoreStateForSimulatedFixedAttribs();
+
// Gets the buffer id for a given target.
BufferManager::BufferInfo* GetBufferInfoForTarget(GLenum target) {
DCHECK(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER);
@@ -1328,6 +1359,12 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
// The size of attrib 0.
GLsizei attrib_0_size_;
+ // The buffer used to simulate GL_FIXED attribs.
+ GLuint fixed_attrib_buffer_id_;
+
+ // The size of fiixed attrib buffer.
+ GLsizei fixed_attrib_buffer_size_;
+
// Current active texture by 0 - n index.
// In other words, if we call glActiveTexture(GL_TEXTURE2) this value would
// be 2.
@@ -1695,6 +1732,8 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group)
unpack_alignment_(4),
attrib_0_buffer_id_(0),
attrib_0_size_(0),
+ fixed_attrib_buffer_id_(0),
+ fixed_attrib_buffer_size_(0),
active_texture_unit_(0),
clear_red_(0),
clear_green_(0),
@@ -1777,6 +1816,7 @@ bool GLES2DecoderImpl::Initialize(gfx::GLContext* context,
glBindBuffer(GL_ARRAY_BUFFER, attrib_0_buffer_id_);
glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glGenBuffersARB(1, &fixed_attrib_buffer_id_);
texture_units_.reset(
new TextureUnit[group_->max_texture_units()]);
@@ -2405,6 +2445,9 @@ void GLES2DecoderImpl::Destroy() {
if (attrib_0_buffer_id_) {
glDeleteBuffersARB(1, &attrib_0_buffer_id_);
}
+ if (fixed_attrib_buffer_id_) {
+ glDeleteBuffersARB(1, &fixed_attrib_buffer_id_);
+ }
// Remove the saved frame buffer mapping from the parent decoder. The
// parent pointer is a weak pointer so it will be null if the parent has
@@ -3216,12 +3259,19 @@ void GLES2DecoderImpl::DoDrawArrays(
return;
}
- if (IsDrawValid(first + count - 1)) {
- bool simulated_attrib_0 = SimulateAttrib0(first + count - 1);
- bool textures_set = SetBlackTextureForNonRenderableTextures();
- glDrawArrays(mode, first, count);
- if (textures_set) {
- RestoreStateForNonRenderableTextures();
+ GLuint max_vertex_accessed = first + count - 1;
+ if (IsDrawValid(max_vertex_accessed)) {
+ bool simulated_attrib_0 = SimulateAttrib0(max_vertex_accessed);
+ bool simulated_fixed_attribs = false;
+ if (SimulateFixedAttribs(max_vertex_accessed, &simulated_fixed_attribs)) {
+ bool textures_set = SetBlackTextureForNonRenderableTextures();
+ glDrawArrays(mode, first, count);
+ if (textures_set) {
+ RestoreStateForNonRenderableTextures();
+ }
+ if (simulated_fixed_attribs) {
+ RestoreStateForSimulatedFixedAttribs();
+ }
}
if (simulated_attrib_0) {
RestoreStateForSimulatedAttrib0();
@@ -3877,7 +3927,7 @@ bool GLES2DecoderImpl::IsDrawValid(GLuint max_vertex_accessed) {
const VertexAttribManager::VertexAttribInfoList& infos =
vertex_attrib_manager_.GetEnabledVertexAttribInfos();
for (VertexAttribManager::VertexAttribInfoList::const_iterator it =
- infos.begin(); it != infos.end(); ++it) {
+ infos.begin(); it != infos.end(); ++it) {
const VertexAttribManager::VertexAttribInfo* info = *it;
const ProgramManager::ProgramInfo::VertexAttribInfo* attrib_info =
current_program_->GetAttribInfoByLocation(info->index());
@@ -3958,6 +4008,98 @@ void GLES2DecoderImpl::RestoreStateForSimulatedAttrib0() {
bound_array_buffer_ ? bound_array_buffer_->service_id() : 0);
}
+bool GLES2DecoderImpl::SimulateFixedAttribs(
+ GLuint max_vertex_accessed, bool* simulated) {
+ DCHECK(simulated);
+ *simulated = false;
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2)
+ return true;
+
+ if (!vertex_attrib_manager_.HaveFixedAttribs()) {
+ return true;
+ }
+
+ // NOTE: we could be smart and try to check if a buffer is used
+ // twice in 2 different attribs, find the overlapping parts and therefore
+ // duplicate the minimum amount of data but this whole code path is not meant
+ // 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.
+ int num_vertices = max_vertex_accessed + 1;
+ int elements_needed = 0;
+ const VertexAttribManager::VertexAttribInfoList& infos =
+ vertex_attrib_manager_.GetEnabledVertexAttribInfos();
+ for (VertexAttribManager::VertexAttribInfoList::const_iterator it =
+ infos.begin(); it != infos.end(); ++it) {
+ const VertexAttribManager::VertexAttribInfo* info = *it;
+ const ProgramManager::ProgramInfo::VertexAttribInfo* attrib_info =
+ current_program_->GetAttribInfoByLocation(info->index());
+ if (attrib_info &&
+ info->CanAccess(max_vertex_accessed) &&
+ info->type() == GL_FIXED) {
+ int elements_used = 0;
+ if (!SafeMultiply(
+ static_cast<int>(num_vertices),
+ info->size(), &elements_used) ||
+ !SafeAdd(elements_needed, elements_used, &elements_needed)) {
+ SetGLError(GL_OUT_OF_MEMORY, "glDrawXXX: simulating GL_FIXED attribs");
+ return false;
+ }
+ }
+ }
+
+ const int kSizeOfFloat = sizeof(float); // NOLINT
+ int size_needed = 0;
+ if (!SafeMultiply(elements_needed, kSizeOfFloat, &size_needed)) {
+ SetGLError(GL_OUT_OF_MEMORY, "glDrawXXX: simulating GL_FIXED attribs");
+ return false;
+ }
+
+
+ glBindBuffer(GL_ARRAY_BUFFER, fixed_attrib_buffer_id_);
+ if (size_needed > fixed_attrib_buffer_size_) {
+ glBufferData(GL_ARRAY_BUFFER, size_needed, NULL, GL_DYNAMIC_DRAW);
+ }
+
+ // Copy the elements and convert to float
+ GLintptr offset = 0;
+ for (VertexAttribManager::VertexAttribInfoList::const_iterator it =
+ infos.begin(); it != infos.end(); ++it) {
+ const VertexAttribManager::VertexAttribInfo* info = *it;
+ const ProgramManager::ProgramInfo::VertexAttribInfo* attrib_info =
+ current_program_->GetAttribInfoByLocation(info->index());
+ if (attrib_info &&
+ info->CanAccess(max_vertex_accessed) &&
+ info->type() == GL_FIXED) {
+ int num_elements = info->size() * kSizeOfFloat;
+ int size = num_elements * num_vertices;
+ scoped_array<float> data(new float[size]);
+ const int32* src = reinterpret_cast<const int32 *>(
+ info->buffer()->GetRange(info->offset(), size));
+ const int32* end = src + num_elements;
+ float* dst = data.get();
+ while (src != end) {
+ *dst++ = static_cast<float>(*src++) / 65536.0f;
+ }
+ glBufferSubData(GL_ARRAY_BUFFER, offset, size, data.get());
+ glVertexAttribPointer(
+ info->index(), info->size(), GL_FLOAT, false, 0,
+ reinterpret_cast<GLvoid*>(offset));
+ offset += size;
+ }
+ }
+ *simulated = true;
+ return true;
+}
+
+void GLES2DecoderImpl::RestoreStateForSimulatedFixedAttribs() {
+ // There's no need to call glVertexAttribPointer because we shadow all the
+ // settings and passing GL_FIXED to it will not work.
+ glBindBuffer(GL_ARRAY_BUFFER,
+ bound_array_buffer_ ? bound_array_buffer_->service_id() : 0);
+}
+
error::Error GLES2DecoderImpl::HandleDrawElements(
uint32 immediate_data_size, const gles2::DrawElements& c) {
if (!bound_element_array_buffer_ ||
@@ -4002,11 +4144,17 @@ error::Error GLES2DecoderImpl::HandleDrawElements(
if (IsDrawValid(max_vertex_accessed)) {
bool simulated_attrib_0 = SimulateAttrib0(max_vertex_accessed);
- bool textures_set = SetBlackTextureForNonRenderableTextures();
- const GLvoid* indices = reinterpret_cast<const GLvoid*>(offset);
- glDrawElements(mode, count, type, indices);
- if (textures_set) {
- RestoreStateForNonRenderableTextures();
+ bool simulated_fixed_attribs = false;
+ if (SimulateFixedAttribs(max_vertex_accessed, &simulated_fixed_attribs)) {
+ bool textures_set = SetBlackTextureForNonRenderableTextures();
+ const GLvoid* indices = reinterpret_cast<const GLvoid*>(offset);
+ glDrawElements(mode, count, type, indices);
+ if (textures_set) {
+ RestoreStateForNonRenderableTextures();
+ }
+ if (simulated_fixed_attribs) {
+ RestoreStateForSimulatedFixedAttribs();
+ }
}
if (simulated_attrib_0) {
RestoreStateForSimulatedAttrib0();
@@ -4540,7 +4688,8 @@ error::Error GLES2DecoderImpl::HandleVertexAttribPointer(
"glVertexAttribPointer: stride not valid for type");
return error::kNoError;
}
- vertex_attrib_manager_.GetVertexAttribInfo(indx)->SetInfo(
+ vertex_attrib_manager_.SetAttribInfo(
+ indx,
bound_array_buffer_,
size,
type,
@@ -4548,7 +4697,9 @@ error::Error GLES2DecoderImpl::HandleVertexAttribPointer(
stride,
stride != 0 ? stride : component_size * size,
offset);
- glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
+ if (type != GL_FIXED) {
+ glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
+ }
return error::kNoError;
}
@@ -5745,6 +5896,18 @@ error::Error GLES2DecoderImpl::HandleCommandBufferEnable(
// TODO(gman): make this some kind of table to function pointer thingy.
if (feature_str.compare(PEPPER3D_ALLOW_BUFFERS_ON_MULTIPLE_TARGETS) == 0) {
buffer_manager()->set_allow_buffers_on_multiple_targets(true);
+ } else if (feature_str.compare(PEPPER3D_SUPPORT_FIXED_ATTRIBS) == 0) {
+ buffer_manager()->set_allow_buffers_on_multiple_targets(true);
+ // TODO(gman): decide how to remove the need for this const_cast.
+ // I could make validators_ non const but that seems bad as this is the only
+ // place it is needed. I could make some special friend class of validators
+ // just to allow this to set them. That seems silly. I could refactor this
+ // code to use the extension mechanism or the initialization attributes to
+ // turn this feature on. Given that the only real point of this is to make
+ // the conformance tests pass and given that there is lots of real work that
+ // needs to be done it seems like refactoring for one to one of those
+ // methods is a very low priority.
+ const_cast<Validators*>(validators_)->vertex_attrib_type.AddValue(GL_FIXED);
} else if (feature_str.compare(PEPPER3D_SKIP_GLSL_TRANSLATION) == 0) {
use_shader_translator_ = false;
} else {
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 e253a73..1b082dd 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -50,12 +50,15 @@ void GLES2DecoderTestBase::InitDecoder(const char* extensions) {
EXPECT_CALL(*gl_, EnableVertexAttribArray(0))
.Times(1)
.RetiresOnSaturation();
- static GLuint attrib_ids[] = {
+ static GLuint attrib_0_id[] = {
kServiceAttrib0BufferId,
};
- EXPECT_CALL(*gl_, GenBuffersARB(arraysize(attrib_ids), _))
- .WillOnce(SetArrayArgument<1>(attrib_ids,
- attrib_ids + arraysize(attrib_ids)))
+ static GLuint fixed_attrib_buffer_id[] = {
+ kServiceFixedAttribBufferId,
+ };
+ EXPECT_CALL(*gl_, GenBuffersARB(arraysize(attrib_0_id), _))
+ .WillOnce(SetArrayArgument<1>(attrib_0_id,
+ attrib_0_id + arraysize(attrib_0_id)))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, kServiceAttrib0BufferId))
.Times(1)
@@ -66,6 +69,11 @@ void GLES2DecoderTestBase::InitDecoder(const char* extensions) {
EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, 0))
.Times(1)
.RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GenBuffersARB(arraysize(fixed_attrib_buffer_id), _))
+ .WillOnce(SetArrayArgument<1>(
+ fixed_attrib_buffer_id,
+ fixed_attrib_buffer_id + arraysize(fixed_attrib_buffer_id)))
+ .RetiresOnSaturation();
for (GLint tt = 0; tt < TestHelper::kNumTextureUnits; ++tt) {
EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0 + tt))
@@ -146,7 +154,7 @@ void GLES2DecoderTestBase::TearDown() {
// All Tests should have read all their GLErrors before getting here.
EXPECT_EQ(GL_NO_ERROR, GetGLError());
EXPECT_CALL(*gl_, DeleteBuffersARB(1, _))
- .Times(1)
+ .Times(2)
.RetiresOnSaturation();
decoder_->Destroy();
decoder_.reset();
@@ -394,6 +402,7 @@ const GLint GLES2DecoderTestBase::kMaxVaryingVectors;
const GLint GLES2DecoderTestBase::kMaxVertexUniformVectors;
const GLuint GLES2DecoderTestBase::kServiceAttrib0BufferId;
+const GLuint GLES2DecoderTestBase::kServiceFixedAttribBufferId;
const GLuint GLES2DecoderTestBase::kServiceBufferId;
const GLuint GLES2DecoderTestBase::kServiceFramebufferId;
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 d5981c7..a6c8cad 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -49,6 +49,7 @@ class GLES2DecoderTestBase : public testing::Test {
static const GLint kMaxVertexUniformVectors = 128;
static const GLuint kServiceAttrib0BufferId = 801;
+ static const GLuint kServiceFixedAttribBufferId = 802;
static const GLuint kServiceBufferId = 301;
static const GLuint kServiceFramebufferId = 302;