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