summaryrefslogtreecommitdiffstats
path: root/gpu/command_buffer/service/gles2_cmd_decoder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gpu/command_buffer/service/gles2_cmd_decoder.cc')
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc237
1 files changed, 200 insertions, 37 deletions
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 {