Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1323)

Unified Diff: gpu/command_buffer/service/gles2_cmd_decoder.cc

Issue 501097: Add Immediate command data size validation.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: gpu/command_buffer/service/gles2_cmd_decoder.cc
===================================================================
--- gpu/command_buffer/service/gles2_cmd_decoder.cc (revision 35070)
+++ gpu/command_buffer/service/gles2_cmd_decoder.cc (working copy)
@@ -18,28 +18,60 @@
namespace gpu {
namespace gles2 {
+// Check that certain assumptions the code makes are true. There are places in
+// the code where shared memory is passed direclty to GL. Example, glUniformiv,
+// glShaderSource. The command buffer code assumes GLint and GLsizei (and maybe
+// a few others) are 32bits. If they are not 32bits the code will have to change
+// to call those GL functions with service side memory and then copy the results
+// to shared memory, converting the sizes.
+COMPILE_ASSERT(sizeof(GLint) == sizeof(uint32), // NOLINT
+ GLint_not_same_size_as_uint32);
+COMPILE_ASSERT(sizeof(GLsizei) == sizeof(uint32), // NOLINT
+ GLint_not_same_size_as_uint32);
+
namespace {
+size_t GetGLTypeSize(GLenum type) {
+ switch (type) {
+ case GL_BYTE:
+ return sizeof(GLbyte); // NOLINT
+ case GL_UNSIGNED_BYTE:
+ return sizeof(GLubyte); // NOLINT
+ case GL_SHORT:
+ return sizeof(GLshort); // NOLINT
+ case GL_UNSIGNED_SHORT:
+ return sizeof(GLushort); // NOLINT
+ case GL_FLOAT:
+ return sizeof(GLfloat); // NOLINT
+ default:
+ return 0;
+ }
+}
+
// Returns the address of the first byte after a struct.
template <typename T>
const void* AddressAfterStruct(const T& pod) {
return reinterpret_cast<const uint8*>(&pod) + sizeof(pod);
}
-// Returns the address of the frst byte after the struct.
+// Returns the address of the frst byte after the struct or NULL if size >
+// immediate_data_size.
template <typename RETURN_TYPE, typename COMMAND_TYPE>
-RETURN_TYPE GetImmediateDataAs(const COMMAND_TYPE& pod) {
- return static_cast<RETURN_TYPE>(const_cast<void*>(AddressAfterStruct(pod)));
+RETURN_TYPE GetImmediateDataAs(const COMMAND_TYPE& pod,
+ uint32 size,
+ uint32 immediate_data_size) {
+ return (size <= immediate_data_size) ?
+ static_cast<RETURN_TYPE>(const_cast<void*>(AddressAfterStruct(pod))) :
+ NULL;
}
-// Checks if there is enough immediate data.
-template<typename T>
-bool CheckImmediateDataSize(
+// Computes the data size for certain gl commands like glUniform.
+uint32 ComputeImmediateDataSize(
uint32 immediate_data_size,
GLuint count,
size_t size,
unsigned int elements_per_unit) {
- return immediate_data_size == count * size * elements_per_unit;
+ return count * size * elements_per_unit;
}
// A struct to hold info about each command.
@@ -59,39 +91,6 @@
#undef GLES2_CMD_OP
};
-// These commands convert from c calls to local os calls.
-void GLGenBuffersHelper(GLsizei n, GLuint* ids) {
- glGenBuffersARB(n, ids);
-}
-
-void GLGenFramebuffersHelper(GLsizei n, GLuint* ids) {
- glGenFramebuffersEXT(n, ids);
-}
-
-void GLGenRenderbuffersHelper(GLsizei n, GLuint* ids) {
- glGenRenderbuffersEXT(n, ids);
-}
-
-void GLGenTexturesHelper(GLsizei n, GLuint* ids) {
- glGenTextures(n, ids);
-}
-
-void GLDeleteBuffersHelper(GLsizei n, GLuint* ids) {
- glDeleteBuffersARB(n, ids);
-}
-
-void GLDeleteFramebuffersHelper(GLsizei n, GLuint* ids) {
- glDeleteFramebuffersEXT(n, ids);
-}
-
-void GLDeleteRenderbuffersHelper(GLsizei n, GLuint* ids) {
- glDeleteRenderbuffersEXT(n, ids);
-}
-
-void GLDeleteTexturesHelper(GLsizei n, GLuint* ids) {
- glDeleteTextures(n, ids);
-}
-
namespace GLErrorBit {
enum GLErrorBit {
kNoError = 0,
@@ -221,6 +220,131 @@
// cmd stuff to outside this class.
class GLES2DecoderImpl : public GLES2Decoder {
public:
+ // 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:
+ VertexAttribInfo()
+ : enabled_(false),
+ size_(0),
+ type_(0),
+ offset_(0),
+ real_stride_(0),
+ buffer_(0),
+ buffer_size_(0),
+ num_elements_(0) {
+ }
+ // Returns true if this VertexAttrib can access index.
+ bool CanAccess(GLuint index);
+
+ void set_enabled(bool enabled) {
+ enabled_ = enabled;
+ }
+
+ GLuint buffer() const {
+ return buffer_;
+ }
+
+ void Clear() {
+ buffer_ = 0;
+ SetBufferSize(0);
+ }
+
+ void SetBufferSize(GLsizeiptr buffer_size) {
+ buffer_size_ = buffer_size;
+ if (offset_ > buffer_size || real_stride_ == 0) {
+ num_elements_ = 0;
+ } else {
+ uint32 size = buffer_size - offset_;
+ num_elements_ = size / real_stride_ +
+ (size % real_stride_ >= GetGLTypeSize(type_) ? 1 : 0);
+ }
+ }
+
+ void SetInfo(
+ GLuint buffer,
+ GLsizeiptr buffer_size,
+ GLint size,
+ GLenum type,
+ GLsizei real_stride,
+ GLsizei offset) {
+ DCHECK(real_stride > 0);
+ buffer_ = buffer;
+ size_ = size;
+ type_ = type;
+ real_stride_ = real_stride;
+ offset_ = offset;
+ SetBufferSize(buffer_size);
+ }
+
+ private:
+ // Whether or not this attribute is enabled.
+ bool enabled_;
+
+ // number of components (1, 2, 3, 4)
+ GLint size_;
+
+ // GL_BYTE, GL_FLOAT, etc. See glVertexAttribPointer.
+ GLenum type_;
+
+ // The offset into the buffer.
+ GLsizei offset_;
+
+ // The stride that will be used to access the buffer. This is the actual
+ // stide, NOT the GL bogus stride. In other words there is never a stride
+ // of 0.
+ GLsizei real_stride_;
+
+ // The service side name of the buffer bound to this attribute. 0 = invalid
+ GLuint buffer_;
+
+ // The size of the buffer.
+ GLsizeiptr buffer_size_;
+
+ // The number of elements that can be accessed.
+ GLuint num_elements_;
+ };
+
+ // Info about Buffers currently in the system.
+ struct BufferInfo {
+ BufferInfo()
+ : size(0) {
+ }
+
+ explicit BufferInfo(GLsizeiptr _size)
+ : size(_size) {
+ }
+
+ GLsizeiptr size;
+ };
+
+ // This is used to track which attributes a particular program needs
+ // so we can verify at glDrawXXX time that every attribute is either disabled
+ // or if enabled that it points to a valid source.
+ class ProgramInfo {
+ public:
+ typedef std::vector<GLuint> AttribLocationVector;
+
+ ProgramInfo() {
+ }
+
+ void SetNumAttributes(int num_attribs) {
+ attrib_locations_.resize(num_attribs);
+ }
+
+ void SetAttributeLocation(GLuint index, int location) {
+ DCHECK(index < attrib_locations_.size());
+ attrib_locations_[index] = location;
+ }
+
+ const AttribLocationVector& GetAttribLocations() const {
+ return attrib_locations_;
+ }
+ private:
+ AttribLocationVector attrib_locations_;
+ };
+
GLES2DecoderImpl();
// Overridden from AsyncAPIInterface.
@@ -237,41 +361,59 @@
// Overridden from GLES2Decoder.
virtual void Destroy();
+ // Removes any buffers in the VertexAtrribInfos and BufferInfos. This is used
+ // on glDeleteBuffers so we can make sure the user does not try to render
+ // with deleted buffers.
+ void RemoveBufferInfo(GLuint buffer_id);
+
private:
bool InitPlatformSpecific();
bool InitGlew();
// Template to help call glGenXXX functions.
- template <void gl_gen_function(GLsizei, GLuint*)>
+ template <void gl_gen_function(GLES2DecoderImpl*, GLsizei, GLuint*)>
bool GenGLObjects(GLsizei n, const GLuint* client_ids) {
// TODO(gman): Verify client ids are unused.
scoped_array<GLuint>temp(new GLuint[n]);
- gl_gen_function(n, temp.get());
+ gl_gen_function(this, n, temp.get());
// TODO(gman): check for success before copying results.
- for (GLsizei ii = 0; ii < n; ++ii) {
- if (!id_map_.AddMapping(client_ids[ii], temp[ii])) {
- // TODO(gman): fail.
- }
- }
- return true;
+ return RegisterObjects(n, client_ids, temp.get());
}
// Template to help call glDeleteXXX functions.
- template <void gl_delete_function(GLsizei, GLuint*)>
+ template <void gl_delete_function(GLES2DecoderImpl*, GLsizei, GLuint*)>
bool DeleteGLObjects(GLsizei n, const GLuint* client_ids) {
scoped_array<GLuint>temp(new GLuint[n]);
- // TODO(gman): check for success before copying results.
- for (GLsizei ii = 0; ii < n; ++ii) {
- if (id_map_.GetServiceId(client_ids[ii], &temp[ii])) {
- id_map_.RemoveMapping(client_ids[ii], temp[ii]);
- } else {
- temp[ii] = 0;
- }
- }
- gl_delete_function(n, temp.get());
+ UnregisterObjects(n, client_ids, temp.get());
+ gl_delete_function(this, n, temp.get());
return true;
}
+ // Register client ids with generated service ids.
+ bool RegisterObjects(
+ GLsizei n, const GLuint* client_ids, const GLuint* service_ids);
+
+ // Unregisters client ids with service ids.
+ void UnregisterObjects(
+ GLsizei n, const GLuint* client_ids, GLuint* service_ids);
+
+ // Gets the program info for the given program. Returns NULL if none exists.
+ // Programs that have no had glLinkProgram succesfully called on them will
+ // not exist.
+ ProgramInfo* GetProgramInfo(GLuint program);
+
+ // Updates the program info for the given program.
+ void UpdateProgramInfo(GLuint program);
+
+ // Deletes the program info for the given program.
+ void RemoveProgramInfo(GLuint program);
+
+ // Gets the buffer info for the given buffer.
+ const BufferInfo* GetBufferInfo(GLuint buffer);
+
+ // Sets the info for a buffer.
+ void SetBufferInfo(GLuint buffer, GLsizeiptr size);
+
// Wrapper for glCreateProgram
void CreateProgramHelper(GLuint client_id);
@@ -281,15 +423,46 @@
// Wrapper for glBindBuffer since we need to track the current targets.
void DoBindBuffer(GLenum target, GLuint buffer);
+ // Wrapper for glBindBuffer since we need to track the current targets.
apatrick 2009/12/22 02:37:21 BindBuffer -> DrawArrays
+ void DoDrawArrays(GLenum mode, GLint first, GLsizei count);
+
+ // Wrapper for glDisableVertexAttribArray.
+ void DoDisableVertexAttribArray(GLuint index);
+
+ // Wrapper for glEnableVertexAttribArray.
+ void DoEnableVertexAttribArray(GLuint index);
+
+ // Wrapper for glLinkProgram
+ void DoLinkProgram(GLuint program);
+
// Swaps the buffers (copies/renders to the current window).
void DoSwapBuffers();
+ // Wrapper for glUseProgram
+ void DoUseProgram(GLuint program);
+
// Gets the GLError through our wrapper.
GLenum GetGLError();
// Sets our wrapper for the GLError.
void SetGLError(GLenum error);
+ // Copies the real GL errors to the wrapper. This is so we can
+ // make sure there are no native GL errors before calling some GL function
+ // so that on return we know any error generated was for that specific
+ // command.
+ void CopyRealGLErrorsToWrapper();
+
+ // Checks if the current program and vertex attributes are valid for drawing.
+ bool IsDrawValid(GLuint max_vertex_accessed);
+
+ // Gets the buffer id for a given target.
+ GLuint GetBufferForTarget(GLenum target) {
+ DCHECK(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER);
+ return target == GL_ARRAY_BUFFER ? bound_array_buffer_ :
+ bound_element_array_buffer_;
+ }
+
// Generate a member function prototype for each command in an automated and
// typesafe way.
#define GLES2_CMD_OP(name) \
@@ -324,6 +497,26 @@
// to call glDrawElements.
GLuint bound_element_array_buffer_;
+ // The maximum vertex attributes.
+ GLuint 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_;
+
+ // Infor for each buffer in the system.
apatrick 2009/12/22 02:37:21 Infor -> Info
+ // TODO(gman): Choose a faster container.
+ typedef std::map<GLuint, BufferInfo> BufferInfoMap;
+ BufferInfoMap buffer_infos_;
+
+ // Info for each "successfully linked" program by service side program Id.
+ // TODO(gman): Choose a faster container.
+ typedef std::map<GLuint, ProgramInfo> ProgramInfoMap;
+ ProgramInfoMap program_infos_;
+
+ // The program in current use through glUseProgram.
+ ProgramInfo* current_program_info_;
+
#if defined(OS_WIN)
HDC device_context_;
HGLRC gl_context_;
@@ -346,6 +539,8 @@
unpack_alignment_(4),
bound_array_buffer_(0),
bound_element_array_buffer_(0),
+ max_vertex_attribs_(0),
+ current_program_info_(NULL),
#ifdef OS_WIN
device_context_(NULL),
gl_context_(NULL),
@@ -360,6 +555,17 @@
return false;
CHECK_GL_ERROR();
+ // Lookup GL things we need to know.
+ GLint value;
+ glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value);
+ max_vertex_attribs_ = value;
+
+ DCHECK_GE(max_vertex_attribs_, 8u);
+
+ vertex_attrib_infos_.reset(new VertexAttribInfo[max_vertex_attribs_]);
+ memset(vertex_attrib_infos_.get(), 0,
+ sizeof(vertex_attrib_infos_[0]) * max_vertex_attribs_);
+
//glBindFramebuffer(0, 0);
return true;
}
@@ -533,9 +739,84 @@
return true;
}
+// These commands convert from c calls to local os calls.
+void GLGenBuffersHelper(
+ GLES2DecoderImpl*, GLsizei n, GLuint* ids) {
+ glGenBuffersARB(n, ids);
+}
+
+void GLGenFramebuffersHelper(
+ GLES2DecoderImpl*, GLsizei n, GLuint* ids) {
+ glGenFramebuffersEXT(n, ids);
+}
+
+void GLGenRenderbuffersHelper(
+ GLES2DecoderImpl*, GLsizei n, GLuint* ids) {
+ glGenRenderbuffersEXT(n, ids);
+}
+
+void GLGenTexturesHelper(
+ GLES2DecoderImpl*, GLsizei n, GLuint* ids) {
+ glGenTextures(n, ids);
+}
+
+void GLDeleteBuffersHelper(
+ GLES2DecoderImpl* decoder, GLsizei n, GLuint* ids) {
+ glDeleteBuffersARB(n, ids);
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ decoder->RemoveBufferInfo(ids[ii]);
+ }
+}
+
+void GLDeleteFramebuffersHelper(
+ GLES2DecoderImpl*, GLsizei n, GLuint* ids) {
+ glDeleteFramebuffersEXT(n, ids);
+}
+
+void GLDeleteRenderbuffersHelper(
+ GLES2DecoderImpl*, GLsizei n, GLuint* ids) {
+ glDeleteRenderbuffersEXT(n, ids);
+}
+
+void GLDeleteTexturesHelper(
+ GLES2DecoderImpl*, GLsizei n, GLuint* ids) {
+ glDeleteTextures(n, ids);
+}
+
} // anonymous namespace
#endif
+bool GLES2DecoderImpl::RegisterObjects(
+ GLsizei n, const GLuint* client_ids, const GLuint* service_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (!id_map_.AddMapping(client_ids[ii], service_ids[ii])) {
+ // TODO(gman): fail.
+ }
+ }
+ return true;
+}
+
+void GLES2DecoderImpl::UnregisterObjects(
+ GLsizei n, const GLuint* client_ids, GLuint* service_ids) {
+ // TODO(gman): check for success before copying results.
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (id_map_.GetServiceId(client_ids[ii], &service_ids[ii])) {
+ id_map_.RemoveMapping(client_ids[ii], service_ids[ii]);
+ } else {
+ service_ids[ii] = 0;
+ }
+ }
+}
+
+void GLES2DecoderImpl::RemoveBufferInfo(GLuint buffer_id) {
+ for (GLuint ii = 0; ii < max_vertex_attribs_; ++ii) {
+ if (vertex_attrib_infos_[ii].buffer() == buffer_id) {
+ vertex_attrib_infos_[ii].Clear();
+ }
+ }
+ buffer_infos_.erase(buffer_id);
+}
+
bool GLES2DecoderImpl::InitPlatformSpecific() {
#if defined(OS_WIN)
device_context_ = ::GetDC(hwnd());
@@ -678,8 +959,10 @@
#undef GLES2_CMD_OP
}
if (debug()) {
- if (glGetError() != 0) {
+ GLenum error;
+ while ((error = glGetError()) != GL_NO_ERROR) {
// TODO(gman): Change output to something useful for NaCl.
+ SetGLError(error);
printf("GL ERROR b4: %s\n", GetCommandName(command));
}
}
@@ -723,6 +1006,24 @@
glBindBuffer(target, buffer);
}
+void GLES2DecoderImpl::DoDisableVertexAttribArray(GLuint index) {
+ if (index < max_vertex_attribs_) {
+ vertex_attrib_infos_[index].set_enabled(false);
+ glEnableVertexAttribArray(index);
+ } else {
+ SetGLError(GL_INVALID_VALUE);
+ }
+}
+
+void GLES2DecoderImpl::DoEnableVertexAttribArray(GLuint index) {
+ if (index < max_vertex_attribs_) {
+ vertex_attrib_infos_[index].set_enabled(true);
+ glEnableVertexAttribArray(index);
+ } else {
+ SetGLError(GL_INVALID_VALUE);
+ }
+}
+
parse_error::ParseError GLES2DecoderImpl::HandleDeleteShader(
uint32 immediate_data_size, const gles2::DeleteShader& c) {
GLuint shader = c.shader;
@@ -731,7 +1032,7 @@
SetGLError(GL_INVALID_VALUE);
return parse_error::kParseNoError;
}
- glDeleteProgram(service_id);
+ glDeleteShader(service_id);
id_map_.RemoveMapping(shader, service_id);
return parse_error::kParseNoError;
}
@@ -744,11 +1045,31 @@
SetGLError(GL_INVALID_VALUE);
return parse_error::kParseNoError;
}
+ RemoveProgramInfo(program);
glDeleteProgram(service_id);
id_map_.RemoveMapping(program, service_id);
return parse_error::kParseNoError;
}
+void GLES2DecoderImpl::DoDrawArrays(
+ GLenum mode, GLint first, GLsizei count) {
+ if (IsDrawValid(first + count - 1)) {
+ glDrawArrays(mode, first, count);
+ }
+}
+
+void GLES2DecoderImpl::DoLinkProgram(GLuint program) {
+ CopyRealGLErrorsToWrapper();
+ glLinkProgram(program);
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR) {
+ RemoveProgramInfo(program);
+ SetGLError(error);
+ } else {
+ UpdateProgramInfo(program);
+ }
+};
+
// NOTE: If you need to know the results of SwapBuffers (like losing
// the context) then add a new command. Do NOT make SwapBuffers synchronous.
void GLES2DecoderImpl::DoSwapBuffers() {
@@ -762,6 +1083,17 @@
#endif
}
+void GLES2DecoderImpl::DoUseProgram(GLuint program) {
+ ProgramInfo* info = GetProgramInfo(program);
+ if (!info) {
+ // Program was not linked successfully. (ie, glLinkProgram)
+ SetGLError(GL_INVALID_OPERATION);
+ } else {
+ current_program_info_ = info;
+ glUseProgram(program);
+ }
+}
+
GLenum GLES2DecoderImpl::GetGLError() {
// Check the GL error first, then our wrapped error.
GLenum error = glGetError();
@@ -786,6 +1118,97 @@
error_bits_ |= GLErrorToErrorBit(error);
}
+void GLES2DecoderImpl::CopyRealGLErrorsToWrapper() {
+ GLenum error;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ SetGLError(error);
+ }
+}
+
+const GLES2DecoderImpl::BufferInfo* GLES2DecoderImpl::GetBufferInfo(
+ GLuint buffer) {
+ BufferInfoMap::iterator it = buffer_infos_.find(buffer);
+ return it != buffer_infos_.end() ? &it->second : NULL;
+}
+
+void GLES2DecoderImpl::SetBufferInfo(GLuint buffer, GLsizeiptr size) {
+ buffer_infos_[buffer] = BufferInfo(size);
+
+ // Also go through VertexAttribInfo and update any info that references
+ // the same buffer.
+ for (GLuint ii = 0; ii < max_vertex_attribs_; ++ii) {
+ if (vertex_attrib_infos_[ii].buffer() == buffer) {
+ vertex_attrib_infos_[ii].SetBufferSize(size);
+ }
+ }
+}
+
+GLES2DecoderImpl::ProgramInfo* GLES2DecoderImpl::GetProgramInfo(
+ GLuint program) {
+ ProgramInfoMap::iterator it = program_infos_.find(program);
+ return it != program_infos_.end() ? &it->second : NULL;
+}
+
+void GLES2DecoderImpl::UpdateProgramInfo(GLuint program) {
+ ProgramInfo* info = GetProgramInfo(program);
+ if (!info) {
+ std::pair<ProgramInfoMap::iterator, bool> result =
+ program_infos_.insert(std::make_pair(program, ProgramInfo()));
+ DCHECK(result.second);
+ info = &result.first->second;
+ }
+ GLint num_attribs = 0;
+ GLint max_len = 0;
+ glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &num_attribs);
+ info->SetNumAttributes(num_attribs);
+ glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len);
+ // TODO(gman): Should we check for error?
+ scoped_array<char> name_buffer(new char[max_len + 1]);
+ for (GLint ii = 0; ii < num_attribs; ++ii) {
+ GLsizei length;
+ GLsizei size;
+ GLenum type;
+ glGetActiveAttrib(
+ program, ii, max_len + 1, &length, &size, &type, name_buffer.get());
+ // TODO(gman): Should we check for error?
+ GLint location = glGetAttribLocation(program, name_buffer.get());
+ info->SetAttributeLocation(ii, num_attribs);
+ }
+}
+
+void GLES2DecoderImpl::RemoveProgramInfo(GLuint program) {
+ ProgramInfoMap::iterator it = program_infos_.find(program);
+ if (it != program_infos_.end()) {
+ if (current_program_info_ == &it->second) {
+ current_program_info_ = NULL;
+ }
+ program_infos_.erase(it);
+ }
+}
+
+bool GLES2DecoderImpl::VertexAttribInfo::CanAccess(GLuint index) {
+ return !enabled_ || (buffer_ != 0 && index < num_elements_);
+}
+
+bool GLES2DecoderImpl::IsDrawValid(GLuint max_vertex_accessed) {
+ if (current_program_info_) {
+ // Validate that all attribs current program needs are setup correctly.
+ const ProgramInfo::AttribLocationVector& locations =
+ current_program_info_->GetAttribLocations();
+ for (size_t ii = 0; ii < locations.size(); ++ii) {
+ GLuint location = locations[ii];
+ DCHECK_LT(location, max_vertex_attribs_);
+ if (!vertex_attrib_infos_[location].CanAccess(max_vertex_accessed)) {
+ SetGLError(GL_INVALID_OPERATION);
+ }
+ }
+ return true;
+ }
+ // We do not set a GL error here because the GL spec says no error if the
+ // program is invalid.
+ return false;
+};
+
parse_error::ParseError GLES2DecoderImpl::HandleDrawElements(
uint32 immediate_data_size, const gles2::DrawElements& c) {
if (bound_element_array_buffer_ != 0) {
@@ -797,9 +1220,15 @@
SetGLError(GL_INVALID_VALUE);
} else {
const GLvoid* indices = reinterpret_cast<const GLvoid*>(c.index_offset);
- // TODO(gman): Validate indices
- // TOOD(gman): Validate all attribs current program needs are setup.
- glDrawElements(mode, count, type, indices);
+ // TODO(gman): Validate indices. Get maximum index.
+ //
+ // This value should be computed by walking the index buffer from 0 to
+ // count and finding the maximum vertex accessed.
+ // For now we'll special case 0 to not check.
+ GLuint max_vertex_accessed = 0;
+ if (IsDrawValid(max_vertex_accessed)) {
+ glDrawElements(mode, count, type, indices);
+ }
}
} else {
SetGLError(GL_INVALID_VALUE);
@@ -865,8 +1294,8 @@
}
GLsizei count = c.count;
uint32 data_size = c.data_size;
- // TODO(gman): need to check that data_size is in range for arg_count.
- const char** data = GetImmediateDataAs<const char**>(c);
+ const char** data = GetImmediateDataAs<const char**>(
+ c, data_size, immediate_data_size);
if (!data) {
return parse_error::kParseOutOfBounds;
}
@@ -876,21 +1305,35 @@
parse_error::ParseError GLES2DecoderImpl::HandleVertexAttribPointer(
uint32 immediate_data_size, const gles2::VertexAttribPointer& c) {
- // TODO(gman): Is this a valid check or does this check have to come
- // at glDrawElements time.
if (bound_array_buffer_ != 0) {
GLuint indx = c.indx;
GLint size = c.size;
GLenum type = c.type;
GLboolean normalized = c.normalized;
GLsizei stride = c.stride;
- GLuint offset = c.offset;
- const void* ptr = reinterpret_cast<const void*>(c.offset);
+ GLsizei offset = c.offset;
+ const void* ptr = reinterpret_cast<const void*>(offset);
if (!ValidateGLenumVertexAttribType(type) ||
- !ValidateGLenumVertexAttribSize(size)) {
+ !ValidateGLenumVertexAttribSize(size) ||
+ indx >= max_vertex_attribs_ ||
+ stride < 0) {
SetGLError(GL_INVALID_VALUE);
return parse_error::kParseNoError;
}
+ const BufferInfo* buffer_info = GetBufferInfo(bound_array_buffer_);
+ GLsizei component_size = GetGLTypeSize(type);
+ GLsizei real_stride = stride != 0 ? stride : component_size * size;
+ if (offset % component_size > 0) {
+ SetGLError(GL_INVALID_VALUE);
+ return parse_error::kParseNoError;
+ }
+ vertex_attrib_infos_[indx].SetInfo(
+ bound_array_buffer_,
+ buffer_info ? buffer_info->size : 0,
+ size,
+ type,
+ real_stride,
+ offset);
glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
} else {
SetGLError(GL_INVALID_VALUE);
@@ -975,9 +1418,8 @@
return parse_error::kParseNoError;
}
uint32 name_size = c.data_size;
- const char* name = GetImmediateDataAs<const char*>(c);
- // TODO(gman): Make sure validate checks arg_count
- // covers data_size.
+ const char* name = GetImmediateDataAs<const char*>(
+ c, name_size, immediate_data_size);
GLint* location = GetSharedMemoryAs<GLint*>(
c.location_shm_id, c.location_shm_offset, sizeof(GLint));
if (!location || !name) {
@@ -1016,9 +1458,8 @@
return parse_error::kParseNoError;
}
uint32 name_size = c.data_size;
- const char* name = GetImmediateDataAs<const char*>(c);
- // TODO(gman): Make sure validate checks arg_count
- // covers data_size.
+ const char* name = GetImmediateDataAs<const char*>(
+ c, name_size, immediate_data_size);
GLint* location = GetSharedMemoryAs<GLint*>(
c.location_shm_id, c.location_shm_offset, sizeof(GLint));
if (!location || !name) {
@@ -1043,13 +1484,26 @@
return parse_error::kParseOutOfBounds;
}
}
- // TODO(gman): Validate case where data is NULL.
if (!ValidateGLenumBufferTarget(target) ||
!ValidateGLenumBufferUsage(usage)) {
SetGLError(GL_INVALID_VALUE);
return parse_error::kParseNoError;
}
+ // Clear the buffer to 0 if no initial data was passed in.
+ scoped_array<int8> zero;
+ if (!data) {
+ zero.reset(new int8[size]);
+ memset(zero.get(), 0, size);
+ data = zero.get();
+ }
+ CopyRealGLErrorsToWrapper();
glBufferData(target, size, data, usage);
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR) {
+ SetGLError(error);
+ } else {
+ SetBufferInfo(GetBufferForTarget(target), size);
+ }
return parse_error::kParseNoError;
}
@@ -1057,15 +1511,25 @@
uint32 immediate_data_size, const gles2::BufferDataImmediate& c) {
GLenum target = static_cast<GLenum>(c.target);
GLsizeiptr size = static_cast<GLsizeiptr>(c.size);
- const void* data = GetImmediateDataAs<const void*>(c);
+ const void* data = GetImmediateDataAs<const void*>(
+ c, size, immediate_data_size);
+ if (!data) {
+ return parse_error::kParseOutOfBounds;
+ }
GLenum usage = static_cast<GLenum>(c.usage);
if (!ValidateGLenumBufferTarget(target) ||
!ValidateGLenumBufferUsage(usage)) {
SetGLError(GL_INVALID_VALUE);
return parse_error::kParseNoError;
}
- // TODO(gman): Handle case where data is NULL.
+ CopyRealGLErrorsToWrapper();
glBufferData(target, size, data, usage);
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR) {
+ SetGLError(error);
+ } else {
+ SetBufferInfo(GetBufferForTarget(target), size);
+ }
return parse_error::kParseNoError;
}
@@ -1093,7 +1557,12 @@
SetGLError(GL_INVALID_VALUE);
return parse_error::kParseNoError;
}
- // TODO(gman): Validate case where data is NULL.
+ scoped_array<int8> zero;
+ if (!data) {
+ zero.reset(new int8[image_size]);
+ memset(zero.get(), 0, image_size);
+ data = zero.get();
+ }
glCompressedTexImage2D(
target, level, internal_format, width, height, border, image_size, data);
return parse_error::kParseNoError;
@@ -1108,9 +1577,8 @@
GLsizei height = static_cast<GLsizei>(c.height);
GLint border = static_cast<GLint>(c.border);
GLsizei image_size = static_cast<GLsizei>(c.imageSize);
- const void* data = GetImmediateDataAs<const void*>(c);
- // Immediate version.
- // TODO(gman): Handle case where data is NULL.
+ const void* data = GetImmediateDataAs<const void*>(
+ c, image_size, immediate_data_size);
if (!data) {
return parse_error::kParseOutOfBounds;
}
@@ -1153,7 +1621,12 @@
SetGLError(GL_INVALID_VALUE);
return parse_error::kParseNoError;
}
- // TODO(gman): Validate case where data is NULL.
+ scoped_array<int8> zero;
+ if (!pixels) {
+ zero.reset(new int8[pixels_size]);
+ memset(zero.get(), 0, pixels_size);
+ pixels = zero.get();
+ }
glTexImage2D(
target, level, internal_format, width, height, border, format, type,
pixels);
@@ -1170,9 +1643,10 @@
GLint border = static_cast<GLint>(c.border);
GLenum format = static_cast<GLenum>(c.format);
GLenum type = static_cast<GLenum>(c.type);
- const void* pixels = GetImmediateDataAs<const void*>(c);
- // Immediate version.
- // TODO(gman): Handle case where data is NULL.
+ uint32 size = GLES2Util::ComputeImageDataSize(
+ width, height, format, type, unpack_alignment_);
+ const void* pixels = GetImmediateDataAs<const void*>(
+ c, size, immediate_data_size);
if (!pixels) {
return parse_error::kParseOutOfBounds;
}
« no previous file with comments | « gpu/command_buffer/build_gles2_cmd_buffer.py ('k') | gpu/command_buffer/service/gles2_cmd_decoder_autogen.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698