diff options
-rw-r--r-- | gpu/GLES2/gles2_command_buffer.h | 2 | ||||
-rw-r--r-- | gpu/command_buffer/common/gles2_cmd_utils.cc | 2 | ||||
-rw-r--r-- | gpu/command_buffer/service/buffer_manager.cc | 11 | ||||
-rw-r--r-- | gpu/command_buffer/service/buffer_manager.h | 3 | ||||
-rw-r--r-- | gpu/command_buffer/service/buffer_manager_unittest.cc | 18 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 237 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc | 19 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h | 1 |
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; |