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