• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
BufferManager(MemoryTracker * memory_tracker,FeatureInfo * feature_info)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 
~BufferManager()33 BufferManager::~BufferManager() {
34   DCHECK(buffers_.empty());
35   CHECK_EQ(buffer_count_, 0u);
36 }
37 
Destroy(bool have_context)38 void BufferManager::Destroy(bool have_context) {
39   have_context_ = have_context;
40   buffers_.clear();
41   DCHECK_EQ(0u, memory_tracker_->GetMemRepresented());
42 }
43 
CreateBuffer(GLuint client_id,GLuint service_id)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 
GetBuffer(GLuint client_id)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 
RemoveBuffer(GLuint client_id)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 
StartTracking(Buffer *)66 void BufferManager::StartTracking(Buffer* /* buffer */) {
67   ++buffer_count_;
68 }
69 
StopTracking(Buffer * buffer)70 void BufferManager::StopTracking(Buffer* buffer) {
71   memory_tracker_->TrackMemFree(buffer->size());
72   --buffer_count_;
73 }
74 
Buffer(BufferManager * manager,GLuint service_id)75 Buffer::Buffer(BufferManager* manager, GLuint service_id)
76     : manager_(manager),
77       size_(0),
78       deleted_(false),
79       shadowed_(false),
80       is_client_side_array_(false),
81       service_id_(service_id),
82       target_(0),
83       usage_(GL_STATIC_DRAW) {
84   manager_->StartTracking(this);
85 }
86 
~Buffer()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 
SetInfo(GLsizeiptr size,GLenum usage,bool shadow,const GLvoid * data,bool is_client_side_array)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 
CheckRange(GLintptr offset,GLsizeiptr size) const122 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 
SetRange(GLintptr offset,GLsizeiptr size,const GLvoid * data)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 
GetRange(GLintptr offset,GLsizeiptr size) const143 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 
ClearCache()154 void Buffer::ClearCache() {
155   range_set_.clear();
156 }
157 
158 template <typename T>
GetMaxValue(const void * data,GLuint offset,GLsizei count)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 
GetMaxValueForRange(GLuint offset,GLsizei count,GLenum type,GLuint * max_value)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 
GetClientId(GLuint service_id,GLuint * client_id) const228 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 
IsUsageClientSideArray(GLenum usage)240 bool BufferManager::IsUsageClientSideArray(GLenum usage) {
241   return usage == GL_STREAM_DRAW && use_client_side_arrays_for_stream_buffers_;
242 }
243 
UseNonZeroSizeForClientSideArrayBuffer()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 
SetInfo(Buffer * buffer,GLsizeiptr size,GLenum usage,const GLvoid * data)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 
ValidateAndDoBufferData(ContextState * context_state,GLenum target,GLsizeiptr size,const GLvoid * data,GLenum usage)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 
DoBufferData(ErrorState * error_state,Buffer * buffer,GLsizeiptr size,GLenum usage,const GLvoid * data)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 
ValidateAndDoBufferSubData(ContextState * context_state,GLenum target,GLintptr offset,GLsizeiptr size,const GLvoid * data)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 
DoBufferSubData(ErrorState * error_state,Buffer * buffer,GLintptr offset,GLsizeiptr size,const GLvoid * data)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 
ValidateAndDoGetBufferParameteriv(ContextState * context_state,GLenum target,GLenum pname,GLint * params)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 
SetTarget(Buffer * buffer,GLenum target)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.
GetBufferInfoForTarget(ContextState * state,GLenum target)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