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/strings/stringprintf.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "base/trace_event/memory_dump_manager.h"
11 #include "base/trace_event/trace_event.h"
12 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
13 #include "gpu/command_buffer/service/context_state.h"
14 #include "gpu/command_buffer/service/error_state.h"
15 #include "gpu/command_buffer/service/feature_info.h"
16 #include "gpu/command_buffer/service/memory_tracking.h"
17 #include "ui/gl/gl_bindings.h"
18 #include "ui/gl/gl_implementation.h"
19 #include "ui/gl/trace_util.h"
24 BufferManager::BufferManager(MemoryTracker
* memory_tracker
,
25 FeatureInfo
* feature_info
)
26 : memory_type_tracker_(
27 new MemoryTypeTracker(memory_tracker
, MemoryTracker::kManaged
)),
28 memory_tracker_(memory_tracker
),
29 feature_info_(feature_info
),
30 allow_buffers_on_multiple_targets_(false),
31 allow_fixed_attribs_(false),
34 use_client_side_arrays_for_stream_buffers_(
36 ? feature_info
->workarounds()
37 .use_client_side_arrays_for_stream_buffers
39 // When created from InProcessCommandBuffer, we won't have a |memory_tracker_|
40 // so don't register a dump provider.
41 if (memory_tracker_
) {
42 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
43 this, base::ThreadTaskRunnerHandle::Get());
47 BufferManager::~BufferManager() {
48 DCHECK(buffers_
.empty());
49 CHECK_EQ(buffer_count_
, 0u);
51 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
55 void BufferManager::Destroy(bool have_context
) {
56 have_context_
= have_context
;
58 DCHECK_EQ(0u, memory_type_tracker_
->GetMemRepresented());
61 void BufferManager::CreateBuffer(GLuint client_id
, GLuint service_id
) {
62 scoped_refptr
<Buffer
> buffer(new Buffer(this, service_id
));
63 std::pair
<BufferMap::iterator
, bool> result
=
64 buffers_
.insert(std::make_pair(client_id
, buffer
));
65 DCHECK(result
.second
);
68 Buffer
* BufferManager::GetBuffer(
70 BufferMap::iterator it
= buffers_
.find(client_id
);
71 return it
!= buffers_
.end() ? it
->second
.get() : NULL
;
74 void BufferManager::RemoveBuffer(GLuint client_id
) {
75 BufferMap::iterator it
= buffers_
.find(client_id
);
76 if (it
!= buffers_
.end()) {
77 Buffer
* buffer
= it
->second
.get();
78 buffer
->MarkAsDeleted();
83 void BufferManager::StartTracking(Buffer
* /* buffer */) {
87 void BufferManager::StopTracking(Buffer
* buffer
) {
88 memory_type_tracker_
->TrackMemFree(buffer
->size());
92 Buffer::MappedRange::MappedRange(
93 GLintptr offset
, GLsizeiptr size
, GLenum access
, void* pointer
,
94 scoped_refptr
<gpu::Buffer
> shm
)
101 DCHECK(shm
.get() && GetShmPointer());
104 Buffer::MappedRange::~MappedRange() {
107 void* Buffer::MappedRange::GetShmPointer() const {
109 return shm
->GetDataAddress(static_cast<unsigned int>(offset
),
110 static_cast<unsigned int>(size
));
113 Buffer::Buffer(BufferManager
* manager
, GLuint service_id
)
118 is_client_side_array_(false),
119 service_id_(service_id
),
121 usage_(GL_STATIC_DRAW
) {
122 manager_
->StartTracking(this);
127 if (manager_
->have_context_
) {
128 GLuint id
= service_id();
129 glDeleteBuffersARB(1, &id
);
131 manager_
->StopTracking(this);
136 void Buffer::SetInfo(
137 GLsizeiptr size
, GLenum usage
, bool shadow
, const GLvoid
* data
,
138 bool is_client_side_array
) {
140 is_client_side_array_
= is_client_side_array
;
142 if (size
!= size_
|| shadow
!= shadowed_
) {
146 shadow_
.reset(new int8
[size
]);
153 memcpy(shadow_
.get(), data
, size
);
155 memset(shadow_
.get(), 0, size
);
158 mapped_range_
.reset(nullptr);
161 bool Buffer::CheckRange(
162 GLintptr offset
, GLsizeiptr size
) const {
164 return offset
>= 0 && size
>= 0 &&
165 offset
<= std::numeric_limits
<int32
>::max() &&
166 size
<= std::numeric_limits
<int32
>::max() &&
167 SafeAddInt32(offset
, size
, &end
) && end
<= size_
;
170 bool Buffer::SetRange(
171 GLintptr offset
, GLsizeiptr size
, const GLvoid
* data
) {
172 if (!CheckRange(offset
, size
)) {
176 memcpy(shadow_
.get() + offset
, data
, size
);
182 const void* Buffer::GetRange(
183 GLintptr offset
, GLsizeiptr size
) const {
187 if (!CheckRange(offset
, size
)) {
190 return shadow_
.get() + offset
;
193 void Buffer::ClearCache() {
197 template <typename T
>
198 GLuint
GetMaxValue(const void* data
, GLuint offset
, GLsizei count
) {
199 GLuint max_value
= 0;
200 const T
* element
= reinterpret_cast<const T
*>(
201 static_cast<const int8
*>(data
) + offset
);
202 const T
* end
= element
+ count
;
203 for (; element
< end
; ++element
) {
204 if (*element
> max_value
) {
205 max_value
= *element
;
211 bool Buffer::GetMaxValueForRange(
212 GLuint offset
, GLsizei count
, GLenum type
, GLuint
* max_value
) {
213 Range
range(offset
, count
, type
);
214 RangeToMaxValueMap::iterator it
= range_set_
.find(range
);
215 if (it
!= range_set_
.end()) {
216 *max_value
= it
->second
;
221 if (!SafeMultiplyUint32(
222 count
, GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type
), &size
)) {
226 if (!SafeAddUint32(offset
, size
, &size
)) {
230 if (size
> static_cast<uint32
>(size_
)) {
238 // Scan the range for the max value and store
241 case GL_UNSIGNED_BYTE
:
242 max_v
= GetMaxValue
<uint8
>(shadow_
.get(), offset
, count
);
244 case GL_UNSIGNED_SHORT
:
245 // Check we are not accessing an odd byte for a 2 byte value.
246 if ((offset
& 1) != 0) {
249 max_v
= GetMaxValue
<uint16
>(shadow_
.get(), offset
, count
);
251 case GL_UNSIGNED_INT
:
252 // Check we are not accessing a non aligned address for a 4 byte value.
253 if ((offset
& 3) != 0) {
256 max_v
= GetMaxValue
<uint32
>(shadow_
.get(), offset
, count
);
259 NOTREACHED(); // should never get here by validation.
262 range_set_
.insert(std::make_pair(range
, max_v
));
267 bool BufferManager::GetClientId(GLuint service_id
, GLuint
* client_id
) const {
268 // This doesn't need to be fast. It's only used during slow queries.
269 for (BufferMap::const_iterator it
= buffers_
.begin();
270 it
!= buffers_
.end(); ++it
) {
271 if (it
->second
->service_id() == service_id
) {
272 *client_id
= it
->first
;
279 bool BufferManager::IsUsageClientSideArray(GLenum usage
) {
280 return usage
== GL_STREAM_DRAW
&& use_client_side_arrays_for_stream_buffers_
;
283 bool BufferManager::UseNonZeroSizeForClientSideArrayBuffer() {
284 return feature_info_
.get() &&
285 feature_info_
->workarounds()
286 .use_non_zero_size_for_client_side_stream_buffers
;
289 void BufferManager::SetInfo(Buffer
* buffer
, GLenum target
, GLsizeiptr size
,
290 GLenum usage
, const GLvoid
* data
) {
292 memory_type_tracker_
->TrackMemFree(buffer
->size());
293 const bool is_client_side_array
= IsUsageClientSideArray(usage
);
294 const bool support_fixed_attribs
=
295 gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2
;
296 // TODO(zmo): Don't shadow buffer data on ES3. crbug.com/491002.
297 const bool shadow
= target
== GL_ELEMENT_ARRAY_BUFFER
||
298 allow_buffers_on_multiple_targets_
||
299 (allow_fixed_attribs_
&& !support_fixed_attribs
) ||
300 is_client_side_array
;
301 buffer
->SetInfo(size
, usage
, shadow
, data
, is_client_side_array
);
302 memory_type_tracker_
->TrackMemAlloc(buffer
->size());
305 void BufferManager::ValidateAndDoBufferData(
306 ContextState
* context_state
, GLenum target
, GLsizeiptr size
,
307 const GLvoid
* data
, GLenum usage
) {
308 ErrorState
* error_state
= context_state
->GetErrorState();
309 if (!feature_info_
->validators()->buffer_target
.IsValid(target
)) {
310 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
311 error_state
, "glBufferData", target
, "target");
314 if (!feature_info_
->validators()->buffer_usage
.IsValid(usage
)) {
315 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
316 error_state
, "glBufferData", usage
, "usage");
320 ERRORSTATE_SET_GL_ERROR(
321 error_state
, GL_INVALID_VALUE
, "glBufferData", "size < 0");
325 Buffer
* buffer
= GetBufferInfoForTarget(context_state
, target
);
327 ERRORSTATE_SET_GL_ERROR(
328 error_state
, GL_INVALID_VALUE
, "glBufferData", "unknown buffer");
332 if (!memory_type_tracker_
->EnsureGPUMemoryAvailable(size
)) {
333 ERRORSTATE_SET_GL_ERROR(
334 error_state
, GL_OUT_OF_MEMORY
, "glBufferData", "out of memory");
338 DoBufferData(error_state
, buffer
, target
, size
, usage
, data
);
342 void BufferManager::DoBufferData(
343 ErrorState
* error_state
,
348 const GLvoid
* data
) {
349 // Clear the buffer to 0 if no initial data was passed in.
350 scoped_ptr
<int8
[]> zero
;
352 zero
.reset(new int8
[size
]);
353 memset(zero
.get(), 0, size
);
357 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state
, "glBufferData");
358 if (IsUsageClientSideArray(usage
)) {
359 GLsizei empty_size
= UseNonZeroSizeForClientSideArrayBuffer() ? 1 : 0;
360 glBufferData(target
, empty_size
, NULL
, usage
);
362 glBufferData(target
, size
, data
, usage
);
364 GLenum error
= ERRORSTATE_PEEK_GL_ERROR(error_state
, "glBufferData");
365 if (error
== GL_NO_ERROR
) {
366 SetInfo(buffer
, target
, size
, usage
, data
);
368 SetInfo(buffer
, target
, 0, usage
, NULL
);
372 void BufferManager::ValidateAndDoBufferSubData(
373 ContextState
* context_state
, GLenum target
, GLintptr offset
, GLsizeiptr size
,
374 const GLvoid
* data
) {
375 ErrorState
* error_state
= context_state
->GetErrorState();
376 Buffer
* buffer
= GetBufferInfoForTarget(context_state
, target
);
378 ERRORSTATE_SET_GL_ERROR(error_state
, GL_INVALID_VALUE
, "glBufferSubData",
383 DoBufferSubData(error_state
, buffer
, target
, offset
, size
, data
);
386 void BufferManager::DoBufferSubData(
387 ErrorState
* error_state
,
392 const GLvoid
* data
) {
393 if (!buffer
->SetRange(offset
, size
, data
)) {
394 ERRORSTATE_SET_GL_ERROR(
395 error_state
, GL_INVALID_VALUE
, "glBufferSubData", "out of range");
399 if (!buffer
->IsClientSideArray()) {
400 glBufferSubData(target
, offset
, size
, data
);
404 void BufferManager::ValidateAndDoGetBufferParameteri64v(
405 ContextState
* context_state
, GLenum target
, GLenum pname
, GLint64
* params
) {
406 Buffer
* buffer
= GetBufferInfoForTarget(context_state
, target
);
408 ERRORSTATE_SET_GL_ERROR(
409 context_state
->GetErrorState(), GL_INVALID_OPERATION
,
410 "glGetBufferParameteri64v", "no buffer bound for target");
415 *params
= buffer
->size();
417 case GL_BUFFER_MAP_LENGTH
:
419 const Buffer::MappedRange
* mapped_range
= buffer
->GetMappedRange();
420 *params
= mapped_range
? mapped_range
->size
: 0;
423 case GL_BUFFER_MAP_OFFSET
:
425 const Buffer::MappedRange
* mapped_range
= buffer
->GetMappedRange();
426 *params
= mapped_range
? mapped_range
->offset
: 0;
434 void BufferManager::ValidateAndDoGetBufferParameteriv(
435 ContextState
* context_state
, GLenum target
, GLenum pname
, GLint
* params
) {
436 Buffer
* buffer
= GetBufferInfoForTarget(context_state
, target
);
438 ERRORSTATE_SET_GL_ERROR(
439 context_state
->GetErrorState(), GL_INVALID_OPERATION
,
440 "glGetBufferParameteriv", "no buffer bound for target");
445 *params
= buffer
->size();
447 case GL_BUFFER_USAGE
:
448 *params
= buffer
->usage();
450 case GL_BUFFER_ACCESS_FLAGS
:
452 const Buffer::MappedRange
* mapped_range
= buffer
->GetMappedRange();
453 *params
= mapped_range
? mapped_range
->access
: 0;
456 case GL_BUFFER_MAPPED
:
457 *params
= buffer
->GetMappedRange() == nullptr ? false : true;
464 bool BufferManager::SetTarget(Buffer
* buffer
, GLenum target
) {
465 if (!allow_buffers_on_multiple_targets_
) {
466 // After being bound to ELEMENT_ARRAY_BUFFER target, a buffer cannot be
467 // bound to any other targets except for COPY_READ/WRITE_BUFFER target;
468 // After being bound to non ELEMENT_ARRAY_BUFFER target, a buffer cannot
469 // be bound to ELEMENT_ARRAY_BUFFER target.
471 // Note that we don't force the WebGL 2 rule that a buffer bound to
472 // TRANSFORM_FEEDBACK_BUFFER target should not be bound to any other
473 // targets, because that is not a security threat, so we only enforce it
474 // in the WebGL2RenderingContextBase.
475 switch (buffer
->initial_target()) {
476 case GL_ELEMENT_ARRAY_BUFFER
:
478 case GL_ARRAY_BUFFER
:
479 case GL_PIXEL_PACK_BUFFER
:
480 case GL_PIXEL_UNPACK_BUFFER
:
481 case GL_TRANSFORM_FEEDBACK_BUFFER
:
482 case GL_UNIFORM_BUFFER
:
488 case GL_ARRAY_BUFFER
:
489 case GL_COPY_READ_BUFFER
:
490 case GL_COPY_WRITE_BUFFER
:
491 case GL_PIXEL_PACK_BUFFER
:
492 case GL_PIXEL_UNPACK_BUFFER
:
493 case GL_TRANSFORM_FEEDBACK_BUFFER
:
494 case GL_UNIFORM_BUFFER
:
495 if (target
== GL_ELEMENT_ARRAY_BUFFER
) {
503 if (buffer
->initial_target() == 0)
504 buffer
->set_initial_target(target
);
508 // Since one BufferManager can be shared by multiple decoders, ContextState is
509 // passed in each time and not just passed in during initialization.
510 Buffer
* BufferManager::GetBufferInfoForTarget(
511 ContextState
* state
, GLenum target
) const {
513 case GL_ARRAY_BUFFER
:
514 return state
->bound_array_buffer
.get();
515 case GL_ELEMENT_ARRAY_BUFFER
:
516 return state
->vertex_attrib_manager
->element_array_buffer();
517 case GL_COPY_READ_BUFFER
:
518 return state
->bound_copy_read_buffer
.get();
519 case GL_COPY_WRITE_BUFFER
:
520 return state
->bound_copy_write_buffer
.get();
521 case GL_PIXEL_PACK_BUFFER
:
522 return state
->bound_pixel_pack_buffer
.get();
523 case GL_PIXEL_UNPACK_BUFFER
:
524 return state
->bound_pixel_unpack_buffer
.get();
525 case GL_TRANSFORM_FEEDBACK_BUFFER
:
526 return state
->bound_transform_feedback_buffer
.get();
527 case GL_UNIFORM_BUFFER
:
528 return state
->bound_uniform_buffer
.get();
535 bool BufferManager::OnMemoryDump(const base::trace_event::MemoryDumpArgs
& args
,
536 base::trace_event::ProcessMemoryDump
* pmd
) {
537 const int client_id
= memory_tracker_
->ClientId();
538 for (const auto& buffer_entry
: buffers_
) {
539 const auto& client_buffer_id
= buffer_entry
.first
;
540 const auto& buffer
= buffer_entry
.second
;
542 std::string dump_name
= base::StringPrintf("gl/client_%d/buffers/buffer_%d",
543 client_id
, client_buffer_id
);
544 base::trace_event::MemoryAllocatorDump
* dump
=
545 pmd
->CreateAllocatorDump(dump_name
);
546 dump
->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize
,
547 base::trace_event::MemoryAllocatorDump::kUnitsBytes
,
548 static_cast<uint64_t>(buffer
->size()));
550 auto guid
= gfx::GetGLBufferGUIDForTracing(
551 memory_tracker_
->ClientTracingId(), client_buffer_id
);
552 pmd
->CreateSharedGlobalAllocatorDump(guid
);
553 pmd
->AddOwnershipEdge(dump
->guid(), guid
);