Home | History | Annotate | Download | only in service
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "gpu/command_buffer/service/vertex_attrib_manager.h"
      6 
      7 #include <list>
      8 
      9 #include "base/logging.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "build/build_config.h"
     13 #define GLES2_GPU_SERVICE 1
     14 #include "gpu/command_buffer/common/gles2_cmd_format.h"
     15 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
     16 #include "gpu/command_buffer/service/buffer_manager.h"
     17 #include "gpu/command_buffer/service/error_state.h"
     18 #include "gpu/command_buffer/service/feature_info.h"
     19 #include "gpu/command_buffer/service/gl_utils.h"
     20 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
     21 #include "gpu/command_buffer/service/gpu_switches.h"
     22 #include "gpu/command_buffer/service/program_manager.h"
     23 #include "gpu/command_buffer/service/vertex_array_manager.h"
     24 
     25 namespace gpu {
     26 namespace gles2 {
     27 
     28 VertexAttrib::VertexAttrib()
     29     : index_(0),
     30       enabled_(false),
     31       size_(4),
     32       type_(GL_FLOAT),
     33       offset_(0),
     34       normalized_(GL_FALSE),
     35       gl_stride_(0),
     36       real_stride_(16),
     37       divisor_(0),
     38       is_client_side_array_(false),
     39       list_(NULL) {
     40 }
     41 
     42 VertexAttrib::~VertexAttrib() {
     43 }
     44 
     45 void VertexAttrib::SetInfo(
     46     Buffer* buffer,
     47     GLint size,
     48     GLenum type,
     49     GLboolean normalized,
     50     GLsizei gl_stride,
     51     GLsizei real_stride,
     52     GLsizei offset) {
     53   DCHECK_GT(real_stride, 0);
     54   buffer_ = buffer;
     55   size_ = size;
     56   type_ = type;
     57   normalized_ = normalized;
     58   gl_stride_ = gl_stride;
     59   real_stride_ = real_stride;
     60   offset_ = offset;
     61 }
     62 
     63 void VertexAttrib::Unbind(Buffer* buffer) {
     64   if (buffer_.get() == buffer) {
     65     buffer_ = NULL;
     66   }
     67 }
     68 
     69 bool VertexAttrib::CanAccess(GLuint index) const {
     70   if (!enabled_) {
     71     return true;
     72   }
     73 
     74   if (!buffer_.get() || buffer_->IsDeleted()) {
     75     return false;
     76   }
     77 
     78   // The number of elements that can be accessed.
     79   GLsizeiptr buffer_size = buffer_->size();
     80   if (offset_ > buffer_size || real_stride_ == 0) {
     81     return false;
     82   }
     83 
     84   uint32 usable_size = buffer_size - offset_;
     85   GLuint num_elements = usable_size / real_stride_ +
     86       ((usable_size % real_stride_) >=
     87        (GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type_) * size_) ? 1 : 0);
     88   return index < num_elements;
     89 }
     90 
     91 VertexAttribManager::VertexAttribManager()
     92     : num_fixed_attribs_(0),
     93       element_array_buffer_(NULL),
     94       manager_(NULL),
     95       deleted_(false),
     96       service_id_(0) {
     97 }
     98 
     99 VertexAttribManager::VertexAttribManager(
    100     VertexArrayManager* manager, GLuint service_id, uint32 num_vertex_attribs)
    101     : num_fixed_attribs_(0),
    102       element_array_buffer_(NULL),
    103       manager_(manager),
    104       deleted_(false),
    105       service_id_(service_id) {
    106   manager_->StartTracking(this);
    107   Initialize(num_vertex_attribs, false);
    108 }
    109 
    110 VertexAttribManager::~VertexAttribManager() {
    111   if (manager_) {
    112     if (manager_->have_context_) {
    113       if (service_id_ != 0)  // 0 indicates an emulated VAO
    114         glDeleteVertexArraysOES(1, &service_id_);
    115     }
    116     manager_->StopTracking(this);
    117     manager_ = NULL;
    118   }
    119 }
    120 
    121 void VertexAttribManager::Initialize(
    122     uint32 max_vertex_attribs, bool init_attribs) {
    123   vertex_attribs_.resize(max_vertex_attribs);
    124 
    125   for (uint32 vv = 0; vv < vertex_attribs_.size(); ++vv) {
    126     vertex_attribs_[vv].set_index(vv);
    127     vertex_attribs_[vv].SetList(&disabled_vertex_attribs_);
    128 
    129     if (init_attribs) {
    130       glVertexAttrib4f(vv, 0.0f, 0.0f, 0.0f, 1.0f);
    131     }
    132   }
    133 }
    134 
    135 void VertexAttribManager::SetElementArrayBuffer(Buffer* buffer) {
    136   element_array_buffer_ = buffer;
    137 }
    138 
    139 bool VertexAttribManager::Enable(GLuint index, bool enable) {
    140   if (index >= vertex_attribs_.size()) {
    141     return false;
    142   }
    143   VertexAttrib& info = vertex_attribs_[index];
    144   if (info.enabled() != enable) {
    145     info.set_enabled(enable);
    146     info.SetList(enable ? &enabled_vertex_attribs_ : &disabled_vertex_attribs_);
    147   }
    148   return true;
    149 }
    150 
    151 void VertexAttribManager::Unbind(Buffer* buffer) {
    152   if (element_array_buffer_.get() == buffer) {
    153     element_array_buffer_ = NULL;
    154   }
    155   for (uint32 vv = 0; vv < vertex_attribs_.size(); ++vv) {
    156     vertex_attribs_[vv].Unbind(buffer);
    157   }
    158 }
    159 
    160 bool VertexAttribManager::ValidateBindings(
    161     const char* function_name,
    162     GLES2Decoder* decoder,
    163     FeatureInfo* feature_info,
    164     Program* current_program,
    165     GLuint max_vertex_accessed,
    166     GLsizei primcount) {
    167   ErrorState* error_state = decoder->GetErrorState();
    168   // true if any enabled, used divisor is zero
    169   bool divisor0 = false;
    170   const GLuint kInitialBufferId = 0xFFFFFFFFU;
    171   GLuint current_buffer_id = kInitialBufferId;
    172   bool use_client_side_arrays_for_stream_buffers = feature_info->workarounds(
    173       ).use_client_side_arrays_for_stream_buffers;
    174   // Validate all attribs currently enabled. If they are used by the current
    175   // program then check that they have enough elements to handle the draw call.
    176   // If they are not used by the current program check that they have a buffer
    177   // assigned.
    178   for (VertexAttribList::iterator it = enabled_vertex_attribs_.begin();
    179        it != enabled_vertex_attribs_.end(); ++it) {
    180     VertexAttrib* attrib = *it;
    181     const Program::VertexAttrib* attrib_info =
    182         current_program->GetAttribInfoByLocation(attrib->index());
    183     if (attrib_info) {
    184       divisor0 |= (attrib->divisor() == 0);
    185       GLuint count = attrib->MaxVertexAccessed(primcount, max_vertex_accessed);
    186       // This attrib is used in the current program.
    187       if (!attrib->CanAccess(count)) {
    188         ERRORSTATE_SET_GL_ERROR(
    189             error_state, GL_INVALID_OPERATION, function_name,
    190             (std::string(
    191                  "attempt to access out of range vertices in attribute ") +
    192              base::IntToString(attrib->index())).c_str());
    193         return false;
    194       }
    195       if (use_client_side_arrays_for_stream_buffers) {
    196         Buffer* buffer = attrib->buffer();
    197         glEnableVertexAttribArray(attrib->index());
    198         if (buffer->IsClientSideArray()) {
    199           if (current_buffer_id != 0) {
    200             current_buffer_id = 0;
    201             glBindBuffer(GL_ARRAY_BUFFER, 0);
    202           }
    203           attrib->set_is_client_side_array(true);
    204           const void* ptr = buffer->GetRange(attrib->offset(), 0);
    205           DCHECK(ptr);
    206           glVertexAttribPointer(
    207               attrib->index(),
    208               attrib->size(),
    209               attrib->type(),
    210               attrib->normalized(),
    211               attrib->gl_stride(),
    212               ptr);
    213         } else if (attrib->is_client_side_array()) {
    214           attrib->set_is_client_side_array(false);
    215           GLuint new_buffer_id = buffer->service_id();
    216           if (new_buffer_id != current_buffer_id) {
    217             current_buffer_id = new_buffer_id;
    218             glBindBuffer(GL_ARRAY_BUFFER, current_buffer_id);
    219           }
    220           const void* ptr = reinterpret_cast<const void*>(attrib->offset());
    221           glVertexAttribPointer(
    222               attrib->index(),
    223               attrib->size(),
    224               attrib->type(),
    225               attrib->normalized(),
    226               attrib->gl_stride(),
    227               ptr);
    228         }
    229       }
    230     } else {
    231       // This attrib is not used in the current program.
    232       if (!attrib->buffer()) {
    233         ERRORSTATE_SET_GL_ERROR(
    234             error_state, GL_INVALID_OPERATION, function_name,
    235             (std::string(
    236                  "attempt to render with no buffer attached to "
    237                  "enabled attribute ") +
    238                  base::IntToString(attrib->index())).c_str());
    239         return false;
    240       } else if (use_client_side_arrays_for_stream_buffers) {
    241         Buffer* buffer = attrib->buffer();
    242         // Disable client side arrays for unused attributes else we'll
    243         // read bad memory
    244         if (buffer->IsClientSideArray()) {
    245           // Don't disable attrib 0 since it's special.
    246           if (attrib->index() > 0) {
    247             glDisableVertexAttribArray(attrib->index());
    248           }
    249         }
    250       }
    251     }
    252   }
    253 
    254   if (primcount && !divisor0) {
    255     ERRORSTATE_SET_GL_ERROR(
    256         error_state, GL_INVALID_OPERATION, function_name,
    257         "attempt instanced render with all attributes having "
    258         "non-zero divisors");
    259     return false;
    260   }
    261 
    262   if (current_buffer_id != kInitialBufferId) {
    263     // Restore the buffer binding.
    264     decoder->RestoreBufferBindings();
    265   }
    266 
    267   return true;
    268 }
    269 
    270 }  // namespace gles2
    271 }  // namespace gpu
    272