summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gpu/command_buffer/client/gles2_implementation.cc4
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc238
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc13
-rw-r--r--gpu/command_buffer/service/program_manager.cc35
-rw-r--r--gpu/command_buffer/service/program_manager.h16
5 files changed, 228 insertions, 78 deletions
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 8d7c57f..f460329 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -108,8 +108,8 @@ class ClientSideBufferHelper {
VertexAttribInfo()
: enabled_(false),
buffer_id_(0),
- size_(0),
- type_(0),
+ size_(4),
+ type_(GL_FLOAT),
normalized_(GL_FALSE),
pointer_(NULL),
gl_stride_(0) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 74b0385..5fa47fc 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -7,9 +7,10 @@
#include <stdio.h>
#include <algorithm>
-#include <vector>
-#include <string>
+#include <list>
#include <map>
+#include <string>
+#include <vector>
#include "app/gfx/gl/gl_context.h"
#include "base/callback.h"
@@ -292,32 +293,27 @@ GLES2Decoder::GLES2Decoder(ContextGroup* group)
GLES2Decoder::~GLES2Decoder() {
}
-// This class implements GLES2Decoder so we don't have to expose all the GLES2
-// cmd stuff to outside this class.
-class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
- public GLES2Decoder {
+class VertexAttribManager {
public:
- explicit GLES2DecoderImpl(ContextGroup* group);
-
// Info about Vertex Attributes. This is used to track what the user currently
// has bound on each Vertex Attribute so that checking can be done at
// glDrawXXX time.
class VertexAttribInfo {
public:
+ typedef std::list<VertexAttribInfo*> VertexAttribInfoList;
+
VertexAttribInfo()
- : enabled_(false),
- size_(0),
- type_(0),
+ : index_(0),
+ enabled_(false),
+ size_(4),
+ type_(GL_FLOAT),
offset_(0),
- real_stride_(0) {
+ real_stride_(16),
+ list_(NULL) {
}
// Returns true if this VertexAttrib can access index.
- bool CanAccess(GLuint index);
-
- void set_enabled(bool enabled) {
- enabled_ = enabled;
- }
+ bool CanAccess(GLuint index) const;
BufferManager::BufferInfo* buffer() const {
return buffer_;
@@ -327,6 +323,10 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
return offset_;
}
+ GLuint index() const {
+ return index_;
+ }
+
void SetInfo(
BufferManager::BufferInfo* buffer,
GLint size,
@@ -345,7 +345,35 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
buffer_ = NULL;
}
+ bool enabled() const {
+ return enabled_;
+ }
+
private:
+ friend class VertexAttribManager;
+
+ void set_enabled(bool enabled) {
+ enabled_ = enabled;
+ }
+
+ void set_index(GLuint index) {
+ index_ = index;
+ }
+
+ void SetList(VertexAttribInfoList* new_list) {
+ DCHECK(new_list);
+
+ if (list_) {
+ list_->erase(it_);
+ }
+
+ it_ = new_list->insert(new_list->end(), this);
+ list_ = new_list;
+ }
+
+ // The index of this attrib.
+ GLuint index_;
+
// Whether or not this attribute is enabled.
bool enabled_;
@@ -365,8 +393,97 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
// The buffer bound to this attribute.
BufferManager::BufferInfo::Ref buffer_;
+
+ // List this info is on.
+ VertexAttribInfoList* list_;
+
+ // Iterator for list this info is on. Enabled/Disabled
+ VertexAttribInfoList::iterator it_;
};
+ typedef std::list<VertexAttribInfo*> VertexAttribInfoList;
+
+ VertexAttribManager()
+ : max_vertex_attribs_(0) {
+ }
+
+ void Initialize(uint32 num_vertex_attribs);
+
+ bool Enable(GLuint index, bool enable);
+
+ const VertexAttribInfoList& GetEnabledVertexAttribInfos() const {
+ return enabled_vertex_attribs_;
+ }
+
+ VertexAttribInfo* GetVertexAttribInfo(GLuint index) {
+ DCHECK(index < max_vertex_attribs_);
+ return &vertex_attrib_infos_[index];
+ }
+
+ private:
+ uint32 max_vertex_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_;
+
+ // Lists for which vertex attribs are enabled, disabled.
+ VertexAttribInfoList enabled_vertex_attribs_;
+ VertexAttribInfoList disabled_vertex_attribs_;
+};
+
+bool VertexAttribManager::VertexAttribInfo::CanAccess(GLuint index) const {
+ if (!enabled_) {
+ return true;
+ }
+
+ if (!buffer_ || buffer_->IsDeleted()) {
+ return false;
+ }
+
+ // The number of elements that can be accessed.
+ GLsizeiptr buffer_size = buffer_->size();
+ if (offset_ > buffer_size || real_stride_ == 0) {
+ return false;
+ }
+
+ uint32 usable_size = buffer_size - offset_;
+ GLuint num_elements = usable_size / real_stride_ +
+ ((usable_size % real_stride_) >=
+ (GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type_) * size_) ? 1 : 0);
+ return index < num_elements;
+}
+
+
+void VertexAttribManager::Initialize(uint32 max_vertex_attribs) {
+ max_vertex_attribs_ = max_vertex_attribs;
+ vertex_attrib_infos_.reset(
+ new VertexAttribInfo[max_vertex_attribs]);
+ for (uint32 vv = 0; vv < max_vertex_attribs; ++vv) {
+ vertex_attrib_infos_[vv].set_index(vv);
+ vertex_attrib_infos_[vv].SetList(&disabled_vertex_attribs_);
+ }
+}
+
+bool VertexAttribManager::Enable(GLuint index, bool enable) {
+ if (index >= max_vertex_attribs_) {
+ return false;
+ }
+ VertexAttribInfo& info = vertex_attrib_infos_[index];
+ if (info.enabled() != enable) {
+ info.set_enabled(enable);
+ info.SetList(enable ? &enabled_vertex_attribs_ : &disabled_vertex_attribs_);
+ }
+ return true;
+}
+
+// This class implements GLES2Decoder so we don't have to expose all the GLES2
+// cmd stuff to outside this class.
+class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
+ public GLES2Decoder {
+ public:
+ explicit GLES2DecoderImpl(ContextGroup* group);
+
// Overridden from AsyncAPIInterface.
virtual Error DoCommand(unsigned int command,
unsigned int arg_count,
@@ -899,9 +1016,8 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
// to call glDrawElements.
BufferManager::BufferInfo::Ref bound_element_array_buffer_;
- // 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_;
+ // Class that manages vertex attribs.
+ VertexAttribManager vertex_attrib_manager_;
// Current active texture by 0 - n index.
// In other words, if we call glActiveTexture(GL_TEXTURE2) this value would
@@ -1240,8 +1356,8 @@ bool GLES2DecoderImpl::Initialize(gfx::GLContext* context,
return false;
}
- vertex_attrib_infos_.reset(
- new VertexAttribInfo[group_->max_vertex_attribs()]);
+ vertex_attrib_manager_.Initialize(group_->max_vertex_attribs());
+
texture_units_.reset(
new TextureUnit[group_->max_texture_units()]);
for (uint32 tt = 0; tt < group_->max_texture_units(); ++tt) {
@@ -1708,7 +1824,7 @@ error::Error GLES2DecoderImpl::DoCommand(
error::Error result = error::kNoError;
if (debug()) {
// TODO(gman): Change output to something useful for NaCl.
- printf("cmd: %s\n", GetCommandName(command));
+ DLOG(INFO) << "cmd: " << GetCommandName(command);
}
unsigned int command_index = command - kStartPoint - 1;
if (command_index < arraysize(g_command_info)) {
@@ -1734,7 +1850,8 @@ error::Error GLES2DecoderImpl::DoCommand(
while ((error = glGetError()) != GL_NO_ERROR) {
// TODO(gman): Change output to something useful for NaCl.
SetGLError(error, NULL);
- printf("GL ERROR b4: %s\n", GetCommandName(command));
+ DLOG(INFO) << "GL ERROR: " << error
+ << " : " << GetCommandName(command);
}
}
} else {
@@ -1917,8 +2034,7 @@ void GLES2DecoderImpl::DoBindTexture(GLenum target, GLuint client_id) {
}
void GLES2DecoderImpl::DoDisableVertexAttribArray(GLuint index) {
- if (index < group_->max_vertex_attribs()) {
- vertex_attrib_infos_[index].set_enabled(false);
+ if (vertex_attrib_manager_.Enable(index, false)) {
glDisableVertexAttribArray(index);
} else {
SetGLError(GL_INVALID_VALUE,
@@ -1927,8 +2043,7 @@ void GLES2DecoderImpl::DoDisableVertexAttribArray(GLuint index) {
}
void GLES2DecoderImpl::DoEnableVertexAttribArray(GLuint index) {
- if (index < group_->max_vertex_attribs()) {
- vertex_attrib_infos_[index].set_enabled(true);
+ if (vertex_attrib_manager_.Enable(index, true)) {
glEnableVertexAttribArray(index);
} else {
SetGLError(GL_INVALID_VALUE,
@@ -2590,28 +2705,6 @@ void GLES2DecoderImpl::ClearRealGLErrors() {
}
}
-bool GLES2DecoderImpl::VertexAttribInfo::CanAccess(GLuint index) {
- if (!enabled_) {
- return true;
- }
-
- if (!buffer_ || buffer_->IsDeleted()) {
- return false;
- }
-
- // The number of elements that can be accessed.
- GLsizeiptr buffer_size = buffer_->size();
- if (offset_ > buffer_size || real_stride_ == 0) {
- return false;
- }
-
- uint32 usable_size = buffer_size - offset_;
- GLuint num_elements = usable_size / real_stride_ +
- ((usable_size % real_stride_) >=
- (GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type_) * size_) ? 1 : 0);
- return index < num_elements;
-}
-
void GLES2DecoderImpl::SetBlackTextureForNonRenderableTextures(
bool* has_non_renderable_textures) {
DCHECK(has_non_renderable_textures);
@@ -2686,19 +2779,33 @@ bool GLES2DecoderImpl::IsDrawValid(GLuint max_vertex_accessed) {
// But GL says no ERROR.
return false;
}
- // Validate that all attribs current program needs are setup correctly.
- const ProgramManager::ProgramInfo::AttribInfoVector& infos =
- current_program_->GetAttribInfos();
- for (size_t ii = 0; ii < infos.size(); ++ii) {
- GLint location = infos[ii].location;
- if (location < 0) {
- return false;
- }
- DCHECK_LT(static_cast<GLuint>(location), group_->max_vertex_attribs());
- if (!vertex_attrib_infos_[location].CanAccess(max_vertex_accessed)) {
- SetGLError(GL_INVALID_OPERATION,
- "glDrawXXX: attempt to access out of range vertices");
- return 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
+ // assigned.
+ 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) {
+ // This attrib is used in the current program.
+ if (!info->CanAccess(max_vertex_accessed)) {
+ SetGLError(GL_INVALID_OPERATION,
+ "glDrawXXX: attempt to access out of range vertices");
+ return false;
+ }
+ } else {
+ // This attrib is not used in the current program.
+ if (!info->buffer() || info->buffer()->IsDeleted()) {
+ SetGLError(
+ GL_INVALID_OPERATION,
+ "glDrawXXX: attempt to render with no buffer attached to enabled "
+ "attrib");
+ return false;
+ }
}
}
return true;
@@ -3053,7 +3160,7 @@ error::Error GLES2DecoderImpl::HandleVertexAttribPointer(
"glVertexAttribPointer: stride not valid for type");
return error::kNoError;
}
- vertex_attrib_infos_[indx].SetInfo(
+ vertex_attrib_manager_.GetVertexAttribInfo(indx)->SetInfo(
bound_array_buffer_,
size,
type,
@@ -3660,7 +3767,8 @@ error::Error GLES2DecoderImpl::HandleGetVertexAttribPointerv(
return error::kNoError;
}
result->SetNumResults(1);
- *result->GetData() = vertex_attrib_infos_[index].offset();
+ *result->GetData() =
+ vertex_attrib_manager_.GetVertexAttribInfo(index)->offset();
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 759e54c..7a5b708 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -225,6 +225,19 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsMissingAttributesFails) {
EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
}
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsExtraAttributesFails) {
+ SetupIndexBuffer();
+ DoEnableVertexAttribArray(6);
+
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
+ .Times(0);
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
TEST_F(GLES2DecoderWithShaderTest, DrawElementsValidAttributesSucceeds) {
SetupTexture();
SetupVertexBuffer();
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 5b86014..77b0c96 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -25,13 +25,15 @@ void ProgramManager::ProgramInfo::Reset() {
attrib_infos_.clear();
uniform_infos_.clear();
sampler_indices_.clear();
- location_to_index_map_.clear();
+ attrib_location_to_index_map_.clear();
+ uniform_location_to_index_map_.clear();
}
void ProgramManager::ProgramInfo::Update() {
Reset();
GLint num_attribs = 0;
GLint max_len = 0;
+ GLint max_location = -1;
glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTES, &num_attribs);
glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len);
// TODO(gman): Should we check for error?
@@ -45,18 +47,31 @@ void ProgramManager::ProgramInfo::Update() {
if (!IsInvalidPrefix(name_buffer.get(), length)) {
// TODO(gman): Should we check for error?
GLint location = glGetAttribLocation(service_id_, name_buffer.get());
+ if (location > max_location) {
+ max_location = location;
+ }
attrib_infos_.push_back(
VertexAttribInfo(size, type, name_buffer.get(), location));
max_attrib_name_length_ = std::max(max_attrib_name_length_, length);
}
}
+ // Create attrib location to index map.
+ attrib_location_to_index_map_.resize(max_location + 1);
+ for (GLint ii = 0; ii <= max_location; ++ii) {
+ attrib_location_to_index_map_[ii] = -1;
+ }
+ for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
+ const VertexAttribInfo& info = attrib_infos_[ii];
+ attrib_location_to_index_map_[info.location] = ii;
+ }
+
GLint num_uniforms = 0;
max_len = 0;
glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms);
glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len);
name_buffer.reset(new char[max_len]);
- GLint max_location = -1;
+ max_location = -1;
int index = 0; // this index tracks valid uniforms.
for (GLint ii = 0; ii < num_uniforms; ++ii) {
GLsizei length;
@@ -83,15 +98,15 @@ void ProgramManager::ProgramInfo::Update() {
++index;
}
}
- // Create location to index map.
- location_to_index_map_.resize(max_location + 1);
+ // Create uniform location to index map.
+ uniform_location_to_index_map_.resize(max_location + 1);
for (GLint ii = 0; ii <= max_location; ++ii) {
- location_to_index_map_[ii] = -1;
+ uniform_location_to_index_map_[ii] = -1;
}
for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
const UniformInfo& info = uniform_infos_[ii];
for (size_t jj = 0; jj < info.element_locations.size(); ++jj) {
- location_to_index_map_[info.element_locations[jj]] = ii;
+ uniform_location_to_index_map_[info.element_locations[jj]] = ii;
}
}
valid_ = true;
@@ -147,8 +162,8 @@ GLint ProgramManager::ProgramInfo::GetAttribLocation(
bool ProgramManager::ProgramInfo::GetUniformTypeByLocation(
GLint location, GLenum* type) const {
if (location >= 0 &&
- static_cast<size_t>(location) < location_to_index_map_.size()) {
- GLint index = location_to_index_map_[location];
+ static_cast<size_t>(location) < uniform_location_to_index_map_.size()) {
+ GLint index = uniform_location_to_index_map_[location];
if (index >= 0) {
*type = uniform_infos_[index].type;
return true;
@@ -202,8 +217,8 @@ const ProgramManager::ProgramInfo::UniformInfo*
bool ProgramManager::ProgramInfo::SetSamplers(
GLint location, GLsizei count, const GLint* value) {
if (location >= 0 &&
- static_cast<size_t>(location) < location_to_index_map_.size()) {
- GLint index = location_to_index_map_[location];
+ static_cast<size_t>(location) < uniform_location_to_index_map_.size()) {
+ GLint index = uniform_location_to_index_map_[location];
if (index >= 0) {
UniformInfo& info = uniform_infos_[index];
if (info.IsSampler() && count <= info.size) {
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index feb263c..7104242 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -96,6 +96,16 @@ class ProgramManager {
GLint GetAttribLocation(const std::string& name) const;
+ const VertexAttribInfo* GetAttribInfoByLocation(GLuint location) const {
+ if (location < attrib_location_to_index_map_.size()) {
+ GLint index = attrib_location_to_index_map_[location];
+ if (index >= 0) {
+ return &attrib_infos_[index];
+ }
+ }
+ return NULL;
+ }
+
const UniformInfo* GetUniformInfo(GLint index) const {
return (static_cast<size_t>(index) < uniform_infos_.size()) ?
&uniform_infos_[index] : NULL;
@@ -137,15 +147,19 @@ class ProgramManager {
GLsizei max_attrib_name_length_;
+ // Attrib by index.
AttribInfoVector attrib_infos_;
+ // Attrib by location to index.
+ std::vector<GLint> attrib_location_to_index_map_;
+
GLsizei max_uniform_name_length_;
// Uniform info by index.
UniformInfoVector uniform_infos_;
// Uniform location to index.
- std::vector<GLint> location_to_index_map_;
+ std::vector<GLint> uniform_location_to_index_map_;
// The indices of the uniforms that are samplers.
SamplerIndices sampler_indices_;