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/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"
19 BufferManager::BufferManager(
20 MemoryTracker
* memory_tracker
,
21 FeatureInfo
* feature_info
)
23 new MemoryTypeTracker(memory_tracker
, MemoryTracker::kManaged
)),
24 feature_info_(feature_info
),
25 allow_buffers_on_multiple_targets_(false),
28 use_client_side_arrays_for_stream_buffers_(
29 feature_info
? feature_info
->workarounds(
30 ).use_client_side_arrays_for_stream_buffers
: 0) {
33 BufferManager::~BufferManager() {
34 DCHECK(buffers_
.empty());
35 CHECK_EQ(buffer_count_
, 0u);
38 void BufferManager::Destroy(bool have_context
) {
39 have_context_
= have_context
;
41 DCHECK_EQ(0u, memory_tracker_
->GetMemRepresented());
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
);
51 Buffer
* BufferManager::GetBuffer(
53 BufferMap::iterator it
= buffers_
.find(client_id
);
54 return it
!= buffers_
.end() ? it
->second
.get() : NULL
;
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();
66 void BufferManager::StartTracking(Buffer
* /* buffer */) {
70 void BufferManager::StopTracking(Buffer
* buffer
) {
71 memory_tracker_
->TrackMemFree(buffer
->size());
75 Buffer::Buffer(BufferManager
* manager
, GLuint service_id
)
80 is_client_side_array_(false),
81 service_id_(service_id
),
83 usage_(GL_STATIC_DRAW
) {
84 manager_
->StartTracking(this);
89 if (manager_
->have_context_
) {
90 GLuint id
= service_id();
91 glDeleteBuffersARB(1, &id
);
93 manager_
->StopTracking(this);
99 GLsizeiptr size
, GLenum usage
, bool shadow
, const GLvoid
* data
,
100 bool is_client_side_array
) {
102 is_client_side_array_
= is_client_side_array
;
104 if (size
!= size_
|| shadow
!= shadowed_
) {
108 shadow_
.reset(new int8
[size
]);
115 memcpy(shadow_
.get(), data
, size
);
117 memset(shadow_
.get(), 0, size
);
122 bool Buffer::CheckRange(
123 GLintptr offset
, GLsizeiptr size
) const {
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_
;
131 bool Buffer::SetRange(
132 GLintptr offset
, GLsizeiptr size
, const GLvoid
* data
) {
133 if (!CheckRange(offset
, size
)) {
137 memcpy(shadow_
.get() + offset
, data
, size
);
143 const void* Buffer::GetRange(
144 GLintptr offset
, GLsizeiptr size
) const {
148 if (!CheckRange(offset
, size
)) {
151 return shadow_
.get() + offset
;
154 void Buffer::ClearCache() {
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
;
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
;
182 if (!SafeMultiplyUint32(
183 count
, GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type
), &size
)) {
187 if (!SafeAddUint32(offset
, size
, &size
)) {
191 if (size
> static_cast<uint32
>(size_
)) {
199 // Scan the range for the max value and store
202 case GL_UNSIGNED_BYTE
:
203 max_v
= GetMaxValue
<uint8
>(shadow_
.get(), offset
, count
);
205 case GL_UNSIGNED_SHORT
:
206 // Check we are not accessing an odd byte for a 2 byte value.
207 if ((offset
& 1) != 0) {
210 max_v
= GetMaxValue
<uint16
>(shadow_
.get(), offset
, count
);
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) {
217 max_v
= GetMaxValue
<uint32
>(shadow_
.get(), offset
, count
);
220 NOTREACHED(); // should never get here by validation.
223 range_set_
.insert(std::make_pair(range
, max_v
));
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
;
240 bool BufferManager::IsUsageClientSideArray(GLenum usage
) {
241 return usage
== GL_STREAM_DRAW
&& use_client_side_arrays_for_stream_buffers_
;
244 bool BufferManager::UseNonZeroSizeForClientSideArrayBuffer() {
245 return feature_info_
.get() &&
246 feature_info_
->workarounds()
247 .use_non_zero_size_for_client_side_stream_buffers
;
250 void BufferManager::SetInfo(
251 Buffer
* buffer
, GLsizeiptr size
, GLenum usage
, const GLvoid
* data
) {
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());
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");
271 if (!feature_info_
->validators()->buffer_usage
.IsValid(usage
)) {
272 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
273 error_state
, "glBufferData", usage
, "usage");
277 ERRORSTATE_SET_GL_ERROR(
278 error_state
, GL_INVALID_VALUE
, "glBufferData", "size < 0");
282 Buffer
* buffer
= GetBufferInfoForTarget(context_state
, target
);
284 ERRORSTATE_SET_GL_ERROR(
285 error_state
, GL_INVALID_VALUE
, "glBufferData", "unknown buffer");
289 if (!memory_tracker_
->EnsureGPUMemoryAvailable(size
)) {
290 ERRORSTATE_SET_GL_ERROR(
291 error_state
, GL_OUT_OF_MEMORY
, "glBufferData", "out of memory");
295 DoBufferData(error_state
, buffer
, size
, usage
, data
);
299 void BufferManager::DoBufferData(
300 ErrorState
* error_state
,
304 const GLvoid
* data
) {
305 // Clear the buffer to 0 if no initial data was passed in.
306 scoped_ptr
<int8
[]> zero
;
308 zero
.reset(new int8
[size
]);
309 memset(zero
.get(), 0, size
);
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
);
318 glBufferData(buffer
->target(), size
, data
, usage
);
320 GLenum error
= ERRORSTATE_PEEK_GL_ERROR(error_state
, "glBufferData");
321 if (error
== GL_NO_ERROR
) {
322 SetInfo(buffer
, size
, usage
, data
);
324 SetInfo(buffer
, 0, usage
, NULL
);
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
);
334 ERRORSTATE_SET_GL_ERROR(error_state
, GL_INVALID_VALUE
, "glBufferSubData",
339 DoBufferSubData(error_state
, buffer
, offset
, size
, data
);
342 void BufferManager::DoBufferSubData(
343 ErrorState
* error_state
,
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");
354 if (!buffer
->IsClientSideArray()) {
355 glBufferSubData(buffer
->target(), offset
, size
, data
);
359 void BufferManager::ValidateAndDoGetBufferParameteriv(
360 ContextState
* context_state
, GLenum target
, GLenum pname
, GLint
* params
) {
361 Buffer
* buffer
= GetBufferInfoForTarget(context_state
, target
);
363 ERRORSTATE_SET_GL_ERROR(
364 context_state
->GetErrorState(), GL_INVALID_OPERATION
,
365 "glGetBufferParameteriv", "no buffer bound for target");
370 *params
= buffer
->size();
372 case GL_BUFFER_USAGE
:
373 *params
= buffer
->usage();
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_
) {
386 if (buffer
->target() == 0) {
387 buffer
->set_target(target
);
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();
400 return state
->vertex_attrib_manager
->element_array_buffer();