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/buffer_manager.h"
      6 #include <limits>
      7 #include "base/debug/trace_event.h"
      8 #include "base/logging.h"
      9 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
     10 #include "gpu/command_buffer/service/context_state.h"
     11 #include "gpu/command_buffer/service/error_state.h"
     12 #include "gpu/command_buffer/service/feature_info.h"
     13 #include "gpu/command_buffer/service/memory_tracking.h"
     14 #include "ui/gl/gl_bindings.h"
     15 
     16 namespace gpu {
     17 namespace gles2 {
     18 
     19 BufferManager::BufferManager(
     20     MemoryTracker* memory_tracker,
     21     FeatureInfo* feature_info)
     22     : memory_tracker_(
     23           new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)),
     24       feature_info_(feature_info),
     25       allow_buffers_on_multiple_targets_(false),
     26       buffer_count_(0),
     27       have_context_(true),
     28       use_client_side_arrays_for_stream_buffers_(
     29           feature_info ? feature_info->workarounds(
     30               ).use_client_side_arrays_for_stream_buffers : 0) {
     31 }
     32 
     33 BufferManager::~BufferManager() {
     34   DCHECK(buffers_.empty());
     35   CHECK_EQ(buffer_count_, 0u);
     36 }
     37 
     38 void BufferManager::Destroy(bool have_context) {
     39   have_context_ = have_context;
     40   buffers_.clear();
     41   DCHECK_EQ(0u, memory_tracker_->GetMemRepresented());
     42 }
     43 
     44 void BufferManager::CreateBuffer(GLuint client_id, GLuint service_id) {
     45   scoped_refptr<Buffer> buffer(new Buffer(this, service_id));
     46   std::pair<BufferMap::iterator, bool> result =
     47       buffers_.insert(std::make_pair(client_id, buffer));
     48   DCHECK(result.second);
     49 }
     50 
     51 Buffer* BufferManager::GetBuffer(
     52     GLuint client_id) {
     53   BufferMap::iterator it = buffers_.find(client_id);
     54   return it != buffers_.end() ? it->second.get() : NULL;
     55 }
     56 
     57 void BufferManager::RemoveBuffer(GLuint client_id) {
     58   BufferMap::iterator it = buffers_.find(client_id);
     59   if (it != buffers_.end()) {
     60     Buffer* buffer = it->second.get();
     61     buffer->MarkAsDeleted();
     62     buffers_.erase(it);
     63   }
     64 }
     65 
     66 void BufferManager::StartTracking(Buffer* /* buffer */) {
     67   ++buffer_count_;
     68 }
     69 
     70 void BufferManager::StopTracking(Buffer* buffer) {
     71   memory_tracker_->TrackMemFree(buffer->size());
     72   --buffer_count_;
     73 }
     74 
     75 Buffer::Buffer(BufferManager* manager, GLuint service_id)
     76     : manager_(manager),
     77       deleted_(false),
     78       service_id_(service_id),
     79       target_(0),
     80       size_(0),
     81       usage_(GL_STATIC_DRAW),
     82       shadowed_(false),
     83       is_client_side_array_(false) {
     84   manager_->StartTracking(this);
     85 }
     86 
     87 Buffer::~Buffer() {
     88   if (manager_) {
     89     if (manager_->have_context_) {
     90       GLuint id = service_id();
     91       glDeleteBuffersARB(1, &id);
     92     }
     93     manager_->StopTracking(this);
     94     manager_ = NULL;
     95   }
     96 }
     97 
     98 void Buffer::SetInfo(
     99     GLsizeiptr size, GLenum usage, bool shadow, const GLvoid* data,
    100     bool is_client_side_array) {
    101   usage_ = usage;
    102   is_client_side_array_ = is_client_side_array;
    103   ClearCache();
    104   if (size != size_ || shadow != shadowed_) {
    105     shadowed_ = shadow;
    106     size_ = size;
    107     if (shadowed_) {
    108       shadow_.reset(new int8[size]);
    109     } else {
    110       shadow_.reset();
    111     }
    112   }
    113   if (shadowed_) {
    114     if (data) {
    115       memcpy(shadow_.get(), data, size);
    116     } else {
    117       memset(shadow_.get(), 0, size);
    118     }
    119   }
    120 }
    121 
    122 bool Buffer::CheckRange(
    123     GLintptr offset, GLsizeiptr size) const {
    124   int32 end = 0;
    125   return offset >= 0 && size >= 0 &&
    126          offset <= std::numeric_limits<int32>::max() &&
    127          size <= std::numeric_limits<int32>::max() &&
    128          SafeAddInt32(offset, size, &end) && end <= size_;
    129 }
    130 
    131 bool Buffer::SetRange(
    132     GLintptr offset, GLsizeiptr size, const GLvoid * data) {
    133   if (!CheckRange(offset, size)) {
    134     return false;
    135   }
    136   if (shadowed_) {
    137     memcpy(shadow_.get() + offset, data, size);
    138     ClearCache();
    139   }
    140   return true;
    141 }
    142 
    143 const void* Buffer::GetRange(
    144     GLintptr offset, GLsizeiptr size) const {
    145   if (!shadowed_) {
    146     return NULL;
    147   }
    148   if (!CheckRange(offset, size)) {
    149     return NULL;
    150   }
    151   return shadow_.get() + offset;
    152 }
    153 
    154 void Buffer::ClearCache() {
    155   range_set_.clear();
    156 }
    157 
    158 template <typename T>
    159 GLuint GetMaxValue(const void* data, GLuint offset, GLsizei count) {
    160   GLuint max_value = 0;
    161   const T* element = reinterpret_cast<const T*>(
    162       static_cast<const int8*>(data) + offset);
    163   const T* end = element + count;
    164   for (; element < end; ++element) {
    165     if (*element > max_value) {
    166       max_value = *element;
    167     }
    168   }
    169   return max_value;
    170 }
    171 
    172 bool Buffer::GetMaxValueForRange(
    173     GLuint offset, GLsizei count, GLenum type, GLuint* max_value) {
    174   Range range(offset, count, type);
    175   RangeToMaxValueMap::iterator it = range_set_.find(range);
    176   if (it != range_set_.end()) {
    177     *max_value = it->second;
    178     return true;
    179   }
    180 
    181   uint32 size;
    182   if (!SafeMultiplyUint32(
    183       count, GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type), &size)) {
    184     return false;
    185   }
    186 
    187   if (!SafeAddUint32(offset, size, &size)) {
    188     return false;
    189   }
    190 
    191   if (size > static_cast<uint32>(size_)) {
    192     return false;
    193   }
    194 
    195   if (!shadowed_) {
    196     return false;
    197   }
    198 
    199   // Scan the range for the max value and store
    200   GLuint max_v = 0;
    201   switch (type) {
    202     case GL_UNSIGNED_BYTE:
    203       max_v = GetMaxValue<uint8>(shadow_.get(), offset, count);
    204       break;
    205     case GL_UNSIGNED_SHORT:
    206       // Check we are not accessing an odd byte for a 2 byte value.
    207       if ((offset & 1) != 0) {
    208         return false;
    209       }
    210       max_v = GetMaxValue<uint16>(shadow_.get(), offset, count);
    211       break;
    212     case GL_UNSIGNED_INT:
    213       // Check we are not accessing a non aligned address for a 4 byte value.
    214       if ((offset & 3) != 0) {
    215         return false;
    216       }
    217       max_v = GetMaxValue<uint32>(shadow_.get(), offset, count);
    218       break;
    219     default:
    220       NOTREACHED();  // should never get here by validation.
    221       break;
    222   }
    223   range_set_.insert(std::make_pair(range, max_v));
    224   *max_value = max_v;
    225   return true;
    226 }
    227 
    228 bool BufferManager::GetClientId(GLuint service_id, GLuint* client_id) const {
    229   // This doesn't need to be fast. It's only used during slow queries.
    230   for (BufferMap::const_iterator it = buffers_.begin();
    231        it != buffers_.end(); ++it) {
    232     if (it->second->service_id() == service_id) {
    233       *client_id = it->first;
    234       return true;
    235     }
    236   }
    237   return false;
    238 }
    239 
    240 bool BufferManager::IsUsageClientSideArray(GLenum usage) {
    241   return usage == GL_STREAM_DRAW && use_client_side_arrays_for_stream_buffers_;
    242 }
    243 
    244 bool BufferManager::UseNonZeroSizeForClientSideArrayBuffer() {
    245   return feature_info_.get() &&
    246          feature_info_->workarounds()
    247              .use_non_zero_size_for_client_side_stream_buffers;
    248 }
    249 
    250 void BufferManager::SetInfo(
    251     Buffer* buffer, GLsizeiptr size, GLenum usage, const GLvoid* data) {
    252   DCHECK(buffer);
    253   memory_tracker_->TrackMemFree(buffer->size());
    254   bool is_client_side_array = IsUsageClientSideArray(usage);
    255   bool shadow = buffer->target() == GL_ELEMENT_ARRAY_BUFFER ||
    256                 allow_buffers_on_multiple_targets_ ||
    257                 is_client_side_array;
    258   buffer->SetInfo(size, usage, shadow, data, is_client_side_array);
    259   memory_tracker_->TrackMemAlloc(buffer->size());
    260 }
    261 
    262 void BufferManager::ValidateAndDoBufferData(
    263     ContextState* context_state, GLenum target, GLsizeiptr size,
    264     const GLvoid * data, GLenum usage) {
    265   ErrorState* error_state = context_state->GetErrorState();
    266   if (!feature_info_->validators()->buffer_target.IsValid(target)) {
    267     ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
    268         error_state, "glBufferData", target, "target");
    269     return;
    270   }
    271   if (!feature_info_->validators()->buffer_usage.IsValid(usage)) {
    272     ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
    273         error_state, "glBufferData", usage, "usage");
    274     return;
    275   }
    276   if (size < 0) {
    277     ERRORSTATE_SET_GL_ERROR(
    278         error_state, GL_INVALID_VALUE, "glBufferData", "size < 0");
    279     return;
    280   }
    281 
    282   Buffer* buffer = GetBufferInfoForTarget(context_state, target);
    283   if (!buffer) {
    284     ERRORSTATE_SET_GL_ERROR(
    285         error_state, GL_INVALID_VALUE, "glBufferData", "unknown buffer");
    286     return;
    287   }
    288 
    289   if (!memory_tracker_->EnsureGPUMemoryAvailable(size)) {
    290     ERRORSTATE_SET_GL_ERROR(
    291         error_state, GL_OUT_OF_MEMORY, "glBufferData", "out of memory");
    292     return;
    293   }
    294 
    295   DoBufferData(error_state, buffer, size, usage, data);
    296 }
    297 
    298 
    299 void BufferManager::DoBufferData(
    300     ErrorState* error_state,
    301     Buffer* buffer,
    302     GLsizeiptr size,
    303     GLenum usage,
    304     const GLvoid* data) {
    305   // Clear the buffer to 0 if no initial data was passed in.
    306   scoped_ptr<int8[]> zero;
    307   if (!data) {
    308     zero.reset(new int8[size]);
    309     memset(zero.get(), 0, size);
    310     data = zero.get();
    311   }
    312 
    313   ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glBufferData");
    314   if (IsUsageClientSideArray(usage)) {
    315     GLsizei empty_size = UseNonZeroSizeForClientSideArrayBuffer() ? 1 : 0;
    316     glBufferData(buffer->target(), empty_size, NULL, usage);
    317   } else {
    318     glBufferData(buffer->target(), size, data, usage);
    319   }
    320   GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glBufferData");
    321   if (error == GL_NO_ERROR) {
    322     SetInfo(buffer, size, usage, data);
    323   } else {
    324     SetInfo(buffer, 0, usage, NULL);
    325   }
    326 }
    327 
    328 void BufferManager::ValidateAndDoBufferSubData(
    329   ContextState* context_state, GLenum target, GLintptr offset, GLsizeiptr size,
    330   const GLvoid * data) {
    331   ErrorState* error_state = context_state->GetErrorState();
    332   Buffer* buffer = GetBufferInfoForTarget(context_state, target);
    333   if (!buffer) {
    334     ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, "glBufferSubData",
    335                             "unknown buffer");
    336     return;
    337   }
    338 
    339   DoBufferSubData(error_state, buffer, offset, size, data);
    340 }
    341 
    342 void BufferManager::DoBufferSubData(
    343     ErrorState* error_state,
    344     Buffer* buffer,
    345     GLintptr offset,
    346     GLsizeiptr size,
    347     const GLvoid* data) {
    348   if (!buffer->SetRange(offset, size, data)) {
    349     ERRORSTATE_SET_GL_ERROR(
    350         error_state, GL_INVALID_VALUE, "glBufferSubData", "out of range");
    351     return;
    352   }
    353 
    354   if (!buffer->IsClientSideArray()) {
    355     glBufferSubData(buffer->target(), offset, size, data);
    356   }
    357 }
    358 
    359 void BufferManager::ValidateAndDoGetBufferParameteriv(
    360     ContextState* context_state, GLenum target, GLenum pname, GLint* params) {
    361   Buffer* buffer = GetBufferInfoForTarget(context_state, target);
    362   if (!buffer) {
    363     ERRORSTATE_SET_GL_ERROR(
    364         context_state->GetErrorState(), GL_INVALID_OPERATION,
    365         "glGetBufferParameteriv", "no buffer bound for target");
    366     return;
    367   }
    368   switch (pname) {
    369     case GL_BUFFER_SIZE:
    370       *params = buffer->size();
    371       break;
    372     case GL_BUFFER_USAGE:
    373       *params = buffer->usage();
    374       break;
    375     default:
    376       NOTREACHED();
    377   }
    378 }
    379 
    380 bool BufferManager::SetTarget(Buffer* buffer, GLenum target) {
    381   // Check that we are not trying to bind it to a different target.
    382   if (buffer->target() != 0 && buffer->target() != target &&
    383       !allow_buffers_on_multiple_targets_) {
    384     return false;
    385   }
    386   if (buffer->target() == 0) {
    387     buffer->set_target(target);
    388   }
    389   return true;
    390 }
    391 
    392 // Since one BufferManager can be shared by multiple decoders, ContextState is
    393 // passed in each time and not just passed in during initialization.
    394 Buffer* BufferManager::GetBufferInfoForTarget(
    395     ContextState* state, GLenum target) {
    396   DCHECK(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER);
    397   if (target == GL_ARRAY_BUFFER) {
    398     return state->bound_array_buffer.get();
    399   } else {
    400     return state->vertex_attrib_manager->element_array_buffer();
    401   }
    402 }
    403 
    404 }  // namespace gles2
    405 }  // namespace gpu
    406 
    407 
    408