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"
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"
20 BufferManager::BufferManager(
21 MemoryTracker
* memory_tracker
,
22 FeatureInfo
* feature_info
)
24 new MemoryTypeTracker(memory_tracker
, MemoryTracker::kManaged
)),
25 feature_info_(feature_info
),
26 allow_buffers_on_multiple_targets_(false),
27 allow_fixed_attribs_(false),
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
;
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(
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();
68 void BufferManager::StartTracking(Buffer
* /* buffer */) {
72 void BufferManager::StopTracking(Buffer
* buffer
) {
73 memory_tracker_
->TrackMemFree(buffer
->size());
77 Buffer::MappedRange::MappedRange(
78 GLintptr offset
, GLsizeiptr size
, GLenum access
, void* pointer
,
79 scoped_refptr
<gpu::Buffer
> shm
)
86 DCHECK(shm
.get() && GetShmPointer());
89 Buffer::MappedRange::~MappedRange() {
92 void* Buffer::MappedRange::GetShmPointer() const {
94 return shm
->GetDataAddress(static_cast<unsigned int>(offset
),
95 static_cast<unsigned int>(size
));
98 Buffer::Buffer(BufferManager
* manager
, GLuint service_id
)
103 is_client_side_array_(false),
104 service_id_(service_id
),
106 usage_(GL_STATIC_DRAW
) {
107 manager_
->StartTracking(this);
112 if (manager_
->have_context_
) {
113 GLuint id
= service_id();
114 glDeleteBuffersARB(1, &id
);
116 manager_
->StopTracking(this);
121 void Buffer::SetInfo(
122 GLsizeiptr size
, GLenum usage
, bool shadow
, const GLvoid
* data
,
123 bool is_client_side_array
) {
125 is_client_side_array_
= is_client_side_array
;
127 if (size
!= size_
|| shadow
!= shadowed_
) {
131 shadow_
.reset(new int8
[size
]);
138 memcpy(shadow_
.get(), data
, size
);
140 memset(shadow_
.get(), 0, size
);
143 mapped_range_
.reset(nullptr);
146 bool Buffer::CheckRange(
147 GLintptr offset
, GLsizeiptr size
) const {
149 return offset
>= 0 && size
>= 0 &&
150 offset
<= std::numeric_limits
<int32
>::max() &&
151 size
<= std::numeric_limits
<int32
>::max() &&
152 SafeAddInt32(offset
, size
, &end
) && end
<= size_
;
155 bool Buffer::SetRange(
156 GLintptr offset
, GLsizeiptr size
, const GLvoid
* data
) {
157 if (!CheckRange(offset
, size
)) {
161 memcpy(shadow_
.get() + offset
, data
, size
);
167 const void* Buffer::GetRange(
168 GLintptr offset
, GLsizeiptr size
) const {
172 if (!CheckRange(offset
, size
)) {
175 return shadow_
.get() + offset
;
178 void Buffer::ClearCache() {
182 template <typename T
>
183 GLuint
GetMaxValue(const void* data
, GLuint offset
, GLsizei count
) {
184 GLuint max_value
= 0;
185 const T
* element
= reinterpret_cast<const T
*>(
186 static_cast<const int8
*>(data
) + offset
);
187 const T
* end
= element
+ count
;
188 for (; element
< end
; ++element
) {
189 if (*element
> max_value
) {
190 max_value
= *element
;
196 bool Buffer::GetMaxValueForRange(
197 GLuint offset
, GLsizei count
, GLenum type
, GLuint
* max_value
) {
198 Range
range(offset
, count
, type
);
199 RangeToMaxValueMap::iterator it
= range_set_
.find(range
);
200 if (it
!= range_set_
.end()) {
201 *max_value
= it
->second
;
206 if (!SafeMultiplyUint32(
207 count
, GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type
), &size
)) {
211 if (!SafeAddUint32(offset
, size
, &size
)) {
215 if (size
> static_cast<uint32
>(size_
)) {
223 // Scan the range for the max value and store
226 case GL_UNSIGNED_BYTE
:
227 max_v
= GetMaxValue
<uint8
>(shadow_
.get(), offset
, count
);
229 case GL_UNSIGNED_SHORT
:
230 // Check we are not accessing an odd byte for a 2 byte value.
231 if ((offset
& 1) != 0) {
234 max_v
= GetMaxValue
<uint16
>(shadow_
.get(), offset
, count
);
236 case GL_UNSIGNED_INT
:
237 // Check we are not accessing a non aligned address for a 4 byte value.
238 if ((offset
& 3) != 0) {
241 max_v
= GetMaxValue
<uint32
>(shadow_
.get(), offset
, count
);
244 NOTREACHED(); // should never get here by validation.
247 range_set_
.insert(std::make_pair(range
, max_v
));
252 bool BufferManager::GetClientId(GLuint service_id
, GLuint
* client_id
) const {
253 // This doesn't need to be fast. It's only used during slow queries.
254 for (BufferMap::const_iterator it
= buffers_
.begin();
255 it
!= buffers_
.end(); ++it
) {
256 if (it
->second
->service_id() == service_id
) {
257 *client_id
= it
->first
;
264 bool BufferManager::IsUsageClientSideArray(GLenum usage
) {
265 return usage
== GL_STREAM_DRAW
&& use_client_side_arrays_for_stream_buffers_
;
268 bool BufferManager::UseNonZeroSizeForClientSideArrayBuffer() {
269 return feature_info_
.get() &&
270 feature_info_
->workarounds()
271 .use_non_zero_size_for_client_side_stream_buffers
;
274 void BufferManager::SetInfo(Buffer
* buffer
, GLenum target
, GLsizeiptr size
,
275 GLenum usage
, const GLvoid
* data
) {
277 memory_tracker_
->TrackMemFree(buffer
->size());
278 const bool is_client_side_array
= IsUsageClientSideArray(usage
);
279 const bool support_fixed_attribs
=
280 gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2
;
281 // TODO(zmo): Don't shadow buffer data on ES3. crbug.com/491002.
282 const bool shadow
= target
== GL_ELEMENT_ARRAY_BUFFER
||
283 allow_buffers_on_multiple_targets_
||
284 (allow_fixed_attribs_
&& !support_fixed_attribs
) ||
285 is_client_side_array
;
286 buffer
->SetInfo(size
, usage
, shadow
, data
, is_client_side_array
);
287 memory_tracker_
->TrackMemAlloc(buffer
->size());
290 void BufferManager::ValidateAndDoBufferData(
291 ContextState
* context_state
, GLenum target
, GLsizeiptr size
,
292 const GLvoid
* data
, GLenum usage
) {
293 ErrorState
* error_state
= context_state
->GetErrorState();
294 if (!feature_info_
->validators()->buffer_target
.IsValid(target
)) {
295 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
296 error_state
, "glBufferData", target
, "target");
299 if (!feature_info_
->validators()->buffer_usage
.IsValid(usage
)) {
300 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
301 error_state
, "glBufferData", usage
, "usage");
305 ERRORSTATE_SET_GL_ERROR(
306 error_state
, GL_INVALID_VALUE
, "glBufferData", "size < 0");
310 Buffer
* buffer
= GetBufferInfoForTarget(context_state
, target
);
312 ERRORSTATE_SET_GL_ERROR(
313 error_state
, GL_INVALID_VALUE
, "glBufferData", "unknown buffer");
317 if (!memory_tracker_
->EnsureGPUMemoryAvailable(size
)) {
318 ERRORSTATE_SET_GL_ERROR(
319 error_state
, GL_OUT_OF_MEMORY
, "glBufferData", "out of memory");
323 DoBufferData(error_state
, buffer
, target
, size
, usage
, data
);
327 void BufferManager::DoBufferData(
328 ErrorState
* error_state
,
333 const GLvoid
* data
) {
334 // Clear the buffer to 0 if no initial data was passed in.
335 scoped_ptr
<int8
[]> zero
;
337 zero
.reset(new int8
[size
]);
338 memset(zero
.get(), 0, size
);
342 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state
, "glBufferData");
343 if (IsUsageClientSideArray(usage
)) {
344 GLsizei empty_size
= UseNonZeroSizeForClientSideArrayBuffer() ? 1 : 0;
345 glBufferData(target
, empty_size
, NULL
, usage
);
347 glBufferData(target
, size
, data
, usage
);
349 GLenum error
= ERRORSTATE_PEEK_GL_ERROR(error_state
, "glBufferData");
350 if (error
== GL_NO_ERROR
) {
351 SetInfo(buffer
, target
, size
, usage
, data
);
353 SetInfo(buffer
, target
, 0, usage
, NULL
);
357 void BufferManager::ValidateAndDoBufferSubData(
358 ContextState
* context_state
, GLenum target
, GLintptr offset
, GLsizeiptr size
,
359 const GLvoid
* data
) {
360 ErrorState
* error_state
= context_state
->GetErrorState();
361 Buffer
* buffer
= GetBufferInfoForTarget(context_state
, target
);
363 ERRORSTATE_SET_GL_ERROR(error_state
, GL_INVALID_VALUE
, "glBufferSubData",
368 DoBufferSubData(error_state
, buffer
, target
, offset
, size
, data
);
371 void BufferManager::DoBufferSubData(
372 ErrorState
* error_state
,
377 const GLvoid
* data
) {
378 if (!buffer
->SetRange(offset
, size
, data
)) {
379 ERRORSTATE_SET_GL_ERROR(
380 error_state
, GL_INVALID_VALUE
, "glBufferSubData", "out of range");
384 if (!buffer
->IsClientSideArray()) {
385 glBufferSubData(target
, offset
, size
, data
);
389 void BufferManager::ValidateAndDoGetBufferParameteriv(
390 ContextState
* context_state
, GLenum target
, GLenum pname
, GLint
* params
) {
391 Buffer
* buffer
= GetBufferInfoForTarget(context_state
, target
);
393 ERRORSTATE_SET_GL_ERROR(
394 context_state
->GetErrorState(), GL_INVALID_OPERATION
,
395 "glGetBufferParameteriv", "no buffer bound for target");
400 *params
= buffer
->size();
402 case GL_BUFFER_USAGE
:
403 *params
= buffer
->usage();
410 bool BufferManager::SetTarget(Buffer
* buffer
, GLenum target
) {
411 if (!allow_buffers_on_multiple_targets_
) {
412 // After being bound to ELEMENT_ARRAY_BUFFER target, a buffer cannot be
413 // bound to any other targets except for COPY_READ/WRITE_BUFFER target;
414 // After being bound to non ELEMENT_ARRAY_BUFFER target, a buffer cannot
415 // be bound to ELEMENT_ARRAY_BUFFER target.
417 // Note that we don't force the WebGL 2 rule that a buffer bound to
418 // TRANSFORM_FEEDBACK_BUFFER target should not be bound to any other
419 // targets, because that is not a security threat, so we only enforce it
420 // in the WebGL2RenderingContextBase.
421 switch (buffer
->initial_target()) {
422 case GL_ELEMENT_ARRAY_BUFFER
:
424 case GL_ARRAY_BUFFER
:
425 case GL_PIXEL_PACK_BUFFER
:
426 case GL_PIXEL_UNPACK_BUFFER
:
427 case GL_TRANSFORM_FEEDBACK_BUFFER
:
428 case GL_UNIFORM_BUFFER
:
434 case GL_ARRAY_BUFFER
:
435 case GL_COPY_READ_BUFFER
:
436 case GL_COPY_WRITE_BUFFER
:
437 case GL_PIXEL_PACK_BUFFER
:
438 case GL_PIXEL_UNPACK_BUFFER
:
439 case GL_TRANSFORM_FEEDBACK_BUFFER
:
440 case GL_UNIFORM_BUFFER
:
441 if (target
== GL_ELEMENT_ARRAY_BUFFER
) {
449 if (buffer
->initial_target() == 0)
450 buffer
->set_initial_target(target
);
454 // Since one BufferManager can be shared by multiple decoders, ContextState is
455 // passed in each time and not just passed in during initialization.
456 Buffer
* BufferManager::GetBufferInfoForTarget(
457 ContextState
* state
, GLenum target
) const {
459 case GL_ARRAY_BUFFER
:
460 return state
->bound_array_buffer
.get();
461 case GL_ELEMENT_ARRAY_BUFFER
:
462 return state
->vertex_attrib_manager
->element_array_buffer();
463 case GL_COPY_READ_BUFFER
:
464 return state
->bound_copy_read_buffer
.get();
465 case GL_COPY_WRITE_BUFFER
:
466 return state
->bound_copy_write_buffer
.get();
467 case GL_PIXEL_PACK_BUFFER
:
468 return state
->bound_pixel_pack_buffer
.get();
469 case GL_PIXEL_UNPACK_BUFFER
:
470 return state
->bound_pixel_unpack_buffer
.get();
471 case GL_TRANSFORM_FEEDBACK_BUFFER
:
472 return state
->bound_transform_feedback_buffer
.get();
473 case GL_UNIFORM_BUFFER
:
474 return state
->bound_uniform_buffer
.get();