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 // A class to emulate GLES2 over command buffers.
7 #include "gpu/command_buffer/client/gles2_implementation.h"
9 #include <GLES2/gl2ext.h>
10 #include <GLES2/gl2extchromium.h>
18 #include "base/bind.h"
19 #include "gpu/command_buffer/client/buffer_tracker.h"
20 #include "gpu/command_buffer/client/gpu_control.h"
21 #include "gpu/command_buffer/client/gpu_memory_buffer_tracker.h"
22 #include "gpu/command_buffer/client/program_info_manager.h"
23 #include "gpu/command_buffer/client/query_tracker.h"
24 #include "gpu/command_buffer/client/transfer_buffer.h"
25 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
26 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
27 #include "gpu/command_buffer/common/trace_event.h"
28 #include "ui/gfx/gpu_memory_buffer.h"
30 #if defined(__native_client__) && !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
31 #define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS
34 #if defined(GPU_CLIENT_DEBUG)
35 #include "base/command_line.h"
36 #include "ui/gl/gl_switches.h"
42 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
43 static GLuint
ToGLuint(const void* ptr
) {
44 return static_cast<GLuint
>(reinterpret_cast<size_t>(ptr
));
47 #if !defined(_MSC_VER)
48 const size_t GLES2Implementation::kMaxSizeOfSimpleResult
;
49 const unsigned int GLES2Implementation::kStartingOffset
;
52 GLES2Implementation::GLStaticState::GLStaticState() {
55 GLES2Implementation::GLStaticState::~GLStaticState() {
58 GLES2Implementation::GLStaticState::IntState::IntState()
59 : max_combined_texture_image_units(0),
60 max_cube_map_texture_size(0),
61 max_fragment_uniform_vectors(0),
62 max_renderbuffer_size(0),
63 max_texture_image_units(0),
65 max_varying_vectors(0),
66 max_vertex_attribs(0),
67 max_vertex_texture_image_units(0),
68 max_vertex_uniform_vectors(0),
69 num_compressed_texture_formats(0),
70 num_shader_binary_formats(0),
71 bind_generates_resource_chromium(0) {}
73 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
74 GLES2Implementation
* gles2_implementation
)
75 : gles2_implementation_(gles2_implementation
) {
76 CHECK_EQ(0, gles2_implementation_
->use_count_
);
77 ++gles2_implementation_
->use_count_
;
80 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
81 --gles2_implementation_
->use_count_
;
82 CHECK_EQ(0, gles2_implementation_
->use_count_
);
85 GLES2Implementation::GLES2Implementation(
86 GLES2CmdHelper
* helper
,
87 ShareGroup
* share_group
,
88 TransferBufferInterface
* transfer_buffer
,
89 bool bind_generates_resource
,
90 bool lose_context_when_out_of_memory
,
91 GpuControl
* gpu_control
)
93 transfer_buffer_(transfer_buffer
),
94 angle_pack_reverse_row_order_status_(kUnknownExtensionStatus
),
95 chromium_framebuffer_multisample_(kUnknownExtensionStatus
),
98 unpack_flip_y_(false),
99 unpack_row_length_(0),
100 unpack_skip_rows_(0),
101 unpack_skip_pixels_(0),
102 pack_reverse_row_order_(false),
103 active_texture_unit_(0),
104 bound_framebuffer_(0),
105 bound_read_framebuffer_(0),
106 bound_renderbuffer_(0),
108 bound_array_buffer_id_(0),
109 bound_pixel_pack_transfer_buffer_id_(0),
110 bound_pixel_unpack_transfer_buffer_id_(0),
111 async_upload_token_(0),
112 async_upload_sync_(NULL
),
113 async_upload_sync_shm_id_(0),
114 async_upload_sync_shm_offset_(0),
117 lose_context_when_out_of_memory_(lose_context_when_out_of_memory
),
119 error_message_callback_(NULL
),
120 gpu_control_(gpu_control
),
121 capabilities_(gpu_control
->GetCapabilities()),
122 weak_ptr_factory_(this) {
124 DCHECK(transfer_buffer
);
127 std::stringstream ss
;
128 ss
<< std::hex
<< this;
129 this_in_hex_
= ss
.str();
131 GPU_CLIENT_LOG_CODE_BLOCK({
132 debug_
= CommandLine::ForCurrentProcess()->HasSwitch(
133 switches::kEnableGPUClientLogging
);
137 (share_group
? share_group
: new ShareGroup(bind_generates_resource
));
138 DCHECK(share_group_
->bind_generates_resource() == bind_generates_resource
);
140 memset(&reserved_ids_
, 0, sizeof(reserved_ids_
));
143 bool GLES2Implementation::Initialize(
144 unsigned int starting_transfer_buffer_size
,
145 unsigned int min_transfer_buffer_size
,
146 unsigned int max_transfer_buffer_size
,
147 unsigned int mapped_memory_limit
) {
148 TRACE_EVENT0("gpu", "GLES2Implementation::Initialize");
149 DCHECK_GE(starting_transfer_buffer_size
, min_transfer_buffer_size
);
150 DCHECK_LE(starting_transfer_buffer_size
, max_transfer_buffer_size
);
151 DCHECK_GE(min_transfer_buffer_size
, kStartingOffset
);
153 if (!transfer_buffer_
->Initialize(
154 starting_transfer_buffer_size
,
156 min_transfer_buffer_size
,
157 max_transfer_buffer_size
,
163 mapped_memory_
.reset(
164 new MappedMemoryManager(
166 base::Bind(&GLES2Implementation::PollAsyncUploads
,
167 // The mapped memory manager is owned by |this| here, and
168 // since its destroyed before before we destroy ourselves
169 // we don't need extra safety measures for this closure.
170 base::Unretained(this)),
171 mapped_memory_limit
));
173 unsigned chunk_size
= 2 * 1024 * 1024;
174 if (mapped_memory_limit
!= kNoLimit
) {
175 // Use smaller chunks if the client is very memory conscientious.
176 chunk_size
= std::min(mapped_memory_limit
/ 4, chunk_size
);
178 mapped_memory_
->set_chunk_size_multiple(chunk_size
);
180 if (!QueryAndCacheStaticState())
183 util_
.set_num_compressed_texture_formats(
184 static_state_
.int_state
.num_compressed_texture_formats
);
185 util_
.set_num_shader_binary_formats(
186 static_state_
.int_state
.num_shader_binary_formats
);
188 texture_units_
.reset(
190 static_state_
.int_state
.max_combined_texture_image_units
]);
192 query_tracker_
.reset(new QueryTracker(mapped_memory_
.get()));
193 buffer_tracker_
.reset(new BufferTracker(mapped_memory_
.get()));
194 gpu_memory_buffer_tracker_
.reset(new GpuMemoryBufferTracker(gpu_control_
));
196 query_id_allocator_
.reset(new IdAllocator());
197 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
198 GetIdHandler(id_namespaces::kBuffers
)->MakeIds(
199 this, kClientSideArrayId
, arraysize(reserved_ids_
), &reserved_ids_
[0]);
202 vertex_array_object_manager_
.reset(new VertexArrayObjectManager(
203 static_state_
.int_state
.max_vertex_attribs
,
207 // GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
208 // on Client & Service.
209 if (static_state_
.int_state
.bind_generates_resource_chromium
!=
210 (share_group_
->bind_generates_resource() ? 1 : 0)) {
211 SetGLError(GL_INVALID_OPERATION
,
213 "Service bind_generates_resource mismatch.");
220 bool GLES2Implementation::QueryAndCacheStaticState() {
221 TRACE_EVENT0("gpu", "GLES2Implementation::QueryAndCacheStaticState");
222 // Setup query for multiple GetIntegerv's
223 static const GLenum pnames
[] = {
224 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
,
225 GL_MAX_CUBE_MAP_TEXTURE_SIZE
,
226 GL_MAX_FRAGMENT_UNIFORM_VECTORS
,
227 GL_MAX_RENDERBUFFER_SIZE
,
228 GL_MAX_TEXTURE_IMAGE_UNITS
,
230 GL_MAX_VARYING_VECTORS
,
231 GL_MAX_VERTEX_ATTRIBS
,
232 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
,
233 GL_MAX_VERTEX_UNIFORM_VECTORS
,
234 GL_NUM_COMPRESSED_TEXTURE_FORMATS
,
235 GL_NUM_SHADER_BINARY_FORMATS
,
236 GL_BIND_GENERATES_RESOURCE_CHROMIUM
,
239 GetMultipleIntegervState
integerv_state(
240 pnames
, arraysize(pnames
),
241 &static_state_
.int_state
.max_combined_texture_image_units
,
242 sizeof(static_state_
.int_state
));
243 if (!GetMultipleIntegervSetup(&integerv_state
)) {
247 // Setup query for multiple GetShaderPrecisionFormat's
248 static const GLenum precision_params
[][2] = {
249 { GL_VERTEX_SHADER
, GL_LOW_INT
},
250 { GL_VERTEX_SHADER
, GL_MEDIUM_INT
},
251 { GL_VERTEX_SHADER
, GL_HIGH_INT
},
252 { GL_VERTEX_SHADER
, GL_LOW_FLOAT
},
253 { GL_VERTEX_SHADER
, GL_MEDIUM_FLOAT
},
254 { GL_VERTEX_SHADER
, GL_HIGH_FLOAT
},
255 { GL_FRAGMENT_SHADER
, GL_LOW_INT
},
256 { GL_FRAGMENT_SHADER
, GL_MEDIUM_INT
},
257 { GL_FRAGMENT_SHADER
, GL_HIGH_INT
},
258 { GL_FRAGMENT_SHADER
, GL_LOW_FLOAT
},
259 { GL_FRAGMENT_SHADER
, GL_MEDIUM_FLOAT
},
260 { GL_FRAGMENT_SHADER
, GL_HIGH_FLOAT
},
263 GetAllShaderPrecisionFormatsState
precision_state(
264 precision_params
, arraysize(precision_params
));
265 GetAllShaderPrecisionFormatsSetup(&precision_state
);
267 // Allocate and partition transfer buffer for all requests
268 void* buffer
= transfer_buffer_
->Alloc(
269 integerv_state
.transfer_buffer_size_needed
+
270 precision_state
.transfer_buffer_size_needed
);
272 SetGLError(GL_OUT_OF_MEMORY
, "QueryAndCacheStaticState",
273 "Transfer buffer allocation failed.");
276 integerv_state
.buffer
= buffer
;
277 precision_state
.results_buffer
=
278 static_cast<char*>(buffer
) + integerv_state
.transfer_buffer_size_needed
;
280 // Make all the requests and wait once for all the results.
281 GetMultipleIntegervRequest(&integerv_state
);
282 GetAllShaderPrecisionFormatsRequest(&precision_state
);
284 GetMultipleIntegervOnCompleted(&integerv_state
);
285 GetAllShaderPrecisionFormatsOnCompleted(&precision_state
);
287 // TODO(gman): We should be able to free without a token.
288 transfer_buffer_
->FreePendingToken(buffer
, helper_
->InsertToken());
294 GLES2Implementation::~GLES2Implementation() {
295 // Make sure the queries are finished otherwise we'll delete the
296 // shared memory (mapped_memory_) which will free the memory used
297 // by the queries. The GPU process when validating that memory is still
298 // shared will fail and abort (ie, it will stop running).
300 query_tracker_
.reset();
302 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
303 DeleteBuffers(arraysize(reserved_ids_
), &reserved_ids_
[0]);
306 // Release any per-context data in share group.
307 share_group_
->FreeContext(this);
309 buffer_tracker_
.reset();
311 FreeAllAsyncUploadBuffers();
313 if (async_upload_sync_
) {
314 mapped_memory_
->Free(async_upload_sync_
);
315 async_upload_sync_
= NULL
;
318 // Make sure the commands make it the service.
322 GLES2CmdHelper
* GLES2Implementation::helper() const {
326 IdHandlerInterface
* GLES2Implementation::GetIdHandler(int namespace_id
) const {
327 return share_group_
->GetIdHandler(namespace_id
);
330 IdAllocatorInterface
* GLES2Implementation::GetIdAllocator(
331 int namespace_id
) const {
332 if (namespace_id
== id_namespaces::kQueries
)
333 return query_id_allocator_
.get();
338 void* GLES2Implementation::GetResultBuffer() {
339 return transfer_buffer_
->GetResultBuffer();
342 int32
GLES2Implementation::GetResultShmId() {
343 return transfer_buffer_
->GetShmId();
346 uint32
GLES2Implementation::GetResultShmOffset() {
347 return transfer_buffer_
->GetResultOffset();
350 void GLES2Implementation::FreeUnusedSharedMemory() {
351 mapped_memory_
->FreeUnused();
354 void GLES2Implementation::FreeEverything() {
355 FreeAllAsyncUploadBuffers();
357 query_tracker_
->Shrink();
358 FreeUnusedSharedMemory();
359 transfer_buffer_
->Free();
360 helper_
->FreeRingBuffer();
363 void GLES2Implementation::RunIfContextNotLost(const base::Closure
& callback
) {
364 if (!helper_
->IsContextLost())
368 void GLES2Implementation::SignalSyncPoint(uint32 sync_point
,
369 const base::Closure
& callback
) {
370 gpu_control_
->SignalSyncPoint(
372 base::Bind(&GLES2Implementation::RunIfContextNotLost
,
373 weak_ptr_factory_
.GetWeakPtr(),
377 void GLES2Implementation::SignalQuery(uint32 query
,
378 const base::Closure
& callback
) {
379 // Flush previously entered commands to ensure ordering with any
380 // glBeginQueryEXT() calls that may have been put into the context.
381 ShallowFlushCHROMIUM();
382 gpu_control_
->SignalQuery(
384 base::Bind(&GLES2Implementation::RunIfContextNotLost
,
385 weak_ptr_factory_
.GetWeakPtr(),
389 void GLES2Implementation::SetSurfaceVisible(bool visible
) {
391 "gpu", "GLES2Implementation::SetSurfaceVisible", "visible", visible
);
392 // TODO(piman): This probably should be ShallowFlushCHROMIUM().
394 gpu_control_
->SetSurfaceVisible(visible
);
399 void GLES2Implementation::WaitForCmd() {
400 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
401 helper_
->CommandBufferHelper::Finish();
404 bool GLES2Implementation::IsExtensionAvailable(const char* ext
) {
405 const char* extensions
=
406 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS
));
410 int length
= strlen(ext
);
412 int n
= strcspn(extensions
, " ");
413 if (n
== length
&& 0 == strncmp(ext
, extensions
, length
)) {
416 if ('\0' == extensions
[n
]) {
423 bool GLES2Implementation::IsExtensionAvailableHelper(
424 const char* extension
, ExtensionStatus
* status
) {
426 case kAvailableExtensionStatus
:
428 case kUnavailableExtensionStatus
:
431 bool available
= IsExtensionAvailable(extension
);
432 *status
= available
? kAvailableExtensionStatus
:
433 kUnavailableExtensionStatus
;
439 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
440 return IsExtensionAvailableHelper(
441 "GL_ANGLE_pack_reverse_row_order",
442 &angle_pack_reverse_row_order_status_
);
445 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
446 return IsExtensionAvailableHelper(
447 "GL_CHROMIUM_framebuffer_multisample",
448 &chromium_framebuffer_multisample_
);
451 const std::string
& GLES2Implementation::GetLogPrefix() const {
452 const std::string
& prefix(debug_marker_manager_
.GetMarker());
453 return prefix
.empty() ? this_in_hex_
: prefix
;
456 GLenum
GLES2Implementation::GetError() {
457 GPU_CLIENT_SINGLE_THREAD_CHECK();
458 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
459 GLenum err
= GetGLError();
460 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err
));
464 GLenum
GLES2Implementation::GetClientSideGLError() {
465 if (error_bits_
== 0) {
469 GLenum error
= GL_NO_ERROR
;
470 for (uint32 mask
= 1; mask
!= 0; mask
= mask
<< 1) {
471 if ((error_bits_
& mask
) != 0) {
472 error
= GLES2Util::GLErrorBitToGLError(mask
);
476 error_bits_
&= ~GLES2Util::GLErrorToErrorBit(error
);
480 GLenum
GLES2Implementation::GetGLError() {
481 TRACE_EVENT0("gpu", "GLES2::GetGLError");
482 // Check the GL error first, then our wrapped error.
483 typedef cmds::GetError::Result Result
;
484 Result
* result
= GetResultAs
<Result
*>();
485 // If we couldn't allocate a result the context is lost.
489 *result
= GL_NO_ERROR
;
490 helper_
->GetError(GetResultShmId(), GetResultShmOffset());
492 GLenum error
= *result
;
493 if (error
== GL_NO_ERROR
) {
494 error
= GetClientSideGLError();
496 // There was an error, clear the corresponding wrapped error.
497 error_bits_
&= ~GLES2Util::GLErrorToErrorBit(error
);
502 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
503 void GLES2Implementation::FailGLError(GLenum error
) {
504 if (error
!= GL_NO_ERROR
) {
505 NOTREACHED() << "Error";
508 // NOTE: Calling GetGLError overwrites data in the result buffer.
509 void GLES2Implementation::CheckGLError() {
510 FailGLError(GetGLError());
512 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
514 void GLES2Implementation::SetGLError(
515 GLenum error
, const char* function_name
, const char* msg
) {
516 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
517 << GLES2Util::GetStringError(error
) << ": "
518 << function_name
<< ": " << msg
);
523 if (error_message_callback_
) {
524 std::string
temp(GLES2Util::GetStringError(error
) + " : " +
525 function_name
+ ": " + (msg
? msg
: ""));
526 error_message_callback_
->OnErrorMessage(temp
.c_str(), 0);
528 error_bits_
|= GLES2Util::GLErrorToErrorBit(error
);
530 if (error
== GL_OUT_OF_MEMORY
&& lose_context_when_out_of_memory_
) {
531 helper_
->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
532 GL_UNKNOWN_CONTEXT_RESET_ARB
);
536 void GLES2Implementation::SetGLErrorInvalidEnum(
537 const char* function_name
, GLenum value
, const char* label
) {
538 SetGLError(GL_INVALID_ENUM
, function_name
,
539 (std::string(label
) + " was " +
540 GLES2Util::GetStringEnum(value
)).c_str());
543 bool GLES2Implementation::GetBucketContents(uint32 bucket_id
,
544 std::vector
<int8
>* data
) {
545 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
547 const uint32 kStartSize
= 32 * 1024;
548 ScopedTransferBufferPtr
buffer(kStartSize
, helper_
, transfer_buffer_
);
549 if (!buffer
.valid()) {
552 typedef cmd::GetBucketStart::Result Result
;
553 Result
* result
= GetResultAs
<Result
*>();
558 helper_
->GetBucketStart(
559 bucket_id
, GetResultShmId(), GetResultShmOffset(),
560 buffer
.size(), buffer
.shm_id(), buffer
.offset());
562 uint32 size
= *result
;
567 if (!buffer
.valid()) {
569 if (!buffer
.valid()) {
572 helper_
->GetBucketData(
573 bucket_id
, offset
, buffer
.size(), buffer
.shm_id(), buffer
.offset());
576 uint32 size_to_copy
= std::min(size
, buffer
.size());
577 memcpy(&(*data
)[offset
], buffer
.address(), size_to_copy
);
578 offset
+= size_to_copy
;
579 size
-= size_to_copy
;
582 // Free the bucket. This is not required but it does free up the memory.
583 // and we don't have to wait for the result so from the client's perspective
585 helper_
->SetBucketSize(bucket_id
, 0);
590 void GLES2Implementation::SetBucketContents(
591 uint32 bucket_id
, const void* data
, size_t size
) {
593 helper_
->SetBucketSize(bucket_id
, size
);
597 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
598 if (!buffer
.valid()) {
601 memcpy(buffer
.address(), static_cast<const int8
*>(data
) + offset
,
603 helper_
->SetBucketData(
604 bucket_id
, offset
, buffer
.size(), buffer
.shm_id(), buffer
.offset());
605 offset
+= buffer
.size();
606 size
-= buffer
.size();
611 void GLES2Implementation::SetBucketAsCString(
612 uint32 bucket_id
, const char* str
) {
613 // NOTE: strings are passed NULL terminated. That means the empty
614 // string will have a size of 1 and no-string will have a size of 0
616 SetBucketContents(bucket_id
, str
, strlen(str
) + 1);
618 helper_
->SetBucketSize(bucket_id
, 0);
622 bool GLES2Implementation::GetBucketAsString(
623 uint32 bucket_id
, std::string
* str
) {
625 std::vector
<int8
> data
;
626 // NOTE: strings are passed NULL terminated. That means the empty
627 // string will have a size of 1 and no-string will have a size of 0
628 if (!GetBucketContents(bucket_id
, &data
)) {
634 str
->assign(&data
[0], &data
[0] + data
.size() - 1);
638 void GLES2Implementation::SetBucketAsString(
639 uint32 bucket_id
, const std::string
& str
) {
640 // NOTE: strings are passed NULL terminated. That means the empty
641 // string will have a size of 1 and no-string will have a size of 0
642 SetBucketContents(bucket_id
, str
.c_str(), str
.size() + 1);
645 void GLES2Implementation::Disable(GLenum cap
) {
646 GPU_CLIENT_SINGLE_THREAD_CHECK();
647 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
648 << GLES2Util::GetStringCapability(cap
) << ")");
649 bool changed
= false;
650 if (!state_
.SetCapabilityState(cap
, false, &changed
) || changed
) {
651 helper_
->Disable(cap
);
656 void GLES2Implementation::Enable(GLenum cap
) {
657 GPU_CLIENT_SINGLE_THREAD_CHECK();
658 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
659 << GLES2Util::GetStringCapability(cap
) << ")");
660 bool changed
= false;
661 if (!state_
.SetCapabilityState(cap
, true, &changed
) || changed
) {
662 helper_
->Enable(cap
);
667 GLboolean
GLES2Implementation::IsEnabled(GLenum cap
) {
668 GPU_CLIENT_SINGLE_THREAD_CHECK();
669 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
670 << GLES2Util::GetStringCapability(cap
) << ")");
672 if (!state_
.GetEnabled(cap
, &state
)) {
673 typedef cmds::IsEnabled::Result Result
;
674 Result
* result
= GetResultAs
<Result
*>();
679 helper_
->IsEnabled(cap
, GetResultShmId(), GetResultShmOffset());
681 state
= (*result
) != 0;
684 GPU_CLIENT_LOG("returned " << state
);
689 bool GLES2Implementation::GetHelper(GLenum pname
, GLint
* params
) {
691 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
:
692 *params
= static_state_
.int_state
.max_combined_texture_image_units
;
694 case GL_MAX_CUBE_MAP_TEXTURE_SIZE
:
695 *params
= static_state_
.int_state
.max_cube_map_texture_size
;
697 case GL_MAX_FRAGMENT_UNIFORM_VECTORS
:
698 *params
= static_state_
.int_state
.max_fragment_uniform_vectors
;
700 case GL_MAX_RENDERBUFFER_SIZE
:
701 *params
= static_state_
.int_state
.max_renderbuffer_size
;
703 case GL_MAX_TEXTURE_IMAGE_UNITS
:
704 *params
= static_state_
.int_state
.max_texture_image_units
;
706 case GL_MAX_TEXTURE_SIZE
:
707 *params
= static_state_
.int_state
.max_texture_size
;
709 case GL_MAX_VARYING_VECTORS
:
710 *params
= static_state_
.int_state
.max_varying_vectors
;
712 case GL_MAX_VERTEX_ATTRIBS
:
713 *params
= static_state_
.int_state
.max_vertex_attribs
;
715 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
:
716 *params
= static_state_
.int_state
.max_vertex_texture_image_units
;
718 case GL_MAX_VERTEX_UNIFORM_VECTORS
:
719 *params
= static_state_
.int_state
.max_vertex_uniform_vectors
;
721 case GL_NUM_COMPRESSED_TEXTURE_FORMATS
:
722 *params
= static_state_
.int_state
.num_compressed_texture_formats
;
724 case GL_NUM_SHADER_BINARY_FORMATS
:
725 *params
= static_state_
.int_state
.num_shader_binary_formats
;
727 case GL_ARRAY_BUFFER_BINDING
:
728 if (share_group_
->bind_generates_resource()) {
729 *params
= bound_array_buffer_id_
;
733 case GL_ELEMENT_ARRAY_BUFFER_BINDING
:
734 if (share_group_
->bind_generates_resource()) {
736 vertex_array_object_manager_
->bound_element_array_buffer();
740 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM
:
741 *params
= bound_pixel_pack_transfer_buffer_id_
;
743 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM
:
744 *params
= bound_pixel_unpack_transfer_buffer_id_
;
746 case GL_ACTIVE_TEXTURE
:
747 *params
= active_texture_unit_
+ GL_TEXTURE0
;
749 case GL_TEXTURE_BINDING_2D
:
750 if (share_group_
->bind_generates_resource()) {
751 *params
= texture_units_
[active_texture_unit_
].bound_texture_2d
;
755 case GL_TEXTURE_BINDING_CUBE_MAP
:
756 if (share_group_
->bind_generates_resource()) {
757 *params
= texture_units_
[active_texture_unit_
].bound_texture_cube_map
;
761 case GL_TEXTURE_BINDING_EXTERNAL_OES
:
762 if (share_group_
->bind_generates_resource()) {
764 texture_units_
[active_texture_unit_
].bound_texture_external_oes
;
768 case GL_FRAMEBUFFER_BINDING
:
769 if (share_group_
->bind_generates_resource()) {
770 *params
= bound_framebuffer_
;
774 case GL_READ_FRAMEBUFFER_BINDING
:
775 if (IsChromiumFramebufferMultisampleAvailable() &&
776 share_group_
->bind_generates_resource()) {
777 *params
= bound_read_framebuffer_
;
781 case GL_RENDERBUFFER_BINDING
:
782 if (share_group_
->bind_generates_resource()) {
783 *params
= bound_renderbuffer_
;
792 bool GLES2Implementation::GetBooleanvHelper(GLenum pname
, GLboolean
* params
) {
793 // TODO(gman): Make this handle pnames that return more than 1 value.
795 if (!GetHelper(pname
, &value
)) {
798 *params
= static_cast<GLboolean
>(value
);
802 bool GLES2Implementation::GetFloatvHelper(GLenum pname
, GLfloat
* params
) {
803 // TODO(gman): Make this handle pnames that return more than 1 value.
805 if (!GetHelper(pname
, &value
)) {
808 *params
= static_cast<GLfloat
>(value
);
812 bool GLES2Implementation::GetIntegervHelper(GLenum pname
, GLint
* params
) {
813 return GetHelper(pname
, params
);
816 GLuint
GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
817 GLuint buffer_id
, GLsizei count
, GLenum type
, GLuint offset
) {
818 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result
;
819 Result
* result
= GetResultAs
<Result
*>();
824 helper_
->GetMaxValueInBufferCHROMIUM(
825 buffer_id
, count
, type
, offset
, GetResultShmId(), GetResultShmOffset());
830 GLuint
GLES2Implementation::GetMaxValueInBufferCHROMIUM(
831 GLuint buffer_id
, GLsizei count
, GLenum type
, GLuint offset
) {
832 GPU_CLIENT_SINGLE_THREAD_CHECK();
833 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
834 << buffer_id
<< ", " << count
<< ", "
835 << GLES2Util::GetStringGetMaxIndexType(type
)
836 << ", " << offset
<< ")");
837 GLuint result
= GetMaxValueInBufferCHROMIUMHelper(
838 buffer_id
, count
, type
, offset
);
839 GPU_CLIENT_LOG("returned " << result
);
844 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore
) {
846 RestoreArrayBuffer(restore
);
847 // Restore the element array binding.
848 // We only need to restore it if it wasn't a client side array.
849 if (vertex_array_object_manager_
->bound_element_array_buffer() == 0) {
850 helper_
->BindBuffer(GL_ELEMENT_ARRAY_BUFFER
, 0);
855 void GLES2Implementation::RestoreArrayBuffer(bool restore
) {
857 // Restore the user's current binding.
858 helper_
->BindBuffer(GL_ARRAY_BUFFER
, bound_array_buffer_id_
);
862 void GLES2Implementation::DrawElements(
863 GLenum mode
, GLsizei count
, GLenum type
, const void* indices
) {
864 GPU_CLIENT_SINGLE_THREAD_CHECK();
865 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
866 << GLES2Util::GetStringDrawMode(mode
) << ", "
868 << GLES2Util::GetStringIndexType(type
) << ", "
869 << static_cast<const void*>(indices
) << ")");
871 SetGLError(GL_INVALID_VALUE
, "glDrawElements", "count less than 0.");
877 if (vertex_array_object_manager_
->bound_element_array_buffer() != 0 &&
878 !ValidateOffset("glDrawElements", reinterpret_cast<GLintptr
>(indices
))) {
882 bool simulated
= false;
883 if (!vertex_array_object_manager_
->SetupSimulatedIndexAndClientSideBuffers(
884 "glDrawElements", this, helper_
, count
, type
, 0, indices
,
885 &offset
, &simulated
)) {
888 helper_
->DrawElements(mode
, count
, type
, offset
);
889 RestoreElementAndArrayBuffers(simulated
);
893 void GLES2Implementation::Flush() {
894 GPU_CLIENT_SINGLE_THREAD_CHECK();
895 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
896 // Insert the cmd to call glFlush
898 // Flush our command buffer
899 // (tell the service to execute up to the flush cmd.)
900 helper_
->CommandBufferHelper::Flush();
903 void GLES2Implementation::ShallowFlushCHROMIUM() {
904 GPU_CLIENT_SINGLE_THREAD_CHECK();
905 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
906 // Flush our command buffer
907 // (tell the service to execute up to the flush cmd.)
908 helper_
->CommandBufferHelper::Flush();
909 // TODO(piman): Add the FreeEverything() logic here.
912 void GLES2Implementation::Finish() {
913 GPU_CLIENT_SINGLE_THREAD_CHECK();
917 void GLES2Implementation::ShallowFinishCHROMIUM() {
918 GPU_CLIENT_SINGLE_THREAD_CHECK();
919 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
920 // Flush our command buffer (tell the service to execute up to the flush cmd
921 // and don't return until it completes).
922 helper_
->CommandBufferHelper::Finish();
925 void GLES2Implementation::FinishHelper() {
926 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
927 TRACE_EVENT0("gpu", "GLES2::Finish");
928 // Insert the cmd to call glFinish
930 // Finish our command buffer
931 // (tell the service to execute up to the Finish cmd and wait for it to
933 helper_
->CommandBufferHelper::Finish();
936 void GLES2Implementation::SwapBuffers() {
937 GPU_CLIENT_SINGLE_THREAD_CHECK();
938 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
939 // TODO(piman): Strictly speaking we'd want to insert the token after the
940 // swap, but the state update with the updated token might not have happened
941 // by the time the SwapBuffer callback gets called, forcing us to synchronize
942 // with the GPU process more than needed. So instead, make it happen before.
943 // All it means is that we could be slightly looser on the kMaxSwapBuffers
944 // semantics if the client doesn't use the callback mechanism, and by chance
945 // the scheduler yields between the InsertToken and the SwapBuffers.
946 swap_buffers_tokens_
.push(helper_
->InsertToken());
947 helper_
->SwapBuffers();
948 helper_
->CommandBufferHelper::Flush();
949 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
950 // compensate for TODO above.
951 if (swap_buffers_tokens_
.size() > kMaxSwapBuffers
+ 1) {
952 helper_
->WaitForToken(swap_buffers_tokens_
.front());
953 swap_buffers_tokens_
.pop();
957 void GLES2Implementation::GenSharedIdsCHROMIUM(
958 GLuint namespace_id
, GLuint id_offset
, GLsizei n
, GLuint
* ids
) {
959 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenSharedIdsCHROMIUM("
960 << namespace_id
<< ", " << id_offset
<< ", " << n
<< ", " <<
961 static_cast<void*>(ids
) << ")");
962 TRACE_EVENT0("gpu", "GLES2::GenSharedIdsCHROMIUM");
966 ScopedTransferBufferArray
<GLint
> id_buffer(num
, helper_
, transfer_buffer_
);
967 if (!id_buffer
.valid()) {
970 helper_
->GenSharedIdsCHROMIUM(
971 namespace_id
, id_offset
, id_buffer
.num_elements(),
972 id_buffer
.shm_id(), id_buffer
.offset());
974 memcpy(dst
, id_buffer
.address(), sizeof(*dst
) * id_buffer
.num_elements());
975 num
-= id_buffer
.num_elements();
976 dst
+= id_buffer
.num_elements();
978 GPU_CLIENT_LOG_CODE_BLOCK({
979 for (GLsizei i
= 0; i
< n
; ++i
) {
980 GPU_CLIENT_LOG(" " << i
<< ": " << namespace_id
<< ", " << ids
[i
]);
985 void GLES2Implementation::DeleteSharedIdsCHROMIUM(
986 GLuint namespace_id
, GLsizei n
, const GLuint
* ids
) {
987 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteSharedIdsCHROMIUM("
988 << namespace_id
<< ", " << n
<< ", "
989 << static_cast<const void*>(ids
) << ")");
990 GPU_CLIENT_LOG_CODE_BLOCK({
991 for (GLsizei i
= 0; i
< n
; ++i
) {
992 GPU_CLIENT_LOG(" " << i
<< ": " << namespace_id
<< ", " << ids
[i
]);
995 TRACE_EVENT0("gpu", "GLES2::DeleteSharedIdsCHROMIUM");
997 ScopedTransferBufferArray
<GLint
> id_buffer(n
, helper_
, transfer_buffer_
);
998 if (!id_buffer
.valid()) {
1001 memcpy(id_buffer
.address(), ids
, sizeof(*ids
) * id_buffer
.num_elements());
1002 helper_
->DeleteSharedIdsCHROMIUM(
1003 namespace_id
, id_buffer
.num_elements(),
1004 id_buffer
.shm_id(), id_buffer
.offset());
1006 n
-= id_buffer
.num_elements();
1007 ids
+= id_buffer
.num_elements();
1011 void GLES2Implementation::RegisterSharedIdsCHROMIUM(
1012 GLuint namespace_id
, GLsizei n
, const GLuint
* ids
) {
1013 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRegisterSharedIdsCHROMIUM("
1014 << namespace_id
<< ", " << n
<< ", "
1015 << static_cast<const void*>(ids
) << ")");
1016 GPU_CLIENT_LOG_CODE_BLOCK({
1017 for (GLsizei i
= 0; i
< n
; ++i
) {
1018 GPU_CLIENT_LOG(" " << i
<< ": " << namespace_id
<< ", " << ids
[i
]);
1021 TRACE_EVENT0("gpu", "GLES2::RegisterSharedIdsCHROMIUM");
1023 ScopedTransferBufferArray
<GLint
> id_buffer(n
, helper_
, transfer_buffer_
);
1024 if (!id_buffer
.valid()) {
1027 memcpy(id_buffer
.address(), ids
, sizeof(*ids
) * id_buffer
.num_elements());
1028 helper_
->RegisterSharedIdsCHROMIUM(
1029 namespace_id
, id_buffer
.num_elements(),
1030 id_buffer
.shm_id(), id_buffer
.offset());
1032 n
-= id_buffer
.num_elements();
1033 ids
+= id_buffer
.num_elements();
1037 void GLES2Implementation::BindAttribLocation(
1038 GLuint program
, GLuint index
, const char* name
) {
1039 GPU_CLIENT_SINGLE_THREAD_CHECK();
1040 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
1041 << program
<< ", " << index
<< ", " << name
<< ")");
1042 SetBucketAsString(kResultBucketId
, name
);
1043 helper_
->BindAttribLocationBucket(program
, index
, kResultBucketId
);
1044 helper_
->SetBucketSize(kResultBucketId
, 0);
1048 void GLES2Implementation::BindUniformLocationCHROMIUM(
1049 GLuint program
, GLint location
, const char* name
) {
1050 GPU_CLIENT_SINGLE_THREAD_CHECK();
1051 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1052 << program
<< ", " << location
<< ", " << name
<< ")");
1053 SetBucketAsString(kResultBucketId
, name
);
1054 helper_
->BindUniformLocationCHROMIUMBucket(
1055 program
, location
, kResultBucketId
);
1056 helper_
->SetBucketSize(kResultBucketId
, 0);
1060 void GLES2Implementation::GetVertexAttribPointerv(
1061 GLuint index
, GLenum pname
, void** ptr
) {
1062 GPU_CLIENT_SINGLE_THREAD_CHECK();
1063 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1064 << index
<< ", " << GLES2Util::GetStringVertexPointer(pname
) << ", "
1065 << static_cast<void*>(ptr
) << ")");
1066 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results
= 1);
1067 if (!vertex_array_object_manager_
->GetAttribPointer(index
, pname
, ptr
)) {
1068 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1069 typedef cmds::GetVertexAttribPointerv::Result Result
;
1070 Result
* result
= GetResultAs
<Result
*>();
1074 result
->SetNumResults(0);
1075 helper_
->GetVertexAttribPointerv(
1076 index
, pname
, GetResultShmId(), GetResultShmOffset());
1078 result
->CopyResult(ptr
);
1079 GPU_CLIENT_LOG_CODE_BLOCK(num_results
= result
->GetNumResults());
1081 GPU_CLIENT_LOG_CODE_BLOCK({
1082 for (int32 i
= 0; i
< num_results
; ++i
) {
1083 GPU_CLIENT_LOG(" " << i
<< ": " << ptr
[i
]);
1089 bool GLES2Implementation::DeleteProgramHelper(GLuint program
) {
1090 if (!GetIdHandler(id_namespaces::kProgramsAndShaders
)->FreeIds(
1091 this, 1, &program
, &GLES2Implementation::DeleteProgramStub
)) {
1094 "glDeleteProgram", "id not created by this context.");
1097 if (program
== current_program_
) {
1098 current_program_
= 0;
1103 void GLES2Implementation::DeleteProgramStub(
1104 GLsizei n
, const GLuint
* programs
) {
1106 share_group_
->program_info_manager()->DeleteInfo(programs
[0]);
1107 helper_
->DeleteProgram(programs
[0]);
1110 bool GLES2Implementation::DeleteShaderHelper(GLuint shader
) {
1111 if (!GetIdHandler(id_namespaces::kProgramsAndShaders
)->FreeIds(
1112 this, 1, &shader
, &GLES2Implementation::DeleteShaderStub
)) {
1115 "glDeleteShader", "id not created by this context.");
1121 void GLES2Implementation::DeleteShaderStub(
1122 GLsizei n
, const GLuint
* shaders
) {
1124 share_group_
->program_info_manager()->DeleteInfo(shaders
[0]);
1125 helper_
->DeleteShader(shaders
[0]);
1129 GLint
GLES2Implementation::GetAttribLocationHelper(
1130 GLuint program
, const char* name
) {
1131 typedef cmds::GetAttribLocation::Result Result
;
1132 Result
* result
= GetResultAs
<Result
*>();
1137 SetBucketAsCString(kResultBucketId
, name
);
1138 helper_
->GetAttribLocation(
1139 program
, kResultBucketId
, GetResultShmId(), GetResultShmOffset());
1141 helper_
->SetBucketSize(kResultBucketId
, 0);
1145 GLint
GLES2Implementation::GetAttribLocation(
1146 GLuint program
, const char* name
) {
1147 GPU_CLIENT_SINGLE_THREAD_CHECK();
1148 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1149 << ", " << name
<< ")");
1150 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1151 GLint loc
= share_group_
->program_info_manager()->GetAttribLocation(
1152 this, program
, name
);
1153 GPU_CLIENT_LOG("returned " << loc
);
1158 GLint
GLES2Implementation::GetUniformLocationHelper(
1159 GLuint program
, const char* name
) {
1160 typedef cmds::GetUniformLocation::Result Result
;
1161 Result
* result
= GetResultAs
<Result
*>();
1166 SetBucketAsCString(kResultBucketId
, name
);
1167 helper_
->GetUniformLocation(program
, kResultBucketId
,
1168 GetResultShmId(), GetResultShmOffset());
1170 helper_
->SetBucketSize(kResultBucketId
, 0);
1174 GLint
GLES2Implementation::GetUniformLocation(
1175 GLuint program
, const char* name
) {
1176 GPU_CLIENT_SINGLE_THREAD_CHECK();
1177 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1178 << ", " << name
<< ")");
1179 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1180 GLint loc
= share_group_
->program_info_manager()->GetUniformLocation(
1181 this, program
, name
);
1182 GPU_CLIENT_LOG("returned " << loc
);
1187 bool GLES2Implementation::GetProgramivHelper(
1188 GLuint program
, GLenum pname
, GLint
* params
) {
1189 bool got_value
= share_group_
->program_info_manager()->GetProgramiv(
1190 this, program
, pname
, params
);
1191 GPU_CLIENT_LOG_CODE_BLOCK({
1193 GPU_CLIENT_LOG(" 0: " << *params
);
1199 void GLES2Implementation::LinkProgram(GLuint program
) {
1200 GPU_CLIENT_SINGLE_THREAD_CHECK();
1201 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program
<< ")");
1202 helper_
->LinkProgram(program
);
1203 share_group_
->program_info_manager()->CreateInfo(program
);
1207 void GLES2Implementation::ShaderBinary(
1208 GLsizei n
, const GLuint
* shaders
, GLenum binaryformat
, const void* binary
,
1210 GPU_CLIENT_SINGLE_THREAD_CHECK();
1211 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n
<< ", "
1212 << static_cast<const void*>(shaders
) << ", "
1213 << GLES2Util::GetStringEnum(binaryformat
) << ", "
1214 << static_cast<const void*>(binary
) << ", "
1217 SetGLError(GL_INVALID_VALUE
, "glShaderBinary", "n < 0.");
1221 SetGLError(GL_INVALID_VALUE
, "glShaderBinary", "length < 0.");
1224 // TODO(gman): ShaderBinary should use buckets.
1225 unsigned int shader_id_size
= n
* sizeof(*shaders
);
1226 ScopedTransferBufferArray
<GLint
> buffer(
1227 shader_id_size
+ length
, helper_
, transfer_buffer_
);
1228 if (!buffer
.valid() || buffer
.num_elements() != shader_id_size
+ length
) {
1229 SetGLError(GL_OUT_OF_MEMORY
, "glShaderBinary", "out of memory.");
1232 void* shader_ids
= buffer
.elements();
1233 void* shader_data
= buffer
.elements() + shader_id_size
;
1234 memcpy(shader_ids
, shaders
, shader_id_size
);
1235 memcpy(shader_data
, binary
, length
);
1236 helper_
->ShaderBinary(
1242 buffer
.offset() + shader_id_size
,
1247 void GLES2Implementation::PixelStorei(GLenum pname
, GLint param
) {
1248 GPU_CLIENT_SINGLE_THREAD_CHECK();
1249 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1250 << GLES2Util::GetStringPixelStore(pname
) << ", "
1253 case GL_PACK_ALIGNMENT
:
1254 pack_alignment_
= param
;
1256 case GL_UNPACK_ALIGNMENT
:
1257 unpack_alignment_
= param
;
1259 case GL_UNPACK_ROW_LENGTH_EXT
:
1260 unpack_row_length_
= param
;
1262 case GL_UNPACK_SKIP_ROWS_EXT
:
1263 unpack_skip_rows_
= param
;
1265 case GL_UNPACK_SKIP_PIXELS_EXT
:
1266 unpack_skip_pixels_
= param
;
1268 case GL_UNPACK_FLIP_Y_CHROMIUM
:
1269 unpack_flip_y_
= (param
!= 0);
1271 case GL_PACK_REVERSE_ROW_ORDER_ANGLE
:
1272 pack_reverse_row_order_
=
1273 IsAnglePackReverseRowOrderAvailable() ? (param
!= 0) : false;
1278 helper_
->PixelStorei(pname
, param
);
1282 void GLES2Implementation::VertexAttribPointer(
1283 GLuint index
, GLint size
, GLenum type
, GLboolean normalized
, GLsizei stride
,
1285 GPU_CLIENT_SINGLE_THREAD_CHECK();
1286 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1289 << GLES2Util::GetStringVertexAttribType(type
) << ", "
1290 << GLES2Util::GetStringBool(normalized
) << ", "
1292 << static_cast<const void*>(ptr
) << ")");
1293 // Record the info on the client side.
1294 if (!vertex_array_object_manager_
->SetAttribPointer(
1295 bound_array_buffer_id_
, index
, size
, type
, normalized
, stride
, ptr
)) {
1296 SetGLError(GL_INVALID_OPERATION
, "glVertexAttribPointer",
1297 "client side arrays are not allowed in vertex array objects.");
1300 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1301 if (bound_array_buffer_id_
!= 0) {
1302 // Only report NON client side buffers to the service.
1303 if (!ValidateOffset("glVertexAttribPointer",
1304 reinterpret_cast<GLintptr
>(ptr
))) {
1307 helper_
->VertexAttribPointer(index
, size
, type
, normalized
, stride
,
1310 #else // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1311 if (!ValidateOffset("glVertexAttribPointer",
1312 reinterpret_cast<GLintptr
>(ptr
))) {
1315 helper_
->VertexAttribPointer(index
, size
, type
, normalized
, stride
,
1317 #endif // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1321 void GLES2Implementation::VertexAttribDivisorANGLE(
1322 GLuint index
, GLuint divisor
) {
1323 GPU_CLIENT_SINGLE_THREAD_CHECK();
1324 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1326 << divisor
<< ") ");
1327 // Record the info on the client side.
1328 vertex_array_object_manager_
->SetAttribDivisor(index
, divisor
);
1329 helper_
->VertexAttribDivisorANGLE(index
, divisor
);
1333 void GLES2Implementation::ShaderSource(
1336 const GLchar
* const* source
,
1337 const GLint
* length
) {
1338 GPU_CLIENT_SINGLE_THREAD_CHECK();
1339 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderSource("
1340 << shader
<< ", " << count
<< ", "
1341 << static_cast<const void*>(source
) << ", "
1342 << static_cast<const void*>(length
) << ")");
1343 GPU_CLIENT_LOG_CODE_BLOCK({
1344 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1346 if (length
&& length
[ii
] >= 0) {
1347 std::string
str(source
[ii
], length
[ii
]);
1348 GPU_CLIENT_LOG(" " << ii
<< ": ---\n" << str
<< "\n---");
1350 GPU_CLIENT_LOG(" " << ii
<< ": ---\n" << source
[ii
] << "\n---");
1353 GPU_CLIENT_LOG(" " << ii
<< ": NULL");
1358 SetGLError(GL_INVALID_VALUE
, "glShaderSource", "count < 0");
1362 SetGLError(GL_INVALID_VALUE
, "glShaderSource", "shader == 0");
1366 // Compute the total size.
1367 uint32 total_size
= 1;
1368 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1370 total_size
+= (length
&& length
[ii
] >= 0) ?
1371 static_cast<size_t>(length
[ii
]) : strlen(source
[ii
]);
1375 // Concatenate all the strings in to a bucket on the service.
1376 helper_
->SetBucketSize(kResultBucketId
, total_size
);
1378 for (GLsizei ii
= 0; ii
<= count
; ++ii
) {
1379 const char* src
= ii
< count
? source
[ii
] : "";
1381 uint32 size
= ii
< count
?
1382 (length
? static_cast<size_t>(length
[ii
]) : strlen(src
)) : 1;
1384 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1385 if (!buffer
.valid()) {
1388 memcpy(buffer
.address(), src
, buffer
.size());
1389 helper_
->SetBucketData(kResultBucketId
, offset
, buffer
.size(),
1390 buffer
.shm_id(), buffer
.offset());
1391 offset
+= buffer
.size();
1392 src
+= buffer
.size();
1393 size
-= buffer
.size();
1398 DCHECK_EQ(total_size
, offset
);
1400 helper_
->ShaderSourceBucket(shader
, kResultBucketId
);
1401 helper_
->SetBucketSize(kResultBucketId
, 0);
1405 void GLES2Implementation::BufferDataHelper(
1406 GLenum target
, GLsizeiptr size
, const void* data
, GLenum usage
) {
1407 if (!ValidateSize("glBufferData", size
))
1411 if (GetBoundPixelTransferBuffer(target
, "glBufferData", &buffer_id
)) {
1416 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
1418 RemoveTransferBuffer(buffer
);
1420 // Create new buffer.
1421 buffer
= buffer_tracker_
->CreateBuffer(buffer_id
, size
);
1423 if (buffer
->address() && data
)
1424 memcpy(buffer
->address(), data
, size
);
1432 // If there is no data just send BufferData
1434 helper_
->BufferData(target
, size
, 0, 0, usage
);
1438 // See if we can send all at once.
1439 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1440 if (!buffer
.valid()) {
1444 if (buffer
.size() >= static_cast<unsigned int>(size
)) {
1445 memcpy(buffer
.address(), data
, size
);
1446 helper_
->BufferData(
1455 // Make the buffer with BufferData then send via BufferSubData
1456 helper_
->BufferData(target
, size
, 0, 0, usage
);
1457 BufferSubDataHelperImpl(target
, 0, size
, data
, &buffer
);
1461 void GLES2Implementation::BufferData(
1462 GLenum target
, GLsizeiptr size
, const void* data
, GLenum usage
) {
1463 GPU_CLIENT_SINGLE_THREAD_CHECK();
1464 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1465 << GLES2Util::GetStringBufferTarget(target
) << ", "
1467 << static_cast<const void*>(data
) << ", "
1468 << GLES2Util::GetStringBufferUsage(usage
) << ")");
1469 BufferDataHelper(target
, size
, data
, usage
);
1473 void GLES2Implementation::BufferSubDataHelper(
1474 GLenum target
, GLintptr offset
, GLsizeiptr size
, const void* data
) {
1479 if (!ValidateSize("glBufferSubData", size
) ||
1480 !ValidateOffset("glBufferSubData", offset
)) {
1485 if (GetBoundPixelTransferBuffer(target
, "glBufferSubData", &buffer_id
)) {
1489 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
1491 SetGLError(GL_INVALID_VALUE
, "glBufferSubData", "unknown buffer");
1496 int32 buffer_size
= buffer
->size();
1497 if (!SafeAddInt32(offset
, size
, &end
) || end
> buffer_size
) {
1498 SetGLError(GL_INVALID_VALUE
, "glBufferSubData", "out of range");
1502 if (buffer
->address() && data
)
1503 memcpy(static_cast<uint8
*>(buffer
->address()) + offset
, data
, size
);
1507 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1508 BufferSubDataHelperImpl(target
, offset
, size
, data
, &buffer
);
1511 void GLES2Implementation::BufferSubDataHelperImpl(
1512 GLenum target
, GLintptr offset
, GLsizeiptr size
, const void* data
,
1513 ScopedTransferBufferPtr
* buffer
) {
1517 const int8
* source
= static_cast<const int8
*>(data
);
1519 if (!buffer
->valid() || buffer
->size() == 0) {
1520 buffer
->Reset(size
);
1521 if (!buffer
->valid()) {
1525 memcpy(buffer
->address(), source
, buffer
->size());
1526 helper_
->BufferSubData(
1527 target
, offset
, buffer
->size(), buffer
->shm_id(), buffer
->offset());
1528 offset
+= buffer
->size();
1529 source
+= buffer
->size();
1530 size
-= buffer
->size();
1535 void GLES2Implementation::BufferSubData(
1536 GLenum target
, GLintptr offset
, GLsizeiptr size
, const void* data
) {
1537 GPU_CLIENT_SINGLE_THREAD_CHECK();
1538 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1539 << GLES2Util::GetStringBufferTarget(target
) << ", "
1540 << offset
<< ", " << size
<< ", "
1541 << static_cast<const void*>(data
) << ")");
1542 BufferSubDataHelper(target
, offset
, size
, data
);
1546 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer
* buffer
) {
1547 int32 token
= buffer
->last_usage_token();
1548 uint32 async_token
= buffer
->last_async_upload_token();
1551 if (HasAsyncUploadTokenPassed(async_token
)) {
1552 buffer_tracker_
->Free(buffer
);
1554 detached_async_upload_memory_
.push_back(
1555 std::make_pair(buffer
->address(), async_token
));
1556 buffer_tracker_
->Unmanage(buffer
);
1559 if (helper_
->HasTokenPassed(token
))
1560 buffer_tracker_
->Free(buffer
);
1562 buffer_tracker_
->FreePendingToken(buffer
, token
);
1564 buffer_tracker_
->Free(buffer
);
1567 buffer_tracker_
->RemoveBuffer(buffer
->id());
1570 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1572 const char* function_name
,
1573 GLuint
* buffer_id
) {
1577 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
:
1578 *buffer_id
= bound_pixel_pack_transfer_buffer_id_
;
1580 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
:
1581 *buffer_id
= bound_pixel_unpack_transfer_buffer_id_
;
1588 SetGLError(GL_INVALID_OPERATION
, function_name
, "no buffer bound");
1593 BufferTracker::Buffer
*
1594 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1596 const char* function_name
,
1597 GLuint offset
, GLsizei size
) {
1599 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
1601 SetGLError(GL_INVALID_OPERATION
, function_name
, "invalid buffer");
1604 if (buffer
->mapped()) {
1605 SetGLError(GL_INVALID_OPERATION
, function_name
, "buffer mapped");
1608 if ((buffer
->size() - offset
) < static_cast<GLuint
>(size
)) {
1609 SetGLError(GL_INVALID_VALUE
, function_name
, "unpack size to large");
1615 void GLES2Implementation::CompressedTexImage2D(
1616 GLenum target
, GLint level
, GLenum internalformat
, GLsizei width
,
1617 GLsizei height
, GLint border
, GLsizei image_size
, const void* data
) {
1618 GPU_CLIENT_SINGLE_THREAD_CHECK();
1619 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1620 << GLES2Util::GetStringTextureTarget(target
) << ", "
1622 << GLES2Util::GetStringCompressedTextureFormat(internalformat
) << ", "
1623 << width
<< ", " << height
<< ", " << border
<< ", "
1624 << image_size
<< ", "
1625 << static_cast<const void*>(data
) << ")");
1626 if (width
< 0 || height
< 0 || level
< 0) {
1627 SetGLError(GL_INVALID_VALUE
, "glCompressedTexImage2D", "dimension < 0");
1631 SetGLError(GL_INVALID_VALUE
, "glCompressedTexImage2D", "border != 0");
1634 if (height
== 0 || width
== 0) {
1637 // If there's a pixel unpack buffer bound use it when issuing
1638 // CompressedTexImage2D.
1639 if (bound_pixel_unpack_transfer_buffer_id_
) {
1640 GLuint offset
= ToGLuint(data
);
1641 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1642 bound_pixel_unpack_transfer_buffer_id_
,
1643 "glCompressedTexImage2D", offset
, image_size
);
1644 if (buffer
&& buffer
->shm_id() != -1) {
1645 helper_
->CompressedTexImage2D(
1646 target
, level
, internalformat
, width
, height
, image_size
,
1647 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1648 buffer
->set_last_usage_token(helper_
->InsertToken());
1652 SetBucketContents(kResultBucketId
, data
, image_size
);
1653 helper_
->CompressedTexImage2DBucket(
1654 target
, level
, internalformat
, width
, height
, kResultBucketId
);
1655 // Free the bucket. This is not required but it does free up the memory.
1656 // and we don't have to wait for the result so from the client's perspective
1658 helper_
->SetBucketSize(kResultBucketId
, 0);
1662 void GLES2Implementation::CompressedTexSubImage2D(
1663 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
1664 GLsizei height
, GLenum format
, GLsizei image_size
, const void* data
) {
1665 GPU_CLIENT_SINGLE_THREAD_CHECK();
1666 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1667 << GLES2Util::GetStringTextureTarget(target
) << ", "
1669 << xoffset
<< ", " << yoffset
<< ", "
1670 << width
<< ", " << height
<< ", "
1671 << GLES2Util::GetStringCompressedTextureFormat(format
) << ", "
1672 << image_size
<< ", "
1673 << static_cast<const void*>(data
) << ")");
1674 if (width
< 0 || height
< 0 || level
< 0) {
1675 SetGLError(GL_INVALID_VALUE
, "glCompressedTexSubImage2D", "dimension < 0");
1678 // If there's a pixel unpack buffer bound use it when issuing
1679 // CompressedTexSubImage2D.
1680 if (bound_pixel_unpack_transfer_buffer_id_
) {
1681 GLuint offset
= ToGLuint(data
);
1682 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1683 bound_pixel_unpack_transfer_buffer_id_
,
1684 "glCompressedTexSubImage2D", offset
, image_size
);
1685 if (buffer
&& buffer
->shm_id() != -1) {
1686 helper_
->CompressedTexSubImage2D(
1687 target
, level
, xoffset
, yoffset
, width
, height
, format
, image_size
,
1688 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1689 buffer
->set_last_usage_token(helper_
->InsertToken());
1694 SetBucketContents(kResultBucketId
, data
, image_size
);
1695 helper_
->CompressedTexSubImage2DBucket(
1696 target
, level
, xoffset
, yoffset
, width
, height
, format
, kResultBucketId
);
1697 // Free the bucket. This is not required but it does free up the memory.
1698 // and we don't have to wait for the result so from the client's perspective
1700 helper_
->SetBucketSize(kResultBucketId
, 0);
1706 void CopyRectToBuffer(
1709 uint32 unpadded_row_size
,
1710 uint32 pixels_padded_row_size
,
1713 uint32 buffer_padded_row_size
) {
1714 const int8
* source
= static_cast<const int8
*>(pixels
);
1715 int8
* dest
= static_cast<int8
*>(buffer
);
1716 if (flip_y
|| pixels_padded_row_size
!= buffer_padded_row_size
) {
1718 dest
+= buffer_padded_row_size
* (height
- 1);
1720 // the last row is copied unpadded at the end
1721 for (; height
> 1; --height
) {
1722 memcpy(dest
, source
, buffer_padded_row_size
);
1724 dest
-= buffer_padded_row_size
;
1726 dest
+= buffer_padded_row_size
;
1728 source
+= pixels_padded_row_size
;
1730 memcpy(dest
, source
, unpadded_row_size
);
1732 uint32 size
= (height
- 1) * pixels_padded_row_size
+ unpadded_row_size
;
1733 memcpy(dest
, source
, size
);
1737 } // anonymous namespace
1739 void GLES2Implementation::TexImage2D(
1740 GLenum target
, GLint level
, GLint internalformat
, GLsizei width
,
1741 GLsizei height
, GLint border
, GLenum format
, GLenum type
,
1742 const void* pixels
) {
1743 GPU_CLIENT_SINGLE_THREAD_CHECK();
1744 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1745 << GLES2Util::GetStringTextureTarget(target
) << ", "
1747 << GLES2Util::GetStringTextureInternalFormat(internalformat
) << ", "
1748 << width
<< ", " << height
<< ", " << border
<< ", "
1749 << GLES2Util::GetStringTextureFormat(format
) << ", "
1750 << GLES2Util::GetStringPixelType(type
) << ", "
1751 << static_cast<const void*>(pixels
) << ")");
1752 if (level
< 0 || height
< 0 || width
< 0) {
1753 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "dimension < 0");
1757 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "border != 0");
1761 uint32 unpadded_row_size
;
1762 uint32 padded_row_size
;
1763 if (!GLES2Util::ComputeImageDataSizes(
1764 width
, height
, format
, type
, unpack_alignment_
, &size
,
1765 &unpadded_row_size
, &padded_row_size
)) {
1766 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "image size too large");
1770 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1771 if (bound_pixel_unpack_transfer_buffer_id_
) {
1772 GLuint offset
= ToGLuint(pixels
);
1773 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1774 bound_pixel_unpack_transfer_buffer_id_
,
1775 "glTexImage2D", offset
, size
);
1776 if (buffer
&& buffer
->shm_id() != -1) {
1777 helper_
->TexImage2D(
1778 target
, level
, internalformat
, width
, height
, format
, type
,
1779 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1780 buffer
->set_last_usage_token(helper_
->InsertToken());
1786 // If there's no data just issue TexImage2D
1788 helper_
->TexImage2D(
1789 target
, level
, internalformat
, width
, height
, format
, type
,
1795 // compute the advance bytes per row for the src pixels
1796 uint32 src_padded_row_size
;
1797 if (unpack_row_length_
> 0) {
1798 if (!GLES2Util::ComputeImagePaddedRowSize(
1799 unpack_row_length_
, format
, type
, unpack_alignment_
,
1800 &src_padded_row_size
)) {
1802 GL_INVALID_VALUE
, "glTexImage2D", "unpack row length too large");
1806 src_padded_row_size
= padded_row_size
;
1809 // advance pixels pointer past the skip rows and skip pixels
1810 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1811 unpack_skip_rows_
* src_padded_row_size
;
1812 if (unpack_skip_pixels_
) {
1813 uint32 group_size
= GLES2Util::ComputeImageGroupSize(format
, type
);
1814 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1815 unpack_skip_pixels_
* group_size
;
1818 // Check if we can send it all at once.
1819 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1820 if (!buffer
.valid()) {
1824 if (buffer
.size() >= size
) {
1826 pixels
, height
, unpadded_row_size
, src_padded_row_size
, unpack_flip_y_
,
1827 buffer
.address(), padded_row_size
);
1828 helper_
->TexImage2D(
1829 target
, level
, internalformat
, width
, height
, format
, type
,
1830 buffer
.shm_id(), buffer
.offset());
1835 // No, so send it using TexSubImage2D.
1836 helper_
->TexImage2D(
1837 target
, level
, internalformat
, width
, height
, format
, type
,
1840 target
, level
, 0, 0, width
, height
, format
, type
, unpadded_row_size
,
1841 pixels
, src_padded_row_size
, GL_TRUE
, &buffer
, padded_row_size
);
1845 void GLES2Implementation::TexSubImage2D(
1846 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
1847 GLsizei height
, GLenum format
, GLenum type
, const void* pixels
) {
1848 GPU_CLIENT_SINGLE_THREAD_CHECK();
1849 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1850 << GLES2Util::GetStringTextureTarget(target
) << ", "
1852 << xoffset
<< ", " << yoffset
<< ", "
1853 << width
<< ", " << height
<< ", "
1854 << GLES2Util::GetStringTextureFormat(format
) << ", "
1855 << GLES2Util::GetStringPixelType(type
) << ", "
1856 << static_cast<const void*>(pixels
) << ")");
1858 if (level
< 0 || height
< 0 || width
< 0) {
1859 SetGLError(GL_INVALID_VALUE
, "glTexSubImage2D", "dimension < 0");
1862 if (height
== 0 || width
== 0) {
1867 uint32 unpadded_row_size
;
1868 uint32 padded_row_size
;
1869 if (!GLES2Util::ComputeImageDataSizes(
1870 width
, height
, format
, type
, unpack_alignment_
, &temp_size
,
1871 &unpadded_row_size
, &padded_row_size
)) {
1872 SetGLError(GL_INVALID_VALUE
, "glTexSubImage2D", "size to large");
1876 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1877 if (bound_pixel_unpack_transfer_buffer_id_
) {
1878 GLuint offset
= ToGLuint(pixels
);
1879 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1880 bound_pixel_unpack_transfer_buffer_id_
,
1881 "glTexSubImage2D", offset
, temp_size
);
1882 if (buffer
&& buffer
->shm_id() != -1) {
1883 helper_
->TexSubImage2D(
1884 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
,
1885 buffer
->shm_id(), buffer
->shm_offset() + offset
, false);
1886 buffer
->set_last_usage_token(helper_
->InsertToken());
1892 // compute the advance bytes per row for the src pixels
1893 uint32 src_padded_row_size
;
1894 if (unpack_row_length_
> 0) {
1895 if (!GLES2Util::ComputeImagePaddedRowSize(
1896 unpack_row_length_
, format
, type
, unpack_alignment_
,
1897 &src_padded_row_size
)) {
1899 GL_INVALID_VALUE
, "glTexImage2D", "unpack row length too large");
1903 src_padded_row_size
= padded_row_size
;
1906 // advance pixels pointer past the skip rows and skip pixels
1907 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1908 unpack_skip_rows_
* src_padded_row_size
;
1909 if (unpack_skip_pixels_
) {
1910 uint32 group_size
= GLES2Util::ComputeImageGroupSize(format
, type
);
1911 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1912 unpack_skip_pixels_
* group_size
;
1915 ScopedTransferBufferPtr
buffer(temp_size
, helper_
, transfer_buffer_
);
1917 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
,
1918 unpadded_row_size
, pixels
, src_padded_row_size
, GL_FALSE
, &buffer
,
1923 static GLint
ComputeNumRowsThatFitInBuffer(
1924 uint32 padded_row_size
, uint32 unpadded_row_size
,
1925 unsigned int size
) {
1926 DCHECK_GE(unpadded_row_size
, 0u);
1927 if (padded_row_size
== 0) {
1930 GLint num_rows
= size
/ padded_row_size
;
1931 return num_rows
+ (size
- num_rows
* padded_row_size
) / unpadded_row_size
;
1934 void GLES2Implementation::TexSubImage2DImpl(
1935 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
1936 GLsizei height
, GLenum format
, GLenum type
, uint32 unpadded_row_size
,
1937 const void* pixels
, uint32 pixels_padded_row_size
, GLboolean internal
,
1938 ScopedTransferBufferPtr
* buffer
, uint32 buffer_padded_row_size
) {
1940 DCHECK_GE(level
, 0);
1941 DCHECK_GT(height
, 0);
1942 DCHECK_GT(width
, 0);
1944 const int8
* source
= reinterpret_cast<const int8
*>(pixels
);
1945 GLint original_yoffset
= yoffset
;
1946 // Transfer by rows.
1948 unsigned int desired_size
=
1949 buffer_padded_row_size
* (height
- 1) + unpadded_row_size
;
1950 if (!buffer
->valid() || buffer
->size() == 0) {
1951 buffer
->Reset(desired_size
);
1952 if (!buffer
->valid()) {
1957 GLint num_rows
= ComputeNumRowsThatFitInBuffer(
1958 buffer_padded_row_size
, unpadded_row_size
, buffer
->size());
1959 num_rows
= std::min(num_rows
, height
);
1961 source
, num_rows
, unpadded_row_size
, pixels_padded_row_size
,
1962 unpack_flip_y_
, buffer
->address(), buffer_padded_row_size
);
1963 GLint y
= unpack_flip_y_
? original_yoffset
+ height
- num_rows
: yoffset
;
1964 helper_
->TexSubImage2D(
1965 target
, level
, xoffset
, y
, width
, num_rows
, format
, type
,
1966 buffer
->shm_id(), buffer
->offset(), internal
);
1968 yoffset
+= num_rows
;
1969 source
+= num_rows
* pixels_padded_row_size
;
1974 bool GLES2Implementation::GetActiveAttribHelper(
1975 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
1976 GLenum
* type
, char* name
) {
1977 // Clear the bucket so if the command fails nothing will be in it.
1978 helper_
->SetBucketSize(kResultBucketId
, 0);
1979 typedef cmds::GetActiveAttrib::Result Result
;
1980 Result
* result
= GetResultAs
<Result
*>();
1984 // Set as failed so if the command fails we'll recover.
1985 result
->success
= false;
1986 helper_
->GetActiveAttrib(program
, index
, kResultBucketId
,
1987 GetResultShmId(), GetResultShmOffset());
1989 if (result
->success
) {
1991 *size
= result
->size
;
1994 *type
= result
->type
;
1996 if (length
|| name
) {
1997 std::vector
<int8
> str
;
1998 GetBucketContents(kResultBucketId
, &str
);
1999 GLsizei max_size
= std::min(static_cast<size_t>(bufsize
) - 1,
2000 std::max(static_cast<size_t>(0),
2005 if (name
&& bufsize
> 0) {
2006 memcpy(name
, &str
[0], max_size
);
2007 name
[max_size
] = '\0';
2011 return result
->success
!= 0;
2014 void GLES2Implementation::GetActiveAttrib(
2015 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2016 GLenum
* type
, char* name
) {
2017 GPU_CLIENT_SINGLE_THREAD_CHECK();
2018 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2019 << program
<< ", " << index
<< ", " << bufsize
<< ", "
2020 << static_cast<const void*>(length
) << ", "
2021 << static_cast<const void*>(size
) << ", "
2022 << static_cast<const void*>(type
) << ", "
2023 << static_cast<const void*>(name
) << ", ");
2025 SetGLError(GL_INVALID_VALUE
, "glGetActiveAttrib", "bufsize < 0");
2028 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2029 bool success
= share_group_
->program_info_manager()->GetActiveAttrib(
2030 this, program
, index
, bufsize
, length
, size
, type
, name
);
2033 GPU_CLIENT_LOG(" size: " << *size
);
2036 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type
));
2039 GPU_CLIENT_LOG(" name: " << name
);
2045 bool GLES2Implementation::GetActiveUniformHelper(
2046 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2047 GLenum
* type
, char* name
) {
2048 // Clear the bucket so if the command fails nothing will be in it.
2049 helper_
->SetBucketSize(kResultBucketId
, 0);
2050 typedef cmds::GetActiveUniform::Result Result
;
2051 Result
* result
= GetResultAs
<Result
*>();
2055 // Set as failed so if the command fails we'll recover.
2056 result
->success
= false;
2057 helper_
->GetActiveUniform(program
, index
, kResultBucketId
,
2058 GetResultShmId(), GetResultShmOffset());
2060 if (result
->success
) {
2062 *size
= result
->size
;
2065 *type
= result
->type
;
2067 if (length
|| name
) {
2068 std::vector
<int8
> str
;
2069 GetBucketContents(kResultBucketId
, &str
);
2070 GLsizei max_size
= std::min(static_cast<size_t>(bufsize
) - 1,
2071 std::max(static_cast<size_t>(0),
2076 if (name
&& bufsize
> 0) {
2077 memcpy(name
, &str
[0], max_size
);
2078 name
[max_size
] = '\0';
2082 return result
->success
!= 0;
2085 void GLES2Implementation::GetActiveUniform(
2086 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2087 GLenum
* type
, char* name
) {
2088 GPU_CLIENT_SINGLE_THREAD_CHECK();
2089 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2090 << program
<< ", " << index
<< ", " << bufsize
<< ", "
2091 << static_cast<const void*>(length
) << ", "
2092 << static_cast<const void*>(size
) << ", "
2093 << static_cast<const void*>(type
) << ", "
2094 << static_cast<const void*>(name
) << ", ");
2096 SetGLError(GL_INVALID_VALUE
, "glGetActiveUniform", "bufsize < 0");
2099 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2100 bool success
= share_group_
->program_info_manager()->GetActiveUniform(
2101 this, program
, index
, bufsize
, length
, size
, type
, name
);
2104 GPU_CLIENT_LOG(" size: " << *size
);
2107 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type
));
2110 GPU_CLIENT_LOG(" name: " << name
);
2116 void GLES2Implementation::GetAttachedShaders(
2117 GLuint program
, GLsizei maxcount
, GLsizei
* count
, GLuint
* shaders
) {
2118 GPU_CLIENT_SINGLE_THREAD_CHECK();
2119 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2120 << program
<< ", " << maxcount
<< ", "
2121 << static_cast<const void*>(count
) << ", "
2122 << static_cast<const void*>(shaders
) << ", ");
2124 SetGLError(GL_INVALID_VALUE
, "glGetAttachedShaders", "maxcount < 0");
2127 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2128 typedef cmds::GetAttachedShaders::Result Result
;
2129 uint32 size
= Result::ComputeSize(maxcount
);
2130 Result
* result
= static_cast<Result
*>(transfer_buffer_
->Alloc(size
));
2134 result
->SetNumResults(0);
2135 helper_
->GetAttachedShaders(
2137 transfer_buffer_
->GetShmId(),
2138 transfer_buffer_
->GetOffset(result
),
2140 int32 token
= helper_
->InsertToken();
2143 *count
= result
->GetNumResults();
2145 result
->CopyResult(shaders
);
2146 GPU_CLIENT_LOG_CODE_BLOCK({
2147 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2148 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2151 transfer_buffer_
->FreePendingToken(result
, token
);
2155 void GLES2Implementation::GetShaderPrecisionFormat(
2156 GLenum shadertype
, GLenum precisiontype
, GLint
* range
, GLint
* precision
) {
2157 GPU_CLIENT_SINGLE_THREAD_CHECK();
2158 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2159 << GLES2Util::GetStringShaderType(shadertype
) << ", "
2160 << GLES2Util::GetStringShaderPrecision(precisiontype
) << ", "
2161 << static_cast<const void*>(range
) << ", "
2162 << static_cast<const void*>(precision
) << ", ");
2163 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2164 typedef cmds::GetShaderPrecisionFormat::Result Result
;
2165 Result
* result
= GetResultAs
<Result
*>();
2170 GLStaticState::ShaderPrecisionKey
key(shadertype
, precisiontype
);
2171 GLStaticState::ShaderPrecisionMap::iterator i
=
2172 static_state_
.shader_precisions
.find(key
);
2173 if (i
!= static_state_
.shader_precisions
.end()) {
2174 *result
= i
->second
;
2176 result
->success
= false;
2177 helper_
->GetShaderPrecisionFormat(
2178 shadertype
, precisiontype
, GetResultShmId(), GetResultShmOffset());
2180 if (result
->success
)
2181 static_state_
.shader_precisions
[key
] = *result
;
2184 if (result
->success
) {
2186 range
[0] = result
->min_range
;
2187 range
[1] = result
->max_range
;
2188 GPU_CLIENT_LOG(" min_range: " << range
[0]);
2189 GPU_CLIENT_LOG(" min_range: " << range
[1]);
2192 precision
[0] = result
->precision
;
2193 GPU_CLIENT_LOG(" min_range: " << precision
[0]);
2199 const GLubyte
* GLES2Implementation::GetStringHelper(GLenum name
) {
2200 const char* result
= NULL
;
2201 // Clears the bucket so if the command fails nothing will be in it.
2202 helper_
->SetBucketSize(kResultBucketId
, 0);
2203 helper_
->GetString(name
, kResultBucketId
);
2205 if (GetBucketAsString(kResultBucketId
, &str
)) {
2206 // Adds extensions implemented on client side only.
2209 str
+= std::string(str
.empty() ? "" : " ") +
2210 "GL_CHROMIUM_flipy "
2211 "GL_EXT_unpack_subimage "
2212 "GL_CHROMIUM_map_sub";
2213 if (capabilities_
.map_image
) {
2214 // The first space character is intentional.
2215 str
+= " GL_CHROMIUM_map_image";
2217 if (capabilities_
.future_sync_points
)
2218 str
+= " GL_CHROMIUM_future_sync_point";
2224 // Because of WebGL the extensions can change. We have to cache each unique
2225 // result since we don't know when the client will stop referring to a
2226 // previous one it queries.
2227 GLStringMap::iterator it
= gl_strings_
.find(name
);
2228 if (it
== gl_strings_
.end()) {
2229 std::set
<std::string
> strings
;
2230 std::pair
<GLStringMap::iterator
, bool> insert_result
=
2231 gl_strings_
.insert(std::make_pair(name
, strings
));
2232 DCHECK(insert_result
.second
);
2233 it
= insert_result
.first
;
2235 std::set
<std::string
>& string_set
= it
->second
;
2236 std::set
<std::string
>::const_iterator sit
= string_set
.find(str
);
2237 if (sit
!= string_set
.end()) {
2238 result
= sit
->c_str();
2240 std::pair
<std::set
<std::string
>::const_iterator
, bool> insert_result
=
2241 string_set
.insert(str
);
2242 DCHECK(insert_result
.second
);
2243 result
= insert_result
.first
->c_str();
2246 return reinterpret_cast<const GLubyte
*>(result
);
2249 const GLubyte
* GLES2Implementation::GetString(GLenum name
) {
2250 GPU_CLIENT_SINGLE_THREAD_CHECK();
2251 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2252 << GLES2Util::GetStringStringType(name
) << ")");
2253 TRACE_EVENT0("gpu", "GLES2::GetString");
2254 const GLubyte
* result
= GetStringHelper(name
);
2255 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result
));
2260 void GLES2Implementation::GetUniformfv(
2261 GLuint program
, GLint location
, GLfloat
* params
) {
2262 GPU_CLIENT_SINGLE_THREAD_CHECK();
2263 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2264 << program
<< ", " << location
<< ", "
2265 << static_cast<const void*>(params
) << ")");
2266 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2267 typedef cmds::GetUniformfv::Result Result
;
2268 Result
* result
= GetResultAs
<Result
*>();
2272 result
->SetNumResults(0);
2273 helper_
->GetUniformfv(
2274 program
, location
, GetResultShmId(), GetResultShmOffset());
2276 result
->CopyResult(params
);
2277 GPU_CLIENT_LOG_CODE_BLOCK({
2278 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2279 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2285 void GLES2Implementation::GetUniformiv(
2286 GLuint program
, GLint location
, GLint
* params
) {
2287 GPU_CLIENT_SINGLE_THREAD_CHECK();
2288 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2289 << program
<< ", " << location
<< ", "
2290 << static_cast<const void*>(params
) << ")");
2291 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2292 typedef cmds::GetUniformiv::Result Result
;
2293 Result
* result
= GetResultAs
<Result
*>();
2297 result
->SetNumResults(0);
2298 helper_
->GetUniformiv(
2299 program
, location
, GetResultShmId(), GetResultShmOffset());
2301 GetResultAs
<cmds::GetUniformfv::Result
*>()->CopyResult(params
);
2302 GPU_CLIENT_LOG_CODE_BLOCK({
2303 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2304 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2310 void GLES2Implementation::ReadPixels(
2311 GLint xoffset
, GLint yoffset
, GLsizei width
, GLsizei height
, GLenum format
,
2312 GLenum type
, void* pixels
) {
2313 GPU_CLIENT_SINGLE_THREAD_CHECK();
2314 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2315 << xoffset
<< ", " << yoffset
<< ", "
2316 << width
<< ", " << height
<< ", "
2317 << GLES2Util::GetStringReadPixelFormat(format
) << ", "
2318 << GLES2Util::GetStringPixelType(type
) << ", "
2319 << static_cast<const void*>(pixels
) << ")");
2320 if (width
< 0 || height
< 0) {
2321 SetGLError(GL_INVALID_VALUE
, "glReadPixels", "dimensions < 0");
2324 if (width
== 0 || height
== 0) {
2328 // glReadPixel pads the size of each row of pixels by an amount specified by
2329 // glPixelStorei. So, we have to take that into account both in the fact that
2330 // the pixels returned from the ReadPixel command will include that padding
2331 // and that when we copy the results to the user's buffer we need to not
2332 // write those padding bytes but leave them as they are.
2334 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2335 typedef cmds::ReadPixels::Result Result
;
2337 int8
* dest
= reinterpret_cast<int8
*>(pixels
);
2339 uint32 unpadded_row_size
;
2340 uint32 padded_row_size
;
2341 if (!GLES2Util::ComputeImageDataSizes(
2342 width
, 2, format
, type
, pack_alignment_
, &temp_size
, &unpadded_row_size
,
2343 &padded_row_size
)) {
2344 SetGLError(GL_INVALID_VALUE
, "glReadPixels", "size too large.");
2348 if (bound_pixel_pack_transfer_buffer_id_
) {
2349 GLuint offset
= ToGLuint(pixels
);
2350 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
2351 bound_pixel_pack_transfer_buffer_id_
,
2352 "glReadPixels", offset
, padded_row_size
* height
);
2353 if (buffer
&& buffer
->shm_id() != -1) {
2354 helper_
->ReadPixels(xoffset
, yoffset
, width
, height
, format
, type
,
2355 buffer
->shm_id(), buffer
->shm_offset(),
2363 SetGLError(GL_INVALID_OPERATION
, "glReadPixels", "pixels = NULL");
2367 // Transfer by rows.
2368 // The max rows we can transfer.
2370 GLsizei desired_size
= padded_row_size
* height
- 1 + unpadded_row_size
;
2371 ScopedTransferBufferPtr
buffer(desired_size
, helper_
, transfer_buffer_
);
2372 if (!buffer
.valid()) {
2375 GLint num_rows
= ComputeNumRowsThatFitInBuffer(
2376 padded_row_size
, unpadded_row_size
, buffer
.size());
2377 num_rows
= std::min(num_rows
, height
);
2378 // NOTE: We must look up the address of the result area AFTER allocation
2379 // of the transfer buffer since the transfer buffer may be reallocated.
2380 Result
* result
= GetResultAs
<Result
*>();
2384 *result
= 0; // mark as failed.
2385 helper_
->ReadPixels(
2386 xoffset
, yoffset
, width
, num_rows
, format
, type
,
2387 buffer
.shm_id(), buffer
.offset(),
2388 GetResultShmId(), GetResultShmOffset(),
2392 // when doing a y-flip we have to iterate through top-to-bottom chunks
2393 // of the dst. The service side handles reversing the rows within a
2396 if (pack_reverse_row_order_
) {
2397 rows_dst
= dest
+ (height
- num_rows
) * padded_row_size
;
2401 // We have to copy 1 row at a time to avoid writing pad bytes.
2402 const int8
* src
= static_cast<const int8
*>(buffer
.address());
2403 for (GLint yy
= 0; yy
< num_rows
; ++yy
) {
2404 memcpy(rows_dst
, src
, unpadded_row_size
);
2405 rows_dst
+= padded_row_size
;
2406 src
+= padded_row_size
;
2408 if (!pack_reverse_row_order_
) {
2412 // If it was not marked as successful exit.
2416 yoffset
+= num_rows
;
2422 void GLES2Implementation::ActiveTexture(GLenum texture
) {
2423 GPU_CLIENT_SINGLE_THREAD_CHECK();
2424 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2425 << GLES2Util::GetStringEnum(texture
) << ")");
2426 GLuint texture_index
= texture
- GL_TEXTURE0
;
2427 if (texture_index
>= static_cast<GLuint
>(
2428 static_state_
.int_state
.max_combined_texture_image_units
)) {
2429 SetGLErrorInvalidEnum(
2430 "glActiveTexture", texture
, "texture");
2434 active_texture_unit_
= texture_index
;
2435 helper_
->ActiveTexture(texture
);
2439 void GLES2Implementation::GenBuffersHelper(
2440 GLsizei
/* n */, const GLuint
* /* buffers */) {
2443 void GLES2Implementation::GenFramebuffersHelper(
2444 GLsizei
/* n */, const GLuint
* /* framebuffers */) {
2447 void GLES2Implementation::GenRenderbuffersHelper(
2448 GLsizei
/* n */, const GLuint
* /* renderbuffers */) {
2451 void GLES2Implementation::GenTexturesHelper(
2452 GLsizei
/* n */, const GLuint
* /* textures */) {
2455 void GLES2Implementation::GenVertexArraysOESHelper(
2456 GLsizei n
, const GLuint
* arrays
) {
2457 vertex_array_object_manager_
->GenVertexArrays(n
, arrays
);
2460 void GLES2Implementation::GenQueriesEXTHelper(
2461 GLsizei
/* n */, const GLuint
* /* queries */) {
2464 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
2465 // generates a new resource. On newer versions of OpenGL they don't. The code
2466 // related to binding below will need to change if we switch to the new OpenGL
2467 // model. Specifically it assumes a bind will succeed which is always true in
2468 // the old model but possibly not true in the new model if another context has
2469 // deleted the resource.
2471 bool GLES2Implementation::BindBufferHelper(
2472 GLenum target
, GLuint buffer_id
) {
2473 // TODO(gman): See note #1 above.
2474 bool changed
= false;
2476 case GL_ARRAY_BUFFER
:
2477 if (bound_array_buffer_id_
!= buffer_id
) {
2478 bound_array_buffer_id_
= buffer_id
;
2482 case GL_ELEMENT_ARRAY_BUFFER
:
2483 changed
= vertex_array_object_manager_
->BindElementArray(buffer_id
);
2485 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
:
2486 bound_pixel_pack_transfer_buffer_id_
= buffer_id
;
2488 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
:
2489 bound_pixel_unpack_transfer_buffer_id_
= buffer_id
;
2495 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2496 // used even though it's marked it as used here.
2497 GetIdHandler(id_namespaces::kBuffers
)->MarkAsUsedForBind(buffer_id
);
2501 bool GLES2Implementation::BindFramebufferHelper(
2502 GLenum target
, GLuint framebuffer
) {
2503 // TODO(gman): See note #1 above.
2504 bool changed
= false;
2506 case GL_FRAMEBUFFER
:
2507 if (bound_framebuffer_
!= framebuffer
||
2508 bound_read_framebuffer_
!= framebuffer
) {
2509 bound_framebuffer_
= framebuffer
;
2510 bound_read_framebuffer_
= framebuffer
;
2514 case GL_READ_FRAMEBUFFER
:
2515 if (!IsChromiumFramebufferMultisampleAvailable()) {
2516 SetGLErrorInvalidEnum("glBindFramebuffer", target
, "target");
2519 if (bound_read_framebuffer_
!= framebuffer
) {
2520 bound_read_framebuffer_
= framebuffer
;
2524 case GL_DRAW_FRAMEBUFFER
:
2525 if (!IsChromiumFramebufferMultisampleAvailable()) {
2526 SetGLErrorInvalidEnum("glBindFramebuffer", target
, "target");
2529 if (bound_framebuffer_
!= framebuffer
) {
2530 bound_framebuffer_
= framebuffer
;
2535 SetGLErrorInvalidEnum("glBindFramebuffer", target
, "target");
2538 GetIdHandler(id_namespaces::kFramebuffers
)->MarkAsUsedForBind(framebuffer
);
2542 bool GLES2Implementation::BindRenderbufferHelper(
2543 GLenum target
, GLuint renderbuffer
) {
2544 // TODO(gman): See note #1 above.
2545 bool changed
= false;
2547 case GL_RENDERBUFFER
:
2548 if (bound_renderbuffer_
!= renderbuffer
) {
2549 bound_renderbuffer_
= renderbuffer
;
2557 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2558 // used even though it's marked it as used here.
2559 GetIdHandler(id_namespaces::kRenderbuffers
)->MarkAsUsedForBind(renderbuffer
);
2563 bool GLES2Implementation::BindTextureHelper(GLenum target
, GLuint texture
) {
2564 // TODO(gman): See note #1 above.
2565 // TODO(gman): Change this to false once we figure out why it's failing
2567 bool changed
= true;
2568 TextureUnit
& unit
= texture_units_
[active_texture_unit_
];
2571 if (unit
.bound_texture_2d
!= texture
) {
2572 unit
.bound_texture_2d
= texture
;
2576 case GL_TEXTURE_CUBE_MAP
:
2577 if (unit
.bound_texture_cube_map
!= texture
) {
2578 unit
.bound_texture_cube_map
= texture
;
2582 case GL_TEXTURE_EXTERNAL_OES
:
2583 if (unit
.bound_texture_external_oes
!= texture
) {
2584 unit
.bound_texture_external_oes
= texture
;
2592 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2593 // used. even though it's marked it as used here.
2594 GetIdHandler(id_namespaces::kTextures
)->MarkAsUsedForBind(texture
);
2598 bool GLES2Implementation::BindVertexArrayOESHelper(GLuint array
) {
2599 // TODO(gman): See note #1 above.
2600 bool changed
= false;
2601 if (!vertex_array_object_manager_
->BindVertexArray(array
, &changed
)) {
2603 GL_INVALID_OPERATION
, "glBindVertexArrayOES",
2604 "id was not generated with glGenVertexArrayOES");
2606 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
2607 // because unlike other resources VertexArrayObject ids must
2608 // be generated by GenVertexArrays. A random id to Bind will not
2609 // generate a new object.
2613 bool GLES2Implementation::UseProgramHelper(GLuint program
) {
2614 bool changed
= false;
2615 if (current_program_
!= program
) {
2616 current_program_
= program
;
2622 bool GLES2Implementation::IsBufferReservedId(GLuint id
) {
2623 return vertex_array_object_manager_
->IsReservedId(id
);
2626 void GLES2Implementation::DeleteBuffersHelper(
2627 GLsizei n
, const GLuint
* buffers
) {
2628 if (!GetIdHandler(id_namespaces::kBuffers
)->FreeIds(
2629 this, n
, buffers
, &GLES2Implementation::DeleteBuffersStub
)) {
2632 "glDeleteBuffers", "id not created by this context.");
2635 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
2636 if (buffers
[ii
] == bound_array_buffer_id_
) {
2637 bound_array_buffer_id_
= 0;
2639 vertex_array_object_manager_
->UnbindBuffer(buffers
[ii
]);
2641 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffers
[ii
]);
2643 RemoveTransferBuffer(buffer
);
2645 if (buffers
[ii
] == bound_pixel_unpack_transfer_buffer_id_
) {
2646 bound_pixel_unpack_transfer_buffer_id_
= 0;
2651 void GLES2Implementation::DeleteBuffersStub(
2652 GLsizei n
, const GLuint
* buffers
) {
2653 helper_
->DeleteBuffersImmediate(n
, buffers
);
2657 void GLES2Implementation::DeleteFramebuffersHelper(
2658 GLsizei n
, const GLuint
* framebuffers
) {
2659 if (!GetIdHandler(id_namespaces::kFramebuffers
)->FreeIds(
2660 this, n
, framebuffers
, &GLES2Implementation::DeleteFramebuffersStub
)) {
2663 "glDeleteFramebuffers", "id not created by this context.");
2666 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
2667 if (framebuffers
[ii
] == bound_framebuffer_
) {
2668 bound_framebuffer_
= 0;
2670 if (framebuffers
[ii
] == bound_read_framebuffer_
) {
2671 bound_read_framebuffer_
= 0;
2676 void GLES2Implementation::DeleteFramebuffersStub(
2677 GLsizei n
, const GLuint
* framebuffers
) {
2678 helper_
->DeleteFramebuffersImmediate(n
, framebuffers
);
2681 void GLES2Implementation::DeleteRenderbuffersHelper(
2682 GLsizei n
, const GLuint
* renderbuffers
) {
2683 if (!GetIdHandler(id_namespaces::kRenderbuffers
)->FreeIds(
2684 this, n
, renderbuffers
, &GLES2Implementation::DeleteRenderbuffersStub
)) {
2687 "glDeleteRenderbuffers", "id not created by this context.");
2690 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
2691 if (renderbuffers
[ii
] == bound_renderbuffer_
) {
2692 bound_renderbuffer_
= 0;
2697 void GLES2Implementation::DeleteRenderbuffersStub(
2698 GLsizei n
, const GLuint
* renderbuffers
) {
2699 helper_
->DeleteRenderbuffersImmediate(n
, renderbuffers
);
2702 void GLES2Implementation::DeleteTexturesHelper(
2703 GLsizei n
, const GLuint
* textures
) {
2704 if (!GetIdHandler(id_namespaces::kTextures
)->FreeIds(
2705 this, n
, textures
, &GLES2Implementation::DeleteTexturesStub
)) {
2708 "glDeleteTextures", "id not created by this context.");
2711 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
2713 tt
< static_state_
.int_state
.max_combined_texture_image_units
;
2715 TextureUnit
& unit
= texture_units_
[tt
];
2716 if (textures
[ii
] == unit
.bound_texture_2d
) {
2717 unit
.bound_texture_2d
= 0;
2719 if (textures
[ii
] == unit
.bound_texture_cube_map
) {
2720 unit
.bound_texture_cube_map
= 0;
2722 if (textures
[ii
] == unit
.bound_texture_external_oes
) {
2723 unit
.bound_texture_external_oes
= 0;
2729 void GLES2Implementation::DeleteVertexArraysOESHelper(
2730 GLsizei n
, const GLuint
* arrays
) {
2731 vertex_array_object_manager_
->DeleteVertexArrays(n
, arrays
);
2732 if (!GetIdHandler(id_namespaces::kVertexArrays
)->FreeIds(
2733 this, n
, arrays
, &GLES2Implementation::DeleteVertexArraysOESStub
)) {
2736 "glDeleteVertexArraysOES", "id not created by this context.");
2741 void GLES2Implementation::DeleteVertexArraysOESStub(
2742 GLsizei n
, const GLuint
* arrays
) {
2743 helper_
->DeleteVertexArraysOESImmediate(n
, arrays
);
2746 void GLES2Implementation::DeleteTexturesStub(
2747 GLsizei n
, const GLuint
* textures
) {
2748 helper_
->DeleteTexturesImmediate(n
, textures
);
2751 void GLES2Implementation::DisableVertexAttribArray(GLuint index
) {
2752 GPU_CLIENT_SINGLE_THREAD_CHECK();
2754 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index
<< ")");
2755 vertex_array_object_manager_
->SetAttribEnable(index
, false);
2756 helper_
->DisableVertexAttribArray(index
);
2760 void GLES2Implementation::EnableVertexAttribArray(GLuint index
) {
2761 GPU_CLIENT_SINGLE_THREAD_CHECK();
2762 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
2764 vertex_array_object_manager_
->SetAttribEnable(index
, true);
2765 helper_
->EnableVertexAttribArray(index
);
2769 void GLES2Implementation::DrawArrays(GLenum mode
, GLint first
, GLsizei count
) {
2770 GPU_CLIENT_SINGLE_THREAD_CHECK();
2771 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
2772 << GLES2Util::GetStringDrawMode(mode
) << ", "
2773 << first
<< ", " << count
<< ")");
2775 SetGLError(GL_INVALID_VALUE
, "glDrawArrays", "count < 0");
2778 bool simulated
= false;
2779 if (!vertex_array_object_manager_
->SetupSimulatedClientSideBuffers(
2780 "glDrawArrays", this, helper_
, first
+ count
, 0, &simulated
)) {
2783 helper_
->DrawArrays(mode
, first
, count
);
2784 RestoreArrayBuffer(simulated
);
2788 void GLES2Implementation::GetVertexAttribfv(
2789 GLuint index
, GLenum pname
, GLfloat
* params
) {
2790 GPU_CLIENT_SINGLE_THREAD_CHECK();
2791 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
2793 << GLES2Util::GetStringVertexAttribute(pname
) << ", "
2794 << static_cast<const void*>(params
) << ")");
2796 if (vertex_array_object_manager_
->GetVertexAttrib(index
, pname
, &value
)) {
2797 *params
= static_cast<float>(value
);
2800 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
2801 typedef cmds::GetVertexAttribfv::Result Result
;
2802 Result
* result
= GetResultAs
<Result
*>();
2806 result
->SetNumResults(0);
2807 helper_
->GetVertexAttribfv(
2808 index
, pname
, GetResultShmId(), GetResultShmOffset());
2810 result
->CopyResult(params
);
2811 GPU_CLIENT_LOG_CODE_BLOCK({
2812 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2813 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2819 void GLES2Implementation::GetVertexAttribiv(
2820 GLuint index
, GLenum pname
, GLint
* params
) {
2821 GPU_CLIENT_SINGLE_THREAD_CHECK();
2822 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
2824 << GLES2Util::GetStringVertexAttribute(pname
) << ", "
2825 << static_cast<const void*>(params
) << ")");
2827 if (vertex_array_object_manager_
->GetVertexAttrib(index
, pname
, &value
)) {
2831 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
2832 typedef cmds::GetVertexAttribiv::Result Result
;
2833 Result
* result
= GetResultAs
<Result
*>();
2837 result
->SetNumResults(0);
2838 helper_
->GetVertexAttribiv(
2839 index
, pname
, GetResultShmId(), GetResultShmOffset());
2841 result
->CopyResult(params
);
2842 GPU_CLIENT_LOG_CODE_BLOCK({
2843 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2844 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2850 void GLES2Implementation::Swap() {
2853 base::Bind(&GLES2Implementation::OnSwapBuffersComplete
,
2854 weak_ptr_factory_
.GetWeakPtr()));
2857 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect
& sub_buffer
) {
2858 PostSubBufferCHROMIUM(sub_buffer
.x(),
2861 sub_buffer
.height());
2862 gpu_control_
->Echo(base::Bind(&GLES2Implementation::OnSwapBuffersComplete
,
2863 weak_ptr_factory_
.GetWeakPtr()));
2866 void GLES2Implementation::SetSwapBuffersCompleteCallback(
2867 const base::Closure
& swap_buffers_complete_callback
) {
2868 swap_buffers_complete_callback_
= swap_buffers_complete_callback
;
2871 static GLenum
GetGLESOverlayTransform(gfx::OverlayTransform plane_transform
) {
2872 switch (plane_transform
) {
2873 case gfx::OVERLAY_TRANSFORM_INVALID
:
2875 case gfx::OVERLAY_TRANSFORM_NONE
:
2876 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM
;
2877 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL
:
2878 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM
;
2879 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL
:
2880 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM
;
2881 case gfx::OVERLAY_TRANSFORM_ROTATE_90
:
2882 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM
;
2883 case gfx::OVERLAY_TRANSFORM_ROTATE_180
:
2884 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM
;
2885 case gfx::OVERLAY_TRANSFORM_ROTATE_270
:
2886 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM
;
2889 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM
;
2892 void GLES2Implementation::ScheduleOverlayPlane(
2894 gfx::OverlayTransform plane_transform
,
2895 unsigned overlay_texture_id
,
2896 const gfx::Rect
& display_bounds
,
2897 const gfx::RectF
& uv_rect
) {
2898 ScheduleOverlayPlaneCHROMIUM(plane_z_order
,
2899 GetGLESOverlayTransform(plane_transform
),
2903 display_bounds
.width(),
2904 display_bounds
.height(),
2911 void GLES2Implementation::OnSwapBuffersComplete() {
2912 if (!swap_buffers_complete_callback_
.is_null())
2913 swap_buffers_complete_callback_
.Run();
2916 GLboolean
GLES2Implementation::EnableFeatureCHROMIUM(
2917 const char* feature
) {
2918 GPU_CLIENT_SINGLE_THREAD_CHECK();
2919 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
2921 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
2922 typedef cmds::EnableFeatureCHROMIUM::Result Result
;
2923 Result
* result
= GetResultAs
<Result
*>();
2928 SetBucketAsCString(kResultBucketId
, feature
);
2929 helper_
->EnableFeatureCHROMIUM(
2930 kResultBucketId
, GetResultShmId(), GetResultShmOffset());
2932 helper_
->SetBucketSize(kResultBucketId
, 0);
2933 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result
));
2937 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
2938 GLuint target
, GLintptr offset
, GLsizeiptr size
, GLenum access
) {
2939 GPU_CLIENT_SINGLE_THREAD_CHECK();
2940 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
2941 << target
<< ", " << offset
<< ", " << size
<< ", "
2942 << GLES2Util::GetStringEnum(access
) << ")");
2943 // NOTE: target is NOT checked because the service will check it
2944 // and we don't know what targets are valid.
2945 if (access
!= GL_WRITE_ONLY
) {
2946 SetGLErrorInvalidEnum(
2947 "glMapBufferSubDataCHROMIUM", access
, "access");
2950 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size
) ||
2951 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset
)) {
2956 unsigned int shm_offset
;
2957 void* mem
= mapped_memory_
->Alloc(size
, &shm_id
, &shm_offset
);
2959 SetGLError(GL_OUT_OF_MEMORY
, "glMapBufferSubDataCHROMIUM", "out of memory");
2963 std::pair
<MappedBufferMap::iterator
, bool> result
=
2964 mapped_buffers_
.insert(std::make_pair(
2967 access
, shm_id
, mem
, shm_offset
, target
, offset
, size
)));
2968 DCHECK(result
.second
);
2969 GPU_CLIENT_LOG(" returned " << mem
);
2973 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem
) {
2974 GPU_CLIENT_SINGLE_THREAD_CHECK();
2976 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem
<< ")");
2977 MappedBufferMap::iterator it
= mapped_buffers_
.find(mem
);
2978 if (it
== mapped_buffers_
.end()) {
2980 GL_INVALID_VALUE
, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
2983 const MappedBuffer
& mb
= it
->second
;
2984 helper_
->BufferSubData(
2985 mb
.target
, mb
.offset
, mb
.size
, mb
.shm_id
, mb
.shm_offset
);
2986 mapped_memory_
->FreePendingToken(mb
.shm_memory
, helper_
->InsertToken());
2987 mapped_buffers_
.erase(it
);
2991 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
3001 GPU_CLIENT_SINGLE_THREAD_CHECK();
3002 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
3003 << target
<< ", " << level
<< ", "
3004 << xoffset
<< ", " << yoffset
<< ", "
3005 << width
<< ", " << height
<< ", "
3006 << GLES2Util::GetStringTextureFormat(format
) << ", "
3007 << GLES2Util::GetStringPixelType(type
) << ", "
3008 << GLES2Util::GetStringEnum(access
) << ")");
3009 if (access
!= GL_WRITE_ONLY
) {
3010 SetGLErrorInvalidEnum(
3011 "glMapTexSubImage2DCHROMIUM", access
, "access");
3014 // NOTE: target is NOT checked because the service will check it
3015 // and we don't know what targets are valid.
3016 if (level
< 0 || xoffset
< 0 || yoffset
< 0 || width
< 0 || height
< 0) {
3018 GL_INVALID_VALUE
, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
3022 if (!GLES2Util::ComputeImageDataSizes(
3023 width
, height
, format
, type
, unpack_alignment_
, &size
, NULL
, NULL
)) {
3025 GL_INVALID_VALUE
, "glMapTexSubImage2DCHROMIUM", "image size too large");
3029 unsigned int shm_offset
;
3030 void* mem
= mapped_memory_
->Alloc(size
, &shm_id
, &shm_offset
);
3032 SetGLError(GL_OUT_OF_MEMORY
, "glMapTexSubImage2DCHROMIUM", "out of memory");
3036 std::pair
<MappedTextureMap::iterator
, bool> result
=
3037 mapped_textures_
.insert(std::make_pair(
3040 access
, shm_id
, mem
, shm_offset
,
3041 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
)));
3042 DCHECK(result
.second
);
3043 GPU_CLIENT_LOG(" returned " << mem
);
3047 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem
) {
3048 GPU_CLIENT_SINGLE_THREAD_CHECK();
3050 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem
<< ")");
3051 MappedTextureMap::iterator it
= mapped_textures_
.find(mem
);
3052 if (it
== mapped_textures_
.end()) {
3054 GL_INVALID_VALUE
, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
3057 const MappedTexture
& mt
= it
->second
;
3058 helper_
->TexSubImage2D(
3059 mt
.target
, mt
.level
, mt
.xoffset
, mt
.yoffset
, mt
.width
, mt
.height
,
3060 mt
.format
, mt
.type
, mt
.shm_id
, mt
.shm_offset
, GL_FALSE
);
3061 mapped_memory_
->FreePendingToken(mt
.shm_memory
, helper_
->InsertToken());
3062 mapped_textures_
.erase(it
);
3066 void GLES2Implementation::ResizeCHROMIUM(GLuint width
, GLuint height
,
3067 float scale_factor
) {
3068 GPU_CLIENT_SINGLE_THREAD_CHECK();
3069 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
3070 << width
<< ", " << height
<< ", " << scale_factor
<< ")");
3071 helper_
->ResizeCHROMIUM(width
, height
, scale_factor
);
3075 const GLchar
* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
3076 GPU_CLIENT_SINGLE_THREAD_CHECK();
3077 GPU_CLIENT_LOG("[" << GetLogPrefix()
3078 << "] glGetRequestableExtensionsCHROMIUM()");
3080 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
3081 const char* result
= NULL
;
3082 // Clear the bucket so if the command fails nothing will be in it.
3083 helper_
->SetBucketSize(kResultBucketId
, 0);
3084 helper_
->GetRequestableExtensionsCHROMIUM(kResultBucketId
);
3086 if (GetBucketAsString(kResultBucketId
, &str
)) {
3087 // The set of requestable extensions shrinks as we enable
3088 // them. Because we don't know when the client will stop referring
3089 // to a previous one it queries (see GetString) we need to cache
3090 // the unique results.
3091 std::set
<std::string
>::const_iterator sit
=
3092 requestable_extensions_set_
.find(str
);
3093 if (sit
!= requestable_extensions_set_
.end()) {
3094 result
= sit
->c_str();
3096 std::pair
<std::set
<std::string
>::const_iterator
, bool> insert_result
=
3097 requestable_extensions_set_
.insert(str
);
3098 DCHECK(insert_result
.second
);
3099 result
= insert_result
.first
->c_str();
3102 GPU_CLIENT_LOG(" returned " << result
);
3103 return reinterpret_cast<const GLchar
*>(result
);
3106 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
3107 // with VirtualGL contexts.
3108 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension
) {
3109 GPU_CLIENT_SINGLE_THREAD_CHECK();
3110 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
3111 << extension
<< ")");
3112 SetBucketAsCString(kResultBucketId
, extension
);
3113 helper_
->RequestExtensionCHROMIUM(kResultBucketId
);
3114 helper_
->SetBucketSize(kResultBucketId
, 0);
3116 struct ExtensionCheck
{
3117 const char* extension
;
3118 ExtensionStatus
* status
;
3120 const ExtensionCheck checks
[] = {
3122 "GL_ANGLE_pack_reverse_row_order",
3123 &angle_pack_reverse_row_order_status_
,
3126 "GL_CHROMIUM_framebuffer_multisample",
3127 &chromium_framebuffer_multisample_
,
3130 const size_t kNumChecks
= sizeof(checks
)/sizeof(checks
[0]);
3131 for (size_t ii
= 0; ii
< kNumChecks
; ++ii
) {
3132 const ExtensionCheck
& check
= checks
[ii
];
3133 if (*check
.status
== kUnavailableExtensionStatus
&&
3134 !strcmp(extension
, check
.extension
)) {
3135 *check
.status
= kUnknownExtensionStatus
;
3140 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
3141 GPU_CLIENT_SINGLE_THREAD_CHECK();
3142 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
3143 // Wait if this would add too many rate limit tokens.
3144 if (rate_limit_tokens_
.size() == kMaxSwapBuffers
) {
3145 helper_
->WaitForToken(rate_limit_tokens_
.front());
3146 rate_limit_tokens_
.pop();
3148 rate_limit_tokens_
.push(helper_
->InsertToken());
3151 void GLES2Implementation::GetMultipleIntegervCHROMIUM(
3152 const GLenum
* pnames
, GLuint count
, GLint
* results
, GLsizeiptr size
) {
3153 GPU_CLIENT_SINGLE_THREAD_CHECK();
3154 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMultipleIntegervCHROMIUM("
3155 << static_cast<const void*>(pnames
) << ", "
3156 << count
<< ", " << results
<< ", "
3158 GPU_CLIENT_LOG_CODE_BLOCK({
3159 for (GLuint i
= 0; i
< count
; ++i
) {
3161 " " << i
<< ": " << GLES2Util::GetStringGLState(pnames
[i
]));
3164 DCHECK(size
>= 0 && FitInt32NonNegative
<GLsizeiptr
>(size
));
3166 GetMultipleIntegervState
state(pnames
, count
, results
, size
);
3167 if (!GetMultipleIntegervSetup(&state
)) {
3170 state
.buffer
= transfer_buffer_
->Alloc(state
.transfer_buffer_size_needed
);
3171 if (!state
.buffer
) {
3172 SetGLError(GL_OUT_OF_MEMORY
, "glGetMultipleIntegervCHROMIUM",
3173 "Transfer buffer allocation failed.");
3176 GetMultipleIntegervRequest(&state
);
3178 GetMultipleIntegervOnCompleted(&state
);
3180 GPU_CLIENT_LOG(" returned");
3181 GPU_CLIENT_LOG_CODE_BLOCK({
3182 for (int i
= 0; i
< state
.num_results
; ++i
) {
3183 GPU_CLIENT_LOG(" " << i
<< ": " << (results
[i
]));
3187 // TODO(gman): We should be able to free without a token.
3188 transfer_buffer_
->FreePendingToken(state
.buffer
, helper_
->InsertToken());
3192 bool GLES2Implementation::GetMultipleIntegervSetup(
3193 GetMultipleIntegervState
* state
) {
3194 state
->num_results
= 0;
3195 for (GLuint ii
= 0; ii
< state
->pnames_count
; ++ii
) {
3196 int num
= util_
.GLGetNumValuesReturned(state
->pnames
[ii
]);
3198 SetGLErrorInvalidEnum(
3199 "glGetMultipleIntegervCHROMIUM", state
->pnames
[ii
], "pname");
3202 state
->num_results
+= num
;
3204 if (static_cast<size_t>(state
->results_size
) !=
3205 state
->num_results
* sizeof(GLint
)) {
3206 SetGLError(GL_INVALID_VALUE
, "glGetMultipleIntegervCHROMIUM", "bad size");
3209 for (int ii
= 0; ii
< state
->num_results
; ++ii
) {
3210 if (state
->results
[ii
] != 0) {
3211 SetGLError(GL_INVALID_VALUE
,
3212 "glGetMultipleIntegervCHROMIUM", "results not set to zero.");
3216 state
->transfer_buffer_size_needed
=
3217 state
->pnames_count
* sizeof(state
->pnames
[0]) +
3218 state
->num_results
* sizeof(state
->results
[0]);
3222 void GLES2Implementation::GetMultipleIntegervRequest(
3223 GetMultipleIntegervState
* state
) {
3224 GLenum
* pnames_buffer
= static_cast<GLenum
*>(state
->buffer
);
3225 state
->results_buffer
= pnames_buffer
+ state
->pnames_count
;
3226 memcpy(pnames_buffer
, state
->pnames
, state
->pnames_count
* sizeof(GLenum
));
3227 memset(state
->results_buffer
, 0, state
->num_results
* sizeof(GLint
));
3228 helper_
->GetMultipleIntegervCHROMIUM(
3229 transfer_buffer_
->GetShmId(),
3230 transfer_buffer_
->GetOffset(pnames_buffer
),
3231 state
->pnames_count
,
3232 transfer_buffer_
->GetShmId(),
3233 transfer_buffer_
->GetOffset(state
->results_buffer
),
3234 state
->results_size
);
3237 void GLES2Implementation::GetMultipleIntegervOnCompleted(
3238 GetMultipleIntegervState
* state
) {
3239 memcpy(state
->results
, state
->results_buffer
, state
->results_size
);;
3242 void GLES2Implementation::GetAllShaderPrecisionFormatsSetup(
3243 GetAllShaderPrecisionFormatsState
* state
) {
3244 state
->transfer_buffer_size_needed
=
3245 state
->precision_params_count
*
3246 sizeof(cmds::GetShaderPrecisionFormat::Result
);
3249 void GLES2Implementation::GetAllShaderPrecisionFormatsRequest(
3250 GetAllShaderPrecisionFormatsState
* state
) {
3251 typedef cmds::GetShaderPrecisionFormat::Result Result
;
3252 Result
* result
= static_cast<Result
*>(state
->results_buffer
);
3254 for (int i
= 0; i
< state
->precision_params_count
; i
++) {
3255 result
->success
= false;
3256 helper_
->GetShaderPrecisionFormat(state
->precision_params
[i
][0],
3257 state
->precision_params
[i
][1],
3258 transfer_buffer_
->GetShmId(),
3259 transfer_buffer_
->GetOffset(result
));
3264 void GLES2Implementation::GetAllShaderPrecisionFormatsOnCompleted(
3265 GetAllShaderPrecisionFormatsState
* state
) {
3266 typedef cmds::GetShaderPrecisionFormat::Result Result
;
3267 Result
* result
= static_cast<Result
*>(state
->results_buffer
);
3269 for (int i
= 0; i
< state
->precision_params_count
; i
++) {
3270 if (result
->success
) {
3271 const GLStaticState::ShaderPrecisionKey
key(
3272 state
->precision_params
[i
][0], state
->precision_params
[i
][1]);
3273 static_state_
.shader_precisions
[key
] = *result
;
3279 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3280 GLuint program
, std::vector
<int8
>* result
) {
3282 // Clear the bucket so if the command fails nothing will be in it.
3283 helper_
->SetBucketSize(kResultBucketId
, 0);
3284 helper_
->GetProgramInfoCHROMIUM(program
, kResultBucketId
);
3285 GetBucketContents(kResultBucketId
, result
);
3288 void GLES2Implementation::GetProgramInfoCHROMIUM(
3289 GLuint program
, GLsizei bufsize
, GLsizei
* size
, void* info
) {
3290 GPU_CLIENT_SINGLE_THREAD_CHECK();
3293 GL_INVALID_VALUE
, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3297 SetGLError(GL_INVALID_VALUE
, "glProgramInfoCHROMIUM", "size is null.");
3300 // Make sure they've set size to 0 else the value will be undefined on
3302 DCHECK_EQ(0, *size
);
3303 std::vector
<int8
> result
;
3304 GetProgramInfoCHROMIUMHelper(program
, &result
);
3305 if (result
.empty()) {
3308 *size
= result
.size();
3312 if (static_cast<size_t>(bufsize
) < result
.size()) {
3313 SetGLError(GL_INVALID_OPERATION
,
3314 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3317 memcpy(info
, &result
[0], result
.size());
3320 GLuint
GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture
) {
3321 GPU_CLIENT_SINGLE_THREAD_CHECK();
3322 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
3324 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
3325 helper_
->CommandBufferHelper::Flush();
3326 return gpu_control_
->CreateStreamTexture(texture
);
3329 void GLES2Implementation::PostSubBufferCHROMIUM(
3330 GLint x
, GLint y
, GLint width
, GLint height
) {
3331 GPU_CLIENT_SINGLE_THREAD_CHECK();
3332 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
3333 << x
<< ", " << y
<< ", " << width
<< ", " << height
<< ")");
3334 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
3335 "width", width
, "height", height
);
3337 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
3338 swap_buffers_tokens_
.push(helper_
->InsertToken());
3339 helper_
->PostSubBufferCHROMIUM(x
, y
, width
, height
);
3340 helper_
->CommandBufferHelper::Flush();
3341 if (swap_buffers_tokens_
.size() > kMaxSwapBuffers
+ 1) {
3342 helper_
->WaitForToken(swap_buffers_tokens_
.front());
3343 swap_buffers_tokens_
.pop();
3347 void GLES2Implementation::DeleteQueriesEXTHelper(
3348 GLsizei n
, const GLuint
* queries
) {
3349 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
3350 query_tracker_
->RemoveQuery(queries
[ii
]);
3351 query_id_allocator_
->FreeID(queries
[ii
]);
3354 helper_
->DeleteQueriesEXTImmediate(n
, queries
);
3357 GLboolean
GLES2Implementation::IsQueryEXT(GLuint id
) {
3358 GPU_CLIENT_SINGLE_THREAD_CHECK();
3359 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id
<< ")");
3361 // TODO(gman): To be spec compliant IDs from other contexts sharing
3362 // resources need to return true here even though you can't share
3363 // queries across contexts?
3364 return query_tracker_
->GetQuery(id
) != NULL
;
3367 void GLES2Implementation::BeginQueryEXT(GLenum target
, GLuint id
) {
3368 GPU_CLIENT_SINGLE_THREAD_CHECK();
3369 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
3370 << GLES2Util::GetStringQueryTarget(target
)
3371 << ", " << id
<< ")");
3373 // if any outstanding queries INV_OP
3374 QueryMap::iterator it
= current_queries_
.find(target
);
3375 if (it
!= current_queries_
.end()) {
3377 GL_INVALID_OPERATION
, "glBeginQueryEXT", "query already in progress");
3383 SetGLError(GL_INVALID_OPERATION
, "glBeginQueryEXT", "id is 0");
3387 // if not GENned INV_OPERATION
3388 if (!query_id_allocator_
->InUse(id
)) {
3389 SetGLError(GL_INVALID_OPERATION
, "glBeginQueryEXT", "invalid id");
3393 // if id does not have an object
3394 QueryTracker::Query
* query
= query_tracker_
->GetQuery(id
);
3396 query
= query_tracker_
->CreateQuery(id
, target
);
3398 SetGLError(GL_OUT_OF_MEMORY
,
3400 "transfer buffer allocation failed");
3403 } else if (query
->target() != target
) {
3405 GL_INVALID_OPERATION
, "glBeginQueryEXT", "target does not match");
3409 current_queries_
[target
] = query
;
3415 void GLES2Implementation::EndQueryEXT(GLenum target
) {
3416 GPU_CLIENT_SINGLE_THREAD_CHECK();
3417 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
3418 << GLES2Util::GetStringQueryTarget(target
) << ")");
3419 // Don't do anything if the context is lost.
3420 if (helper_
->IsContextLost()) {
3424 QueryMap::iterator it
= current_queries_
.find(target
);
3425 if (it
== current_queries_
.end()) {
3426 SetGLError(GL_INVALID_OPERATION
, "glEndQueryEXT", "no active query");
3430 QueryTracker::Query
* query
= it
->second
;
3432 current_queries_
.erase(it
);
3436 void GLES2Implementation::GetQueryivEXT(
3437 GLenum target
, GLenum pname
, GLint
* params
) {
3438 GPU_CLIENT_SINGLE_THREAD_CHECK();
3439 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
3440 << GLES2Util::GetStringQueryTarget(target
) << ", "
3441 << GLES2Util::GetStringQueryParameter(pname
) << ", "
3442 << static_cast<const void*>(params
) << ")");
3444 if (pname
!= GL_CURRENT_QUERY_EXT
) {
3445 SetGLErrorInvalidEnum("glGetQueryivEXT", pname
, "pname");
3448 QueryMap::iterator it
= current_queries_
.find(target
);
3449 if (it
!= current_queries_
.end()) {
3450 QueryTracker::Query
* query
= it
->second
;
3451 *params
= query
->id();
3455 GPU_CLIENT_LOG(" " << *params
);
3459 void GLES2Implementation::GetQueryObjectuivEXT(
3460 GLuint id
, GLenum pname
, GLuint
* params
) {
3461 GPU_CLIENT_SINGLE_THREAD_CHECK();
3462 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id
<< ", "
3463 << GLES2Util::GetStringQueryObjectParameter(pname
) << ", "
3464 << static_cast<const void*>(params
) << ")");
3466 QueryTracker::Query
* query
= query_tracker_
->GetQuery(id
);
3468 SetGLError(GL_INVALID_OPERATION
, "glQueryObjectuivEXT", "unknown query id");
3472 QueryMap::iterator it
= current_queries_
.find(query
->target());
3473 if (it
!= current_queries_
.end()) {
3475 GL_INVALID_OPERATION
,
3476 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
3480 if (query
->NeverUsed()) {
3482 GL_INVALID_OPERATION
,
3483 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
3488 case GL_QUERY_RESULT_EXT
:
3489 if (!query
->CheckResultsAvailable(helper_
)) {
3490 helper_
->WaitForToken(query
->token());
3491 if (!query
->CheckResultsAvailable(helper_
)) {
3493 CHECK(query
->CheckResultsAvailable(helper_
));
3496 *params
= query
->GetResult();
3498 case GL_QUERY_RESULT_AVAILABLE_EXT
:
3499 *params
= query
->CheckResultsAvailable(helper_
);
3502 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname
, "pname");
3505 GPU_CLIENT_LOG(" " << *params
);
3509 void GLES2Implementation::DrawArraysInstancedANGLE(
3510 GLenum mode
, GLint first
, GLsizei count
, GLsizei primcount
) {
3511 GPU_CLIENT_SINGLE_THREAD_CHECK();
3512 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
3513 << GLES2Util::GetStringDrawMode(mode
) << ", "
3514 << first
<< ", " << count
<< ", " << primcount
<< ")");
3516 SetGLError(GL_INVALID_VALUE
, "glDrawArraysInstancedANGLE", "count < 0");
3519 if (primcount
< 0) {
3520 SetGLError(GL_INVALID_VALUE
, "glDrawArraysInstancedANGLE", "primcount < 0");
3523 if (primcount
== 0) {
3526 bool simulated
= false;
3527 if (!vertex_array_object_manager_
->SetupSimulatedClientSideBuffers(
3528 "glDrawArraysInstancedANGLE", this, helper_
, first
+ count
, primcount
,
3532 helper_
->DrawArraysInstancedANGLE(mode
, first
, count
, primcount
);
3533 RestoreArrayBuffer(simulated
);
3537 void GLES2Implementation::DrawElementsInstancedANGLE(
3538 GLenum mode
, GLsizei count
, GLenum type
, const void* indices
,
3539 GLsizei primcount
) {
3540 GPU_CLIENT_SINGLE_THREAD_CHECK();
3541 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
3542 << GLES2Util::GetStringDrawMode(mode
) << ", "
3544 << GLES2Util::GetStringIndexType(type
) << ", "
3545 << static_cast<const void*>(indices
) << ", "
3546 << primcount
<< ")");
3548 SetGLError(GL_INVALID_VALUE
,
3549 "glDrawElementsInstancedANGLE", "count less than 0.");
3555 if (primcount
< 0) {
3556 SetGLError(GL_INVALID_VALUE
,
3557 "glDrawElementsInstancedANGLE", "primcount < 0");
3560 if (primcount
== 0) {
3563 if (vertex_array_object_manager_
->bound_element_array_buffer() != 0 &&
3564 !ValidateOffset("glDrawElementsInstancedANGLE",
3565 reinterpret_cast<GLintptr
>(indices
))) {
3569 bool simulated
= false;
3570 if (!vertex_array_object_manager_
->SetupSimulatedIndexAndClientSideBuffers(
3571 "glDrawElementsInstancedANGLE", this, helper_
, count
, type
, primcount
,
3572 indices
, &offset
, &simulated
)) {
3575 helper_
->DrawElementsInstancedANGLE(mode
, count
, type
, offset
, primcount
);
3576 RestoreElementAndArrayBuffers(simulated
);
3580 void GLES2Implementation::GenMailboxCHROMIUM(
3582 GPU_CLIENT_SINGLE_THREAD_CHECK();
3583 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
3584 << static_cast<const void*>(mailbox
) << ")");
3585 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
3587 gpu::Mailbox result
= gpu::Mailbox::Generate();
3588 memcpy(mailbox
, result
.name
, sizeof(result
.name
));
3591 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target
,
3592 const GLbyte
* data
) {
3593 GPU_CLIENT_SINGLE_THREAD_CHECK();
3594 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
3595 << static_cast<const void*>(data
) << ")");
3596 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
3597 DCHECK(mailbox
.Verify()) << "ProduceTextureCHROMIUM was passed a "
3598 "mailbox that was not generated by "
3599 "GenMailboxCHROMIUM.";
3600 helper_
->ProduceTextureCHROMIUMImmediate(target
, data
);
3604 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
3605 GLuint texture
, GLenum target
, const GLbyte
* data
) {
3606 GPU_CLIENT_SINGLE_THREAD_CHECK();
3607 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
3608 << static_cast<const void*>(data
) << ")");
3609 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
3610 DCHECK(mailbox
.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
3611 "mailbox that was not generated by "
3612 "GenMailboxCHROMIUM.";
3613 helper_
->ProduceTextureDirectCHROMIUMImmediate(texture
, target
, data
);
3617 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target
,
3618 const GLbyte
* data
) {
3619 GPU_CLIENT_SINGLE_THREAD_CHECK();
3620 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
3621 << static_cast<const void*>(data
) << ")");
3622 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
3623 DCHECK(mailbox
.Verify()) << "ConsumeTextureCHROMIUM was passed a "
3624 "mailbox that was not generated by "
3625 "GenMailboxCHROMIUM.";
3626 helper_
->ConsumeTextureCHROMIUMImmediate(target
, data
);
3630 GLuint
GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
3631 GLenum target
, const GLbyte
* data
) {
3632 GPU_CLIENT_SINGLE_THREAD_CHECK();
3633 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
3634 << static_cast<const void*>(data
) << ")");
3635 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
3636 DCHECK(mailbox
.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
3637 "mailbox that was not generated by "
3638 "GenMailboxCHROMIUM.";
3640 GetIdHandler(id_namespaces::kTextures
)->MakeIds(this, 0, 1, &client_id
);
3641 helper_
->CreateAndConsumeTextureCHROMIUMImmediate(target
,
3643 if (share_group_
->bind_generates_resource())
3644 helper_
->CommandBufferHelper::Flush();
3649 void GLES2Implementation::PushGroupMarkerEXT(
3650 GLsizei length
, const GLchar
* marker
) {
3651 GPU_CLIENT_SINGLE_THREAD_CHECK();
3652 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
3653 << length
<< ", " << marker
<< ")");
3659 (length
? std::string(marker
, length
) : std::string(marker
)));
3660 helper_
->PushGroupMarkerEXT(kResultBucketId
);
3661 helper_
->SetBucketSize(kResultBucketId
, 0);
3662 debug_marker_manager_
.PushGroup(
3663 length
? std::string(marker
, length
) : std::string(marker
));
3666 void GLES2Implementation::InsertEventMarkerEXT(
3667 GLsizei length
, const GLchar
* marker
) {
3668 GPU_CLIENT_SINGLE_THREAD_CHECK();
3669 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
3670 << length
<< ", " << marker
<< ")");
3676 (length
? std::string(marker
, length
) : std::string(marker
)));
3677 helper_
->InsertEventMarkerEXT(kResultBucketId
);
3678 helper_
->SetBucketSize(kResultBucketId
, 0);
3679 debug_marker_manager_
.SetMarker(
3680 length
? std::string(marker
, length
) : std::string(marker
));
3683 void GLES2Implementation::PopGroupMarkerEXT() {
3684 GPU_CLIENT_SINGLE_THREAD_CHECK();
3685 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
3686 helper_
->PopGroupMarkerEXT();
3687 debug_marker_manager_
.PopGroup();
3690 void GLES2Implementation::TraceBeginCHROMIUM(const char* name
) {
3691 GPU_CLIENT_SINGLE_THREAD_CHECK();
3692 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
3694 if (current_trace_name_
.get()) {
3695 SetGLError(GL_INVALID_OPERATION
, "glTraceBeginCHROMIUM",
3696 "trace already running");
3699 TRACE_EVENT_COPY_ASYNC_BEGIN0("gpu", name
, this);
3700 SetBucketAsCString(kResultBucketId
, name
);
3701 helper_
->TraceBeginCHROMIUM(kResultBucketId
);
3702 helper_
->SetBucketSize(kResultBucketId
, 0);
3703 current_trace_name_
.reset(new std::string(name
));
3706 void GLES2Implementation::TraceEndCHROMIUM() {
3707 GPU_CLIENT_SINGLE_THREAD_CHECK();
3708 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
3709 if (!current_trace_name_
.get()) {
3710 SetGLError(GL_INVALID_OPERATION
, "glTraceEndCHROMIUM",
3711 "missing begin trace");
3714 helper_
->TraceEndCHROMIUM();
3715 TRACE_EVENT_COPY_ASYNC_END0("gpu", current_trace_name_
->c_str(), this);
3716 current_trace_name_
.reset();
3719 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target
, GLenum access
) {
3720 GPU_CLIENT_SINGLE_THREAD_CHECK();
3721 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
3722 << target
<< ", " << GLES2Util::GetStringEnum(access
) << ")");
3724 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
:
3725 if (access
!= GL_READ_ONLY
) {
3726 SetGLError(GL_INVALID_ENUM
, "glMapBufferCHROMIUM", "bad access mode");
3730 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
:
3731 if (access
!= GL_WRITE_ONLY
) {
3732 SetGLError(GL_INVALID_ENUM
, "glMapBufferCHROMIUM", "bad access mode");
3738 GL_INVALID_ENUM
, "glMapBufferCHROMIUM", "invalid target");
3742 GetBoundPixelTransferBuffer(target
, "glMapBufferCHROMIUM", &buffer_id
);
3746 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
3748 SetGLError(GL_INVALID_OPERATION
, "glMapBufferCHROMIUM", "invalid buffer");
3751 if (buffer
->mapped()) {
3752 SetGLError(GL_INVALID_OPERATION
, "glMapBufferCHROMIUM", "already mapped");
3755 // Here we wait for previous transfer operations to be finished.
3756 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
3757 // with this method of synchronization. Until this is fixed,
3758 // MapBufferCHROMIUM will not block even if the transfer is not ready
3760 if (buffer
->last_usage_token()) {
3761 helper_
->WaitForToken(buffer
->last_usage_token());
3762 buffer
->set_last_usage_token(0);
3764 buffer
->set_mapped(true);
3766 GPU_CLIENT_LOG(" returned " << buffer
->address());
3768 return buffer
->address();
3771 GLboolean
GLES2Implementation::UnmapBufferCHROMIUM(GLuint target
) {
3772 GPU_CLIENT_SINGLE_THREAD_CHECK();
3774 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target
<< ")");
3776 if (!GetBoundPixelTransferBuffer(target
, "glMapBufferCHROMIUM", &buffer_id
)) {
3777 SetGLError(GL_INVALID_ENUM
, "glUnmapBufferCHROMIUM", "invalid target");
3782 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
3784 SetGLError(GL_INVALID_OPERATION
, "glUnmapBufferCHROMIUM", "invalid buffer");
3787 if (!buffer
->mapped()) {
3788 SetGLError(GL_INVALID_OPERATION
, "glUnmapBufferCHROMIUM", "not mapped");
3791 buffer
->set_mapped(false);
3796 bool GLES2Implementation::EnsureAsyncUploadSync() {
3797 if (async_upload_sync_
)
3801 unsigned int shm_offset
;
3802 void* mem
= mapped_memory_
->Alloc(sizeof(AsyncUploadSync
),
3808 async_upload_sync_shm_id_
= shm_id
;
3809 async_upload_sync_shm_offset_
= shm_offset
;
3810 async_upload_sync_
= static_cast<AsyncUploadSync
*>(mem
);
3811 async_upload_sync_
->Reset();
3816 uint32
GLES2Implementation::NextAsyncUploadToken() {
3817 async_upload_token_
++;
3818 if (async_upload_token_
== 0)
3819 async_upload_token_
++;
3820 return async_upload_token_
;
3823 void GLES2Implementation::PollAsyncUploads() {
3824 if (!async_upload_sync_
)
3827 if (helper_
->IsContextLost()) {
3828 DetachedAsyncUploadMemoryList::iterator it
=
3829 detached_async_upload_memory_
.begin();
3830 while (it
!= detached_async_upload_memory_
.end()) {
3831 mapped_memory_
->Free(it
->first
);
3832 it
= detached_async_upload_memory_
.erase(it
);
3837 DetachedAsyncUploadMemoryList::iterator it
=
3838 detached_async_upload_memory_
.begin();
3839 while (it
!= detached_async_upload_memory_
.end()) {
3840 if (HasAsyncUploadTokenPassed(it
->second
)) {
3841 mapped_memory_
->Free(it
->first
);
3842 it
= detached_async_upload_memory_
.erase(it
);
3849 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
3850 // Free all completed unmanaged async uploads buffers.
3853 // Synchronously free rest of the unmanaged async upload buffers.
3854 if (!detached_async_upload_memory_
.empty()) {
3855 WaitAllAsyncTexImage2DCHROMIUM();
3861 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
3862 GLenum target
, GLint level
, GLenum internalformat
, GLsizei width
,
3863 GLsizei height
, GLint border
, GLenum format
, GLenum type
,
3864 const void* pixels
) {
3865 GPU_CLIENT_SINGLE_THREAD_CHECK();
3866 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
3867 << GLES2Util::GetStringTextureTarget(target
) << ", "
3869 << GLES2Util::GetStringTextureInternalFormat(internalformat
) << ", "
3870 << width
<< ", " << height
<< ", " << border
<< ", "
3871 << GLES2Util::GetStringTextureFormat(format
) << ", "
3872 << GLES2Util::GetStringPixelType(type
) << ", "
3873 << static_cast<const void*>(pixels
) << ")");
3874 if (level
< 0 || height
< 0 || width
< 0) {
3875 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "dimension < 0");
3879 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "border != 0");
3883 uint32 unpadded_row_size
;
3884 uint32 padded_row_size
;
3885 if (!GLES2Util::ComputeImageDataSizes(
3886 width
, height
, format
, type
, unpack_alignment_
, &size
,
3887 &unpadded_row_size
, &padded_row_size
)) {
3888 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "image size too large");
3892 // If there's no data/buffer just issue the AsyncTexImage2D
3893 if (!pixels
&& !bound_pixel_unpack_transfer_buffer_id_
) {
3894 helper_
->AsyncTexImage2DCHROMIUM(
3895 target
, level
, internalformat
, width
, height
, format
, type
,
3900 if (!EnsureAsyncUploadSync()) {
3901 SetGLError(GL_OUT_OF_MEMORY
, "glTexImage2D", "out of memory");
3905 // Otherwise, async uploads require a transfer buffer to be bound.
3906 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3907 // the buffer before the transfer is finished. (Currently such
3908 // synchronization has to be handled manually.)
3909 GLuint offset
= ToGLuint(pixels
);
3910 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
3911 bound_pixel_unpack_transfer_buffer_id_
,
3912 "glAsyncTexImage2DCHROMIUM", offset
, size
);
3913 if (buffer
&& buffer
->shm_id() != -1) {
3914 uint32 async_token
= NextAsyncUploadToken();
3915 buffer
->set_last_async_upload_token(async_token
);
3916 helper_
->AsyncTexImage2DCHROMIUM(
3917 target
, level
, internalformat
, width
, height
, format
, type
,
3918 buffer
->shm_id(), buffer
->shm_offset() + offset
,
3920 async_upload_sync_shm_id_
, async_upload_sync_shm_offset_
);
3924 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
3925 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
3926 GLsizei height
, GLenum format
, GLenum type
, const void* pixels
) {
3927 GPU_CLIENT_SINGLE_THREAD_CHECK();
3928 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
3929 << GLES2Util::GetStringTextureTarget(target
) << ", "
3931 << xoffset
<< ", " << yoffset
<< ", "
3932 << width
<< ", " << height
<< ", "
3933 << GLES2Util::GetStringTextureFormat(format
) << ", "
3934 << GLES2Util::GetStringPixelType(type
) << ", "
3935 << static_cast<const void*>(pixels
) << ")");
3936 if (level
< 0 || height
< 0 || width
< 0) {
3938 GL_INVALID_VALUE
, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
3943 uint32 unpadded_row_size
;
3944 uint32 padded_row_size
;
3945 if (!GLES2Util::ComputeImageDataSizes(
3946 width
, height
, format
, type
, unpack_alignment_
, &size
,
3947 &unpadded_row_size
, &padded_row_size
)) {
3949 GL_INVALID_VALUE
, "glAsyncTexSubImage2DCHROMIUM", "size to large");
3953 if (!EnsureAsyncUploadSync()) {
3954 SetGLError(GL_OUT_OF_MEMORY
, "glTexImage2D", "out of memory");
3958 // Async uploads require a transfer buffer to be bound.
3959 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3960 // the buffer before the transfer is finished. (Currently such
3961 // synchronization has to be handled manually.)
3962 GLuint offset
= ToGLuint(pixels
);
3963 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
3964 bound_pixel_unpack_transfer_buffer_id_
,
3965 "glAsyncTexSubImage2DCHROMIUM", offset
, size
);
3966 if (buffer
&& buffer
->shm_id() != -1) {
3967 uint32 async_token
= NextAsyncUploadToken();
3968 buffer
->set_last_async_upload_token(async_token
);
3969 helper_
->AsyncTexSubImage2DCHROMIUM(
3970 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
,
3971 buffer
->shm_id(), buffer
->shm_offset() + offset
,
3973 async_upload_sync_shm_id_
, async_upload_sync_shm_offset_
);
3977 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target
) {
3978 GPU_CLIENT_SINGLE_THREAD_CHECK();
3979 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
3980 << GLES2Util::GetStringTextureTarget(target
) << ")");
3981 helper_
->WaitAsyncTexImage2DCHROMIUM(target
);
3985 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
3986 GPU_CLIENT_SINGLE_THREAD_CHECK();
3987 GPU_CLIENT_LOG("[" << GetLogPrefix()
3988 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
3989 helper_
->WaitAllAsyncTexImage2DCHROMIUM();
3993 GLuint
GLES2Implementation::InsertSyncPointCHROMIUM() {
3994 GPU_CLIENT_SINGLE_THREAD_CHECK();
3995 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
3996 helper_
->CommandBufferHelper::Flush();
3997 return gpu_control_
->InsertSyncPoint();
4000 GLuint
GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
4001 GPU_CLIENT_SINGLE_THREAD_CHECK();
4002 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
4003 DCHECK(capabilities_
.future_sync_points
);
4004 helper_
->CommandBufferHelper::Flush();
4005 return gpu_control_
->InsertFutureSyncPoint();
4008 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point
) {
4009 GPU_CLIENT_SINGLE_THREAD_CHECK();
4010 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
4011 << sync_point
<< ")");
4012 DCHECK(capabilities_
.future_sync_points
);
4013 helper_
->CommandBufferHelper::Flush();
4014 gpu_control_
->RetireSyncPoint(sync_point
);
4017 GLuint
GLES2Implementation::CreateImageCHROMIUMHelper(GLsizei width
,
4019 GLenum internalformat
,
4022 SetGLError(GL_INVALID_VALUE
, "glCreateImageCHROMIUM", "width <= 0");
4027 SetGLError(GL_INVALID_VALUE
, "glCreateImageCHROMIUM", "height <= 0");
4030 // Flush the command stream to ensure ordering in case the newly
4031 // returned image_id has recently been in use with a different buffer.
4032 helper_
->CommandBufferHelper::Flush();
4034 // Create new buffer.
4035 GLuint buffer_id
= gpu_memory_buffer_tracker_
->CreateBuffer(
4036 width
, height
, internalformat
, usage
);
4037 if (buffer_id
== 0) {
4038 SetGLError(GL_OUT_OF_MEMORY
, "glCreateImageCHROMIUM", "out of GPU memory.");
4044 GLuint
GLES2Implementation::CreateImageCHROMIUM(GLsizei width
,
4046 GLenum internalformat
,
4048 GPU_CLIENT_SINGLE_THREAD_CHECK();
4050 "[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
<< ", "
4052 << GLES2Util::GetStringTextureInternalFormat(internalformat
) << ", "
4053 << GLES2Util::GetStringTextureInternalFormat(usage
) << ")");
4055 CreateImageCHROMIUMHelper(width
, height
, internalformat
, usage
);
4060 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id
) {
4061 gfx::GpuMemoryBuffer
* gpu_buffer
= gpu_memory_buffer_tracker_
->GetBuffer(
4064 SetGLError(GL_INVALID_OPERATION
, "glDestroyImageCHROMIUM", "invalid image");
4068 // Flush the command stream to make sure all pending commands
4069 // that may refer to the image_id are executed on the service side.
4070 helper_
->CommandBufferHelper::Flush();
4071 gpu_memory_buffer_tracker_
->RemoveBuffer(image_id
);
4074 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id
) {
4075 GPU_CLIENT_SINGLE_THREAD_CHECK();
4076 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
4077 << image_id
<< ")");
4078 DestroyImageCHROMIUMHelper(image_id
);
4082 void GLES2Implementation::UnmapImageCHROMIUMHelper(GLuint image_id
) {
4083 gfx::GpuMemoryBuffer
* gpu_buffer
= gpu_memory_buffer_tracker_
->GetBuffer(
4086 SetGLError(GL_INVALID_OPERATION
, "glUnmapImageCHROMIUM", "invalid image");
4090 if (!gpu_buffer
->IsMapped()) {
4091 SetGLError(GL_INVALID_OPERATION
, "glUnmapImageCHROMIUM", "not mapped");
4094 gpu_buffer
->Unmap();
4097 void GLES2Implementation::UnmapImageCHROMIUM(GLuint image_id
) {
4098 GPU_CLIENT_SINGLE_THREAD_CHECK();
4099 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapImageCHROMIUM("
4100 << image_id
<< ")");
4102 UnmapImageCHROMIUMHelper(image_id
);
4106 void* GLES2Implementation::MapImageCHROMIUMHelper(GLuint image_id
) {
4107 gfx::GpuMemoryBuffer
* gpu_buffer
= gpu_memory_buffer_tracker_
->GetBuffer(
4110 SetGLError(GL_INVALID_OPERATION
, "glMapImageCHROMIUM", "invalid image");
4114 if (gpu_buffer
->IsMapped()) {
4115 SetGLError(GL_INVALID_OPERATION
, "glMapImageCHROMIUM", "already mapped");
4119 return gpu_buffer
->Map();
4122 void* GLES2Implementation::MapImageCHROMIUM(GLuint image_id
) {
4123 GPU_CLIENT_SINGLE_THREAD_CHECK();
4124 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapImageCHROMIUM(" << image_id
4127 void* mapped
= MapImageCHROMIUMHelper(image_id
);
4132 void GLES2Implementation::GetImageParameterivCHROMIUMHelper(
4133 GLuint image_id
, GLenum pname
, GLint
* params
) {
4134 if (pname
!= GL_IMAGE_ROWBYTES_CHROMIUM
) {
4135 SetGLError(GL_INVALID_ENUM
, "glGetImageParameterivCHROMIUM",
4136 "invalid parameter");
4140 gfx::GpuMemoryBuffer
* gpu_buffer
= gpu_memory_buffer_tracker_
->GetBuffer(
4143 SetGLError(GL_INVALID_OPERATION
, "glGetImageParameterivCHROMIUM",
4148 if (!gpu_buffer
->IsMapped()) {
4150 GL_INVALID_OPERATION
, "glGetImageParameterivCHROMIUM", "not mapped");
4154 *params
= gpu_buffer
->GetStride();
4157 void GLES2Implementation::GetImageParameterivCHROMIUM(
4158 GLuint image_id
, GLenum pname
, GLint
* params
) {
4159 GPU_CLIENT_SINGLE_THREAD_CHECK();
4160 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint
, params
);
4161 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glImageParameterivCHROMIUM("
4163 << GLES2Util::GetStringBufferParameter(pname
) << ", "
4164 << static_cast<const void*>(params
) << ")");
4165 GetImageParameterivCHROMIUMHelper(image_id
, pname
, params
);
4169 bool GLES2Implementation::ValidateSize(const char* func
, GLsizeiptr size
) {
4171 SetGLError(GL_INVALID_VALUE
, func
, "size < 0");
4174 if (!FitInt32NonNegative
<GLsizeiptr
>(size
)) {
4175 SetGLError(GL_INVALID_OPERATION
, func
, "size more than 32-bit");
4181 bool GLES2Implementation::ValidateOffset(const char* func
, GLintptr offset
) {
4183 SetGLError(GL_INVALID_VALUE
, func
, "offset < 0");
4186 if (!FitInt32NonNegative
<GLintptr
>(offset
)) {
4187 SetGLError(GL_INVALID_OPERATION
, func
, "offset more than 32-bit");
4193 // Include the auto-generated part of this file. We split this because it means
4194 // we can easily edit the non-auto generated parts right here in this file
4195 // instead of having to edit some template or the code generator.
4196 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
4198 } // namespace gles2