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/program_info_manager.h"
22 #include "gpu/command_buffer/client/query_tracker.h"
23 #include "gpu/command_buffer/client/transfer_buffer.h"
24 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
25 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
26 #include "gpu/command_buffer/common/trace_event.h"
28 #if defined(GPU_CLIENT_DEBUG)
29 #include "base/command_line.h"
30 #include "gpu/command_buffer/client/gpu_switches.h"
36 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
37 static GLuint
ToGLuint(const void* ptr
) {
38 return static_cast<GLuint
>(reinterpret_cast<size_t>(ptr
));
41 #if !defined(_MSC_VER)
42 const size_t GLES2Implementation::kMaxSizeOfSimpleResult
;
43 const unsigned int GLES2Implementation::kStartingOffset
;
46 GLES2Implementation::GLStaticState::GLStaticState() {
49 GLES2Implementation::GLStaticState::~GLStaticState() {
52 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
53 GLES2Implementation
* gles2_implementation
)
54 : gles2_implementation_(gles2_implementation
) {
55 CHECK_EQ(0, gles2_implementation_
->use_count_
);
56 ++gles2_implementation_
->use_count_
;
59 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
60 --gles2_implementation_
->use_count_
;
61 CHECK_EQ(0, gles2_implementation_
->use_count_
);
64 GLES2Implementation::GLES2Implementation(
65 GLES2CmdHelper
* helper
,
66 ShareGroup
* share_group
,
67 TransferBufferInterface
* transfer_buffer
,
68 bool bind_generates_resource
,
69 bool lose_context_when_out_of_memory
,
70 bool support_client_side_arrays
,
71 GpuControl
* gpu_control
)
73 transfer_buffer_(transfer_buffer
),
74 angle_pack_reverse_row_order_status_(kUnknownExtensionStatus
),
75 chromium_framebuffer_multisample_(kUnknownExtensionStatus
),
78 unpack_flip_y_(false),
79 unpack_row_length_(0),
81 unpack_skip_pixels_(0),
82 pack_reverse_row_order_(false),
83 active_texture_unit_(0),
84 bound_framebuffer_(0),
85 bound_read_framebuffer_(0),
86 bound_renderbuffer_(0),
87 bound_valuebuffer_(0),
89 bound_array_buffer_id_(0),
90 bound_pixel_pack_transfer_buffer_id_(0),
91 bound_pixel_unpack_transfer_buffer_id_(0),
92 async_upload_token_(0),
93 async_upload_sync_(NULL
),
94 async_upload_sync_shm_id_(0),
95 async_upload_sync_shm_offset_(0),
98 lose_context_when_out_of_memory_(lose_context_when_out_of_memory
),
99 support_client_side_arrays_(support_client_side_arrays
),
101 error_message_callback_(NULL
),
102 gpu_control_(gpu_control
),
103 capabilities_(gpu_control
->GetCapabilities()),
104 weak_ptr_factory_(this) {
106 DCHECK(transfer_buffer
);
109 std::stringstream ss
;
110 ss
<< std::hex
<< this;
111 this_in_hex_
= ss
.str();
113 GPU_CLIENT_LOG_CODE_BLOCK({
114 debug_
= CommandLine::ForCurrentProcess()->HasSwitch(
115 switches::kEnableGPUClientLogging
);
119 (share_group
? share_group
: new ShareGroup(bind_generates_resource
));
120 DCHECK(share_group_
->bind_generates_resource() == bind_generates_resource
);
122 memset(&reserved_ids_
, 0, sizeof(reserved_ids_
));
125 bool GLES2Implementation::Initialize(
126 unsigned int starting_transfer_buffer_size
,
127 unsigned int min_transfer_buffer_size
,
128 unsigned int max_transfer_buffer_size
,
129 unsigned int mapped_memory_limit
) {
130 TRACE_EVENT0("gpu", "GLES2Implementation::Initialize");
131 DCHECK_GE(starting_transfer_buffer_size
, min_transfer_buffer_size
);
132 DCHECK_LE(starting_transfer_buffer_size
, max_transfer_buffer_size
);
133 DCHECK_GE(min_transfer_buffer_size
, kStartingOffset
);
135 if (!transfer_buffer_
->Initialize(
136 starting_transfer_buffer_size
,
138 min_transfer_buffer_size
,
139 max_transfer_buffer_size
,
145 mapped_memory_
.reset(
146 new MappedMemoryManager(
148 base::Bind(&GLES2Implementation::PollAsyncUploads
,
149 // The mapped memory manager is owned by |this| here, and
150 // since its destroyed before before we destroy ourselves
151 // we don't need extra safety measures for this closure.
152 base::Unretained(this)),
153 mapped_memory_limit
));
155 unsigned chunk_size
= 2 * 1024 * 1024;
156 if (mapped_memory_limit
!= kNoLimit
) {
157 // Use smaller chunks if the client is very memory conscientious.
158 chunk_size
= std::min(mapped_memory_limit
/ 4, chunk_size
);
160 mapped_memory_
->set_chunk_size_multiple(chunk_size
);
162 GLStaticState::ShaderPrecisionMap
* shader_precisions
=
163 &static_state_
.shader_precisions
;
164 capabilities_
.VisitPrecisions([shader_precisions
](
165 GLenum shader
, GLenum type
, Capabilities::ShaderPrecision
* result
) {
166 const GLStaticState::ShaderPrecisionKey
key(shader
, type
);
167 cmds::GetShaderPrecisionFormat::Result cached_result
= {
168 true, result
->min_range
, result
->max_range
, result
->precision
};
169 shader_precisions
->insert(std::make_pair(key
, cached_result
));
172 util_
.set_num_compressed_texture_formats(
173 capabilities_
.num_compressed_texture_formats
);
174 util_
.set_num_shader_binary_formats(capabilities_
.num_shader_binary_formats
);
176 texture_units_
.reset(
177 new TextureUnit
[capabilities_
.max_combined_texture_image_units
]);
179 query_tracker_
.reset(new QueryTracker(mapped_memory_
.get()));
180 buffer_tracker_
.reset(new BufferTracker(mapped_memory_
.get()));
182 query_id_allocator_
.reset(new IdAllocator());
183 if (support_client_side_arrays_
) {
184 GetIdHandler(id_namespaces::kBuffers
)->MakeIds(
185 this, kClientSideArrayId
, arraysize(reserved_ids_
), &reserved_ids_
[0]);
188 vertex_array_object_manager_
.reset(new VertexArrayObjectManager(
189 capabilities_
.max_vertex_attribs
, reserved_ids_
[0], reserved_ids_
[1],
190 support_client_side_arrays_
));
192 // GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
193 // on Client & Service.
194 if (capabilities_
.bind_generates_resource_chromium
!=
195 (share_group_
->bind_generates_resource() ? 1 : 0)) {
196 SetGLError(GL_INVALID_OPERATION
,
198 "Service bind_generates_resource mismatch.");
205 GLES2Implementation::~GLES2Implementation() {
206 // Make sure the queries are finished otherwise we'll delete the
207 // shared memory (mapped_memory_) which will free the memory used
208 // by the queries. The GPU process when validating that memory is still
209 // shared will fail and abort (ie, it will stop running).
211 query_tracker_
.reset();
213 if (support_client_side_arrays_
)
214 DeleteBuffers(arraysize(reserved_ids_
), &reserved_ids_
[0]);
216 // Release any per-context data in share group.
217 share_group_
->FreeContext(this);
219 buffer_tracker_
.reset();
221 FreeAllAsyncUploadBuffers();
223 if (async_upload_sync_
) {
224 mapped_memory_
->Free(async_upload_sync_
);
225 async_upload_sync_
= NULL
;
228 // Make sure the commands make it the service.
232 GLES2CmdHelper
* GLES2Implementation::helper() const {
236 IdHandlerInterface
* GLES2Implementation::GetIdHandler(int namespace_id
) const {
237 return share_group_
->GetIdHandler(namespace_id
);
240 IdAllocator
* GLES2Implementation::GetIdAllocator(int namespace_id
) const {
241 if (namespace_id
== id_namespaces::kQueries
)
242 return query_id_allocator_
.get();
247 void* GLES2Implementation::GetResultBuffer() {
248 return transfer_buffer_
->GetResultBuffer();
251 int32
GLES2Implementation::GetResultShmId() {
252 return transfer_buffer_
->GetShmId();
255 uint32
GLES2Implementation::GetResultShmOffset() {
256 return transfer_buffer_
->GetResultOffset();
259 void GLES2Implementation::FreeUnusedSharedMemory() {
260 mapped_memory_
->FreeUnused();
263 void GLES2Implementation::FreeEverything() {
264 FreeAllAsyncUploadBuffers();
266 query_tracker_
->Shrink();
267 FreeUnusedSharedMemory();
268 transfer_buffer_
->Free();
269 helper_
->FreeRingBuffer();
272 void GLES2Implementation::RunIfContextNotLost(const base::Closure
& callback
) {
273 if (!helper_
->IsContextLost())
277 void GLES2Implementation::SignalSyncPoint(uint32 sync_point
,
278 const base::Closure
& callback
) {
279 gpu_control_
->SignalSyncPoint(
281 base::Bind(&GLES2Implementation::RunIfContextNotLost
,
282 weak_ptr_factory_
.GetWeakPtr(),
286 void GLES2Implementation::SignalQuery(uint32 query
,
287 const base::Closure
& callback
) {
288 // Flush previously entered commands to ensure ordering with any
289 // glBeginQueryEXT() calls that may have been put into the context.
290 ShallowFlushCHROMIUM();
291 gpu_control_
->SignalQuery(
293 base::Bind(&GLES2Implementation::RunIfContextNotLost
,
294 weak_ptr_factory_
.GetWeakPtr(),
298 void GLES2Implementation::SetSurfaceVisible(bool visible
) {
300 "gpu", "GLES2Implementation::SetSurfaceVisible", "visible", visible
);
301 // TODO(piman): This probably should be ShallowFlushCHROMIUM().
303 gpu_control_
->SetSurfaceVisible(visible
);
308 void GLES2Implementation::WaitForCmd() {
309 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
310 helper_
->CommandBufferHelper::Finish();
313 bool GLES2Implementation::IsExtensionAvailable(const char* ext
) {
314 const char* extensions
=
315 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS
));
319 int length
= strlen(ext
);
321 int n
= strcspn(extensions
, " ");
322 if (n
== length
&& 0 == strncmp(ext
, extensions
, length
)) {
325 if ('\0' == extensions
[n
]) {
332 bool GLES2Implementation::IsExtensionAvailableHelper(
333 const char* extension
, ExtensionStatus
* status
) {
335 case kAvailableExtensionStatus
:
337 case kUnavailableExtensionStatus
:
340 bool available
= IsExtensionAvailable(extension
);
341 *status
= available
? kAvailableExtensionStatus
:
342 kUnavailableExtensionStatus
;
348 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
349 return IsExtensionAvailableHelper(
350 "GL_ANGLE_pack_reverse_row_order",
351 &angle_pack_reverse_row_order_status_
);
354 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
355 return IsExtensionAvailableHelper(
356 "GL_CHROMIUM_framebuffer_multisample",
357 &chromium_framebuffer_multisample_
);
360 const std::string
& GLES2Implementation::GetLogPrefix() const {
361 const std::string
& prefix(debug_marker_manager_
.GetMarker());
362 return prefix
.empty() ? this_in_hex_
: prefix
;
365 GLenum
GLES2Implementation::GetError() {
366 GPU_CLIENT_SINGLE_THREAD_CHECK();
367 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
368 GLenum err
= GetGLError();
369 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err
));
373 GLenum
GLES2Implementation::GetClientSideGLError() {
374 if (error_bits_
== 0) {
378 GLenum error
= GL_NO_ERROR
;
379 for (uint32 mask
= 1; mask
!= 0; mask
= mask
<< 1) {
380 if ((error_bits_
& mask
) != 0) {
381 error
= GLES2Util::GLErrorBitToGLError(mask
);
385 error_bits_
&= ~GLES2Util::GLErrorToErrorBit(error
);
389 GLenum
GLES2Implementation::GetGLError() {
390 TRACE_EVENT0("gpu", "GLES2::GetGLError");
391 // Check the GL error first, then our wrapped error.
392 typedef cmds::GetError::Result Result
;
393 Result
* result
= GetResultAs
<Result
*>();
394 // If we couldn't allocate a result the context is lost.
398 *result
= GL_NO_ERROR
;
399 helper_
->GetError(GetResultShmId(), GetResultShmOffset());
401 GLenum error
= *result
;
402 if (error
== GL_NO_ERROR
) {
403 error
= GetClientSideGLError();
405 // There was an error, clear the corresponding wrapped error.
406 error_bits_
&= ~GLES2Util::GLErrorToErrorBit(error
);
411 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
412 void GLES2Implementation::FailGLError(GLenum error
) {
413 if (error
!= GL_NO_ERROR
) {
414 NOTREACHED() << "Error";
417 // NOTE: Calling GetGLError overwrites data in the result buffer.
418 void GLES2Implementation::CheckGLError() {
419 FailGLError(GetGLError());
421 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
423 void GLES2Implementation::SetGLError(
424 GLenum error
, const char* function_name
, const char* msg
) {
425 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
426 << GLES2Util::GetStringError(error
) << ": "
427 << function_name
<< ": " << msg
);
432 if (error_message_callback_
) {
433 std::string
temp(GLES2Util::GetStringError(error
) + " : " +
434 function_name
+ ": " + (msg
? msg
: ""));
435 error_message_callback_
->OnErrorMessage(temp
.c_str(), 0);
437 error_bits_
|= GLES2Util::GLErrorToErrorBit(error
);
439 if (error
== GL_OUT_OF_MEMORY
&& lose_context_when_out_of_memory_
) {
440 helper_
->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
441 GL_UNKNOWN_CONTEXT_RESET_ARB
);
445 void GLES2Implementation::SetGLErrorInvalidEnum(
446 const char* function_name
, GLenum value
, const char* label
) {
447 SetGLError(GL_INVALID_ENUM
, function_name
,
448 (std::string(label
) + " was " +
449 GLES2Util::GetStringEnum(value
)).c_str());
452 bool GLES2Implementation::GetBucketContents(uint32 bucket_id
,
453 std::vector
<int8
>* data
) {
454 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
456 const uint32 kStartSize
= 32 * 1024;
457 ScopedTransferBufferPtr
buffer(kStartSize
, helper_
, transfer_buffer_
);
458 if (!buffer
.valid()) {
461 typedef cmd::GetBucketStart::Result Result
;
462 Result
* result
= GetResultAs
<Result
*>();
467 helper_
->GetBucketStart(
468 bucket_id
, GetResultShmId(), GetResultShmOffset(),
469 buffer
.size(), buffer
.shm_id(), buffer
.offset());
471 uint32 size
= *result
;
476 if (!buffer
.valid()) {
478 if (!buffer
.valid()) {
481 helper_
->GetBucketData(
482 bucket_id
, offset
, buffer
.size(), buffer
.shm_id(), buffer
.offset());
485 uint32 size_to_copy
= std::min(size
, buffer
.size());
486 memcpy(&(*data
)[offset
], buffer
.address(), size_to_copy
);
487 offset
+= size_to_copy
;
488 size
-= size_to_copy
;
491 // Free the bucket. This is not required but it does free up the memory.
492 // and we don't have to wait for the result so from the client's perspective
494 helper_
->SetBucketSize(bucket_id
, 0);
499 void GLES2Implementation::SetBucketContents(
500 uint32 bucket_id
, const void* data
, size_t size
) {
502 helper_
->SetBucketSize(bucket_id
, size
);
506 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
507 if (!buffer
.valid()) {
510 memcpy(buffer
.address(), static_cast<const int8
*>(data
) + offset
,
512 helper_
->SetBucketData(
513 bucket_id
, offset
, buffer
.size(), buffer
.shm_id(), buffer
.offset());
514 offset
+= buffer
.size();
515 size
-= buffer
.size();
520 void GLES2Implementation::SetBucketAsCString(
521 uint32 bucket_id
, const char* str
) {
522 // NOTE: strings are passed NULL terminated. That means the empty
523 // string will have a size of 1 and no-string will have a size of 0
525 SetBucketContents(bucket_id
, str
, strlen(str
) + 1);
527 helper_
->SetBucketSize(bucket_id
, 0);
531 bool GLES2Implementation::GetBucketAsString(
532 uint32 bucket_id
, std::string
* str
) {
534 std::vector
<int8
> data
;
535 // NOTE: strings are passed NULL terminated. That means the empty
536 // string will have a size of 1 and no-string will have a size of 0
537 if (!GetBucketContents(bucket_id
, &data
)) {
543 str
->assign(&data
[0], &data
[0] + data
.size() - 1);
547 void GLES2Implementation::SetBucketAsString(
548 uint32 bucket_id
, const std::string
& str
) {
549 // NOTE: strings are passed NULL terminated. That means the empty
550 // string will have a size of 1 and no-string will have a size of 0
551 SetBucketContents(bucket_id
, str
.c_str(), str
.size() + 1);
554 void GLES2Implementation::Disable(GLenum cap
) {
555 GPU_CLIENT_SINGLE_THREAD_CHECK();
556 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
557 << GLES2Util::GetStringCapability(cap
) << ")");
558 bool changed
= false;
559 if (!state_
.SetCapabilityState(cap
, false, &changed
) || changed
) {
560 helper_
->Disable(cap
);
565 void GLES2Implementation::Enable(GLenum cap
) {
566 GPU_CLIENT_SINGLE_THREAD_CHECK();
567 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
568 << GLES2Util::GetStringCapability(cap
) << ")");
569 bool changed
= false;
570 if (!state_
.SetCapabilityState(cap
, true, &changed
) || changed
) {
571 helper_
->Enable(cap
);
576 GLboolean
GLES2Implementation::IsEnabled(GLenum cap
) {
577 GPU_CLIENT_SINGLE_THREAD_CHECK();
578 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
579 << GLES2Util::GetStringCapability(cap
) << ")");
581 if (!state_
.GetEnabled(cap
, &state
)) {
582 typedef cmds::IsEnabled::Result Result
;
583 Result
* result
= GetResultAs
<Result
*>();
588 helper_
->IsEnabled(cap
, GetResultShmId(), GetResultShmOffset());
590 state
= (*result
) != 0;
593 GPU_CLIENT_LOG("returned " << state
);
598 bool GLES2Implementation::GetHelper(GLenum pname
, GLint
* params
) {
600 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
:
601 *params
= capabilities_
.max_combined_texture_image_units
;
603 case GL_MAX_CUBE_MAP_TEXTURE_SIZE
:
604 *params
= capabilities_
.max_cube_map_texture_size
;
606 case GL_MAX_FRAGMENT_UNIFORM_VECTORS
:
607 *params
= capabilities_
.max_fragment_uniform_vectors
;
609 case GL_MAX_RENDERBUFFER_SIZE
:
610 *params
= capabilities_
.max_renderbuffer_size
;
612 case GL_MAX_TEXTURE_IMAGE_UNITS
:
613 *params
= capabilities_
.max_texture_image_units
;
615 case GL_MAX_TEXTURE_SIZE
:
616 *params
= capabilities_
.max_texture_size
;
618 case GL_MAX_VARYING_VECTORS
:
619 *params
= capabilities_
.max_varying_vectors
;
621 case GL_MAX_VERTEX_ATTRIBS
:
622 *params
= capabilities_
.max_vertex_attribs
;
624 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
:
625 *params
= capabilities_
.max_vertex_texture_image_units
;
627 case GL_MAX_VERTEX_UNIFORM_VECTORS
:
628 *params
= capabilities_
.max_vertex_uniform_vectors
;
630 case GL_NUM_COMPRESSED_TEXTURE_FORMATS
:
631 *params
= capabilities_
.num_compressed_texture_formats
;
633 case GL_NUM_SHADER_BINARY_FORMATS
:
634 *params
= capabilities_
.num_shader_binary_formats
;
636 case GL_ARRAY_BUFFER_BINDING
:
637 if (share_group_
->bind_generates_resource()) {
638 *params
= bound_array_buffer_id_
;
642 case GL_ELEMENT_ARRAY_BUFFER_BINDING
:
643 if (share_group_
->bind_generates_resource()) {
645 vertex_array_object_manager_
->bound_element_array_buffer();
649 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM
:
650 *params
= bound_pixel_pack_transfer_buffer_id_
;
652 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM
:
653 *params
= bound_pixel_unpack_transfer_buffer_id_
;
655 case GL_ACTIVE_TEXTURE
:
656 *params
= active_texture_unit_
+ GL_TEXTURE0
;
658 case GL_TEXTURE_BINDING_2D
:
659 if (share_group_
->bind_generates_resource()) {
660 *params
= texture_units_
[active_texture_unit_
].bound_texture_2d
;
664 case GL_TEXTURE_BINDING_CUBE_MAP
:
665 if (share_group_
->bind_generates_resource()) {
666 *params
= texture_units_
[active_texture_unit_
].bound_texture_cube_map
;
670 case GL_TEXTURE_BINDING_EXTERNAL_OES
:
671 if (share_group_
->bind_generates_resource()) {
673 texture_units_
[active_texture_unit_
].bound_texture_external_oes
;
677 case GL_FRAMEBUFFER_BINDING
:
678 if (share_group_
->bind_generates_resource()) {
679 *params
= bound_framebuffer_
;
683 case GL_READ_FRAMEBUFFER_BINDING
:
684 if (IsChromiumFramebufferMultisampleAvailable() &&
685 share_group_
->bind_generates_resource()) {
686 *params
= bound_read_framebuffer_
;
690 case GL_RENDERBUFFER_BINDING
:
691 if (share_group_
->bind_generates_resource()) {
692 *params
= bound_renderbuffer_
;
701 bool GLES2Implementation::GetBooleanvHelper(GLenum pname
, GLboolean
* params
) {
702 // TODO(gman): Make this handle pnames that return more than 1 value.
704 if (!GetHelper(pname
, &value
)) {
707 *params
= static_cast<GLboolean
>(value
);
711 bool GLES2Implementation::GetFloatvHelper(GLenum pname
, GLfloat
* params
) {
712 // TODO(gman): Make this handle pnames that return more than 1 value.
714 if (!GetHelper(pname
, &value
)) {
717 *params
= static_cast<GLfloat
>(value
);
721 bool GLES2Implementation::GetIntegervHelper(GLenum pname
, GLint
* params
) {
722 return GetHelper(pname
, params
);
725 GLuint
GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
726 GLuint buffer_id
, GLsizei count
, GLenum type
, GLuint offset
) {
727 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result
;
728 Result
* result
= GetResultAs
<Result
*>();
733 helper_
->GetMaxValueInBufferCHROMIUM(
734 buffer_id
, count
, type
, offset
, GetResultShmId(), GetResultShmOffset());
739 GLuint
GLES2Implementation::GetMaxValueInBufferCHROMIUM(
740 GLuint buffer_id
, GLsizei count
, GLenum type
, GLuint offset
) {
741 GPU_CLIENT_SINGLE_THREAD_CHECK();
742 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
743 << buffer_id
<< ", " << count
<< ", "
744 << GLES2Util::GetStringGetMaxIndexType(type
)
745 << ", " << offset
<< ")");
746 GLuint result
= GetMaxValueInBufferCHROMIUMHelper(
747 buffer_id
, count
, type
, offset
);
748 GPU_CLIENT_LOG("returned " << result
);
753 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore
) {
755 RestoreArrayBuffer(restore
);
756 // Restore the element array binding.
757 // We only need to restore it if it wasn't a client side array.
758 if (vertex_array_object_manager_
->bound_element_array_buffer() == 0) {
759 helper_
->BindBuffer(GL_ELEMENT_ARRAY_BUFFER
, 0);
764 void GLES2Implementation::RestoreArrayBuffer(bool restore
) {
766 // Restore the user's current binding.
767 helper_
->BindBuffer(GL_ARRAY_BUFFER
, bound_array_buffer_id_
);
771 void GLES2Implementation::DrawElements(
772 GLenum mode
, GLsizei count
, GLenum type
, const void* indices
) {
773 GPU_CLIENT_SINGLE_THREAD_CHECK();
774 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
775 << GLES2Util::GetStringDrawMode(mode
) << ", "
777 << GLES2Util::GetStringIndexType(type
) << ", "
778 << static_cast<const void*>(indices
) << ")");
780 SetGLError(GL_INVALID_VALUE
, "glDrawElements", "count less than 0.");
786 if (vertex_array_object_manager_
->bound_element_array_buffer() != 0 &&
787 !ValidateOffset("glDrawElements", reinterpret_cast<GLintptr
>(indices
))) {
791 bool simulated
= false;
792 if (!vertex_array_object_manager_
->SetupSimulatedIndexAndClientSideBuffers(
793 "glDrawElements", this, helper_
, count
, type
, 0, indices
,
794 &offset
, &simulated
)) {
797 helper_
->DrawElements(mode
, count
, type
, offset
);
798 RestoreElementAndArrayBuffers(simulated
);
802 void GLES2Implementation::Flush() {
803 GPU_CLIENT_SINGLE_THREAD_CHECK();
804 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
805 // Insert the cmd to call glFlush
807 // Flush our command buffer
808 // (tell the service to execute up to the flush cmd.)
809 helper_
->CommandBufferHelper::Flush();
812 void GLES2Implementation::ShallowFlushCHROMIUM() {
813 GPU_CLIENT_SINGLE_THREAD_CHECK();
814 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
815 // Flush our command buffer
816 // (tell the service to execute up to the flush cmd.)
817 helper_
->CommandBufferHelper::Flush();
818 // TODO(piman): Add the FreeEverything() logic here.
821 void GLES2Implementation::Finish() {
822 GPU_CLIENT_SINGLE_THREAD_CHECK();
826 void GLES2Implementation::ShallowFinishCHROMIUM() {
827 GPU_CLIENT_SINGLE_THREAD_CHECK();
828 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
829 // Flush our command buffer (tell the service to execute up to the flush cmd
830 // and don't return until it completes).
831 helper_
->CommandBufferHelper::Finish();
834 void GLES2Implementation::FinishHelper() {
835 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
836 TRACE_EVENT0("gpu", "GLES2::Finish");
837 // Insert the cmd to call glFinish
839 // Finish our command buffer
840 // (tell the service to execute up to the Finish cmd and wait for it to
842 helper_
->CommandBufferHelper::Finish();
845 void GLES2Implementation::SwapBuffers() {
846 GPU_CLIENT_SINGLE_THREAD_CHECK();
847 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
848 // TODO(piman): Strictly speaking we'd want to insert the token after the
849 // swap, but the state update with the updated token might not have happened
850 // by the time the SwapBuffer callback gets called, forcing us to synchronize
851 // with the GPU process more than needed. So instead, make it happen before.
852 // All it means is that we could be slightly looser on the kMaxSwapBuffers
853 // semantics if the client doesn't use the callback mechanism, and by chance
854 // the scheduler yields between the InsertToken and the SwapBuffers.
855 swap_buffers_tokens_
.push(helper_
->InsertToken());
856 helper_
->SwapBuffers();
857 helper_
->CommandBufferHelper::Flush();
858 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
859 // compensate for TODO above.
860 if (swap_buffers_tokens_
.size() > kMaxSwapBuffers
+ 1) {
861 helper_
->WaitForToken(swap_buffers_tokens_
.front());
862 swap_buffers_tokens_
.pop();
866 void GLES2Implementation::BindAttribLocation(
867 GLuint program
, GLuint index
, const char* name
) {
868 GPU_CLIENT_SINGLE_THREAD_CHECK();
869 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
870 << program
<< ", " << index
<< ", " << name
<< ")");
871 SetBucketAsString(kResultBucketId
, name
);
872 helper_
->BindAttribLocationBucket(program
, index
, kResultBucketId
);
873 helper_
->SetBucketSize(kResultBucketId
, 0);
877 void GLES2Implementation::BindUniformLocationCHROMIUM(
878 GLuint program
, GLint location
, const char* name
) {
879 GPU_CLIENT_SINGLE_THREAD_CHECK();
880 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
881 << program
<< ", " << location
<< ", " << name
<< ")");
882 SetBucketAsString(kResultBucketId
, name
);
883 helper_
->BindUniformLocationCHROMIUMBucket(
884 program
, location
, kResultBucketId
);
885 helper_
->SetBucketSize(kResultBucketId
, 0);
889 void GLES2Implementation::GetVertexAttribPointerv(
890 GLuint index
, GLenum pname
, void** ptr
) {
891 GPU_CLIENT_SINGLE_THREAD_CHECK();
892 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
893 << index
<< ", " << GLES2Util::GetStringVertexPointer(pname
) << ", "
894 << static_cast<void*>(ptr
) << ")");
895 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results
= 1);
896 if (!vertex_array_object_manager_
->GetAttribPointer(index
, pname
, ptr
)) {
897 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
898 typedef cmds::GetVertexAttribPointerv::Result Result
;
899 Result
* result
= GetResultAs
<Result
*>();
903 result
->SetNumResults(0);
904 helper_
->GetVertexAttribPointerv(
905 index
, pname
, GetResultShmId(), GetResultShmOffset());
907 result
->CopyResult(ptr
);
908 GPU_CLIENT_LOG_CODE_BLOCK(num_results
= result
->GetNumResults());
910 GPU_CLIENT_LOG_CODE_BLOCK({
911 for (int32 i
= 0; i
< num_results
; ++i
) {
912 GPU_CLIENT_LOG(" " << i
<< ": " << ptr
[i
]);
918 bool GLES2Implementation::DeleteProgramHelper(GLuint program
) {
919 if (!GetIdHandler(id_namespaces::kProgramsAndShaders
)->FreeIds(
920 this, 1, &program
, &GLES2Implementation::DeleteProgramStub
)) {
923 "glDeleteProgram", "id not created by this context.");
926 if (program
== current_program_
) {
927 current_program_
= 0;
932 void GLES2Implementation::DeleteProgramStub(
933 GLsizei n
, const GLuint
* programs
) {
935 share_group_
->program_info_manager()->DeleteInfo(programs
[0]);
936 helper_
->DeleteProgram(programs
[0]);
939 bool GLES2Implementation::DeleteShaderHelper(GLuint shader
) {
940 if (!GetIdHandler(id_namespaces::kProgramsAndShaders
)->FreeIds(
941 this, 1, &shader
, &GLES2Implementation::DeleteShaderStub
)) {
944 "glDeleteShader", "id not created by this context.");
950 void GLES2Implementation::DeleteShaderStub(
951 GLsizei n
, const GLuint
* shaders
) {
953 share_group_
->program_info_manager()->DeleteInfo(shaders
[0]);
954 helper_
->DeleteShader(shaders
[0]);
958 GLint
GLES2Implementation::GetAttribLocationHelper(
959 GLuint program
, const char* name
) {
960 typedef cmds::GetAttribLocation::Result Result
;
961 Result
* result
= GetResultAs
<Result
*>();
966 SetBucketAsCString(kResultBucketId
, name
);
967 helper_
->GetAttribLocation(
968 program
, kResultBucketId
, GetResultShmId(), GetResultShmOffset());
970 helper_
->SetBucketSize(kResultBucketId
, 0);
974 GLint
GLES2Implementation::GetAttribLocation(
975 GLuint program
, const char* name
) {
976 GPU_CLIENT_SINGLE_THREAD_CHECK();
977 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
978 << ", " << name
<< ")");
979 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
980 GLint loc
= share_group_
->program_info_manager()->GetAttribLocation(
981 this, program
, name
);
982 GPU_CLIENT_LOG("returned " << loc
);
987 GLint
GLES2Implementation::GetUniformLocationHelper(
988 GLuint program
, const char* name
) {
989 typedef cmds::GetUniformLocation::Result Result
;
990 Result
* result
= GetResultAs
<Result
*>();
995 SetBucketAsCString(kResultBucketId
, name
);
996 helper_
->GetUniformLocation(program
, kResultBucketId
,
997 GetResultShmId(), GetResultShmOffset());
999 helper_
->SetBucketSize(kResultBucketId
, 0);
1003 GLint
GLES2Implementation::GetUniformLocation(
1004 GLuint program
, const char* name
) {
1005 GPU_CLIENT_SINGLE_THREAD_CHECK();
1006 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1007 << ", " << name
<< ")");
1008 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1009 GLint loc
= share_group_
->program_info_manager()->GetUniformLocation(
1010 this, program
, name
);
1011 GPU_CLIENT_LOG("returned " << loc
);
1016 bool GLES2Implementation::GetProgramivHelper(
1017 GLuint program
, GLenum pname
, GLint
* params
) {
1018 bool got_value
= share_group_
->program_info_manager()->GetProgramiv(
1019 this, program
, pname
, params
);
1020 GPU_CLIENT_LOG_CODE_BLOCK({
1022 GPU_CLIENT_LOG(" 0: " << *params
);
1028 void GLES2Implementation::LinkProgram(GLuint program
) {
1029 GPU_CLIENT_SINGLE_THREAD_CHECK();
1030 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program
<< ")");
1031 helper_
->LinkProgram(program
);
1032 share_group_
->program_info_manager()->CreateInfo(program
);
1036 void GLES2Implementation::ShaderBinary(
1037 GLsizei n
, const GLuint
* shaders
, GLenum binaryformat
, const void* binary
,
1039 GPU_CLIENT_SINGLE_THREAD_CHECK();
1040 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n
<< ", "
1041 << static_cast<const void*>(shaders
) << ", "
1042 << GLES2Util::GetStringEnum(binaryformat
) << ", "
1043 << static_cast<const void*>(binary
) << ", "
1046 SetGLError(GL_INVALID_VALUE
, "glShaderBinary", "n < 0.");
1050 SetGLError(GL_INVALID_VALUE
, "glShaderBinary", "length < 0.");
1053 // TODO(gman): ShaderBinary should use buckets.
1054 unsigned int shader_id_size
= n
* sizeof(*shaders
);
1055 ScopedTransferBufferArray
<GLint
> buffer(
1056 shader_id_size
+ length
, helper_
, transfer_buffer_
);
1057 if (!buffer
.valid() || buffer
.num_elements() != shader_id_size
+ length
) {
1058 SetGLError(GL_OUT_OF_MEMORY
, "glShaderBinary", "out of memory.");
1061 void* shader_ids
= buffer
.elements();
1062 void* shader_data
= buffer
.elements() + shader_id_size
;
1063 memcpy(shader_ids
, shaders
, shader_id_size
);
1064 memcpy(shader_data
, binary
, length
);
1065 helper_
->ShaderBinary(
1071 buffer
.offset() + shader_id_size
,
1076 void GLES2Implementation::PixelStorei(GLenum pname
, GLint param
) {
1077 GPU_CLIENT_SINGLE_THREAD_CHECK();
1078 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1079 << GLES2Util::GetStringPixelStore(pname
) << ", "
1082 case GL_PACK_ALIGNMENT
:
1083 pack_alignment_
= param
;
1085 case GL_UNPACK_ALIGNMENT
:
1086 unpack_alignment_
= param
;
1088 case GL_UNPACK_ROW_LENGTH_EXT
:
1089 unpack_row_length_
= param
;
1091 case GL_UNPACK_SKIP_ROWS_EXT
:
1092 unpack_skip_rows_
= param
;
1094 case GL_UNPACK_SKIP_PIXELS_EXT
:
1095 unpack_skip_pixels_
= param
;
1097 case GL_UNPACK_FLIP_Y_CHROMIUM
:
1098 unpack_flip_y_
= (param
!= 0);
1100 case GL_PACK_REVERSE_ROW_ORDER_ANGLE
:
1101 pack_reverse_row_order_
=
1102 IsAnglePackReverseRowOrderAvailable() ? (param
!= 0) : false;
1107 helper_
->PixelStorei(pname
, param
);
1111 void GLES2Implementation::VertexAttribPointer(
1112 GLuint index
, GLint size
, GLenum type
, GLboolean normalized
, GLsizei stride
,
1114 GPU_CLIENT_SINGLE_THREAD_CHECK();
1115 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1118 << GLES2Util::GetStringVertexAttribType(type
) << ", "
1119 << GLES2Util::GetStringBool(normalized
) << ", "
1121 << static_cast<const void*>(ptr
) << ")");
1122 // Record the info on the client side.
1123 if (!vertex_array_object_manager_
->SetAttribPointer(
1124 bound_array_buffer_id_
, index
, size
, type
, normalized
, stride
, ptr
)) {
1125 SetGLError(GL_INVALID_OPERATION
, "glVertexAttribPointer",
1126 "client side arrays are not allowed in vertex array objects.");
1129 if (!support_client_side_arrays_
|| bound_array_buffer_id_
!= 0) {
1130 // Only report NON client side buffers to the service.
1131 if (!ValidateOffset("glVertexAttribPointer",
1132 reinterpret_cast<GLintptr
>(ptr
))) {
1135 helper_
->VertexAttribPointer(index
, size
, type
, normalized
, stride
,
1141 void GLES2Implementation::VertexAttribDivisorANGLE(
1142 GLuint index
, GLuint divisor
) {
1143 GPU_CLIENT_SINGLE_THREAD_CHECK();
1144 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1146 << divisor
<< ") ");
1147 // Record the info on the client side.
1148 vertex_array_object_manager_
->SetAttribDivisor(index
, divisor
);
1149 helper_
->VertexAttribDivisorANGLE(index
, divisor
);
1153 void GLES2Implementation::ShaderSource(
1156 const GLchar
* const* source
,
1157 const GLint
* length
) {
1158 GPU_CLIENT_SINGLE_THREAD_CHECK();
1159 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderSource("
1160 << shader
<< ", " << count
<< ", "
1161 << static_cast<const void*>(source
) << ", "
1162 << static_cast<const void*>(length
) << ")");
1163 GPU_CLIENT_LOG_CODE_BLOCK({
1164 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1166 if (length
&& length
[ii
] >= 0) {
1167 std::string
str(source
[ii
], length
[ii
]);
1168 GPU_CLIENT_LOG(" " << ii
<< ": ---\n" << str
<< "\n---");
1170 GPU_CLIENT_LOG(" " << ii
<< ": ---\n" << source
[ii
] << "\n---");
1173 GPU_CLIENT_LOG(" " << ii
<< ": NULL");
1178 SetGLError(GL_INVALID_VALUE
, "glShaderSource", "count < 0");
1182 SetGLError(GL_INVALID_VALUE
, "glShaderSource", "shader == 0");
1186 // Compute the total size.
1187 uint32 total_size
= 1;
1188 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1190 total_size
+= (length
&& length
[ii
] >= 0) ?
1191 static_cast<size_t>(length
[ii
]) : strlen(source
[ii
]);
1195 // Concatenate all the strings in to a bucket on the service.
1196 helper_
->SetBucketSize(kResultBucketId
, total_size
);
1198 for (GLsizei ii
= 0; ii
<= count
; ++ii
) {
1199 const char* src
= ii
< count
? source
[ii
] : "";
1201 uint32 size
= ii
< count
?
1202 (length
? static_cast<size_t>(length
[ii
]) : strlen(src
)) : 1;
1204 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1205 if (!buffer
.valid()) {
1208 memcpy(buffer
.address(), src
, buffer
.size());
1209 helper_
->SetBucketData(kResultBucketId
, offset
, buffer
.size(),
1210 buffer
.shm_id(), buffer
.offset());
1211 offset
+= buffer
.size();
1212 src
+= buffer
.size();
1213 size
-= buffer
.size();
1218 DCHECK_EQ(total_size
, offset
);
1220 helper_
->ShaderSourceBucket(shader
, kResultBucketId
);
1221 helper_
->SetBucketSize(kResultBucketId
, 0);
1225 void GLES2Implementation::BufferDataHelper(
1226 GLenum target
, GLsizeiptr size
, const void* data
, GLenum usage
) {
1227 if (!ValidateSize("glBufferData", size
))
1231 if (GetBoundPixelTransferBuffer(target
, "glBufferData", &buffer_id
)) {
1236 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
1238 RemoveTransferBuffer(buffer
);
1240 // Create new buffer.
1241 buffer
= buffer_tracker_
->CreateBuffer(buffer_id
, size
);
1243 if (buffer
->address() && data
)
1244 memcpy(buffer
->address(), data
, size
);
1252 // If there is no data just send BufferData
1254 helper_
->BufferData(target
, size
, 0, 0, usage
);
1258 // See if we can send all at once.
1259 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1260 if (!buffer
.valid()) {
1264 if (buffer
.size() >= static_cast<unsigned int>(size
)) {
1265 memcpy(buffer
.address(), data
, size
);
1266 helper_
->BufferData(
1275 // Make the buffer with BufferData then send via BufferSubData
1276 helper_
->BufferData(target
, size
, 0, 0, usage
);
1277 BufferSubDataHelperImpl(target
, 0, size
, data
, &buffer
);
1281 void GLES2Implementation::BufferData(
1282 GLenum target
, GLsizeiptr size
, const void* data
, GLenum usage
) {
1283 GPU_CLIENT_SINGLE_THREAD_CHECK();
1284 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1285 << GLES2Util::GetStringBufferTarget(target
) << ", "
1287 << static_cast<const void*>(data
) << ", "
1288 << GLES2Util::GetStringBufferUsage(usage
) << ")");
1289 BufferDataHelper(target
, size
, data
, usage
);
1293 void GLES2Implementation::BufferSubDataHelper(
1294 GLenum target
, GLintptr offset
, GLsizeiptr size
, const void* data
) {
1299 if (!ValidateSize("glBufferSubData", size
) ||
1300 !ValidateOffset("glBufferSubData", offset
)) {
1305 if (GetBoundPixelTransferBuffer(target
, "glBufferSubData", &buffer_id
)) {
1309 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
1311 SetGLError(GL_INVALID_VALUE
, "glBufferSubData", "unknown buffer");
1316 int32 buffer_size
= buffer
->size();
1317 if (!SafeAddInt32(offset
, size
, &end
) || end
> buffer_size
) {
1318 SetGLError(GL_INVALID_VALUE
, "glBufferSubData", "out of range");
1322 if (buffer
->address() && data
)
1323 memcpy(static_cast<uint8
*>(buffer
->address()) + offset
, data
, size
);
1327 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1328 BufferSubDataHelperImpl(target
, offset
, size
, data
, &buffer
);
1331 void GLES2Implementation::BufferSubDataHelperImpl(
1332 GLenum target
, GLintptr offset
, GLsizeiptr size
, const void* data
,
1333 ScopedTransferBufferPtr
* buffer
) {
1337 const int8
* source
= static_cast<const int8
*>(data
);
1339 if (!buffer
->valid() || buffer
->size() == 0) {
1340 buffer
->Reset(size
);
1341 if (!buffer
->valid()) {
1345 memcpy(buffer
->address(), source
, buffer
->size());
1346 helper_
->BufferSubData(
1347 target
, offset
, buffer
->size(), buffer
->shm_id(), buffer
->offset());
1348 offset
+= buffer
->size();
1349 source
+= buffer
->size();
1350 size
-= buffer
->size();
1355 void GLES2Implementation::BufferSubData(
1356 GLenum target
, GLintptr offset
, GLsizeiptr size
, const void* data
) {
1357 GPU_CLIENT_SINGLE_THREAD_CHECK();
1358 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1359 << GLES2Util::GetStringBufferTarget(target
) << ", "
1360 << offset
<< ", " << size
<< ", "
1361 << static_cast<const void*>(data
) << ")");
1362 BufferSubDataHelper(target
, offset
, size
, data
);
1366 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer
* buffer
) {
1367 int32 token
= buffer
->last_usage_token();
1368 uint32 async_token
= buffer
->last_async_upload_token();
1371 if (HasAsyncUploadTokenPassed(async_token
)) {
1372 buffer_tracker_
->Free(buffer
);
1374 detached_async_upload_memory_
.push_back(
1375 std::make_pair(buffer
->address(), async_token
));
1376 buffer_tracker_
->Unmanage(buffer
);
1379 if (helper_
->HasTokenPassed(token
))
1380 buffer_tracker_
->Free(buffer
);
1382 buffer_tracker_
->FreePendingToken(buffer
, token
);
1384 buffer_tracker_
->Free(buffer
);
1387 buffer_tracker_
->RemoveBuffer(buffer
->id());
1390 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1392 const char* function_name
,
1393 GLuint
* buffer_id
) {
1397 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
:
1398 *buffer_id
= bound_pixel_pack_transfer_buffer_id_
;
1400 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
:
1401 *buffer_id
= bound_pixel_unpack_transfer_buffer_id_
;
1408 SetGLError(GL_INVALID_OPERATION
, function_name
, "no buffer bound");
1413 BufferTracker::Buffer
*
1414 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1416 const char* function_name
,
1417 GLuint offset
, GLsizei size
) {
1419 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
1421 SetGLError(GL_INVALID_OPERATION
, function_name
, "invalid buffer");
1424 if (buffer
->mapped()) {
1425 SetGLError(GL_INVALID_OPERATION
, function_name
, "buffer mapped");
1428 if ((buffer
->size() - offset
) < static_cast<GLuint
>(size
)) {
1429 SetGLError(GL_INVALID_VALUE
, function_name
, "unpack size to large");
1435 void GLES2Implementation::CompressedTexImage2D(
1436 GLenum target
, GLint level
, GLenum internalformat
, GLsizei width
,
1437 GLsizei height
, GLint border
, GLsizei image_size
, const void* data
) {
1438 GPU_CLIENT_SINGLE_THREAD_CHECK();
1439 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1440 << GLES2Util::GetStringTextureTarget(target
) << ", "
1442 << GLES2Util::GetStringCompressedTextureFormat(internalformat
) << ", "
1443 << width
<< ", " << height
<< ", " << border
<< ", "
1444 << image_size
<< ", "
1445 << static_cast<const void*>(data
) << ")");
1446 if (width
< 0 || height
< 0 || level
< 0) {
1447 SetGLError(GL_INVALID_VALUE
, "glCompressedTexImage2D", "dimension < 0");
1451 SetGLError(GL_INVALID_VALUE
, "glCompressedTexImage2D", "border != 0");
1454 if (height
== 0 || width
== 0) {
1457 // If there's a pixel unpack buffer bound use it when issuing
1458 // CompressedTexImage2D.
1459 if (bound_pixel_unpack_transfer_buffer_id_
) {
1460 GLuint offset
= ToGLuint(data
);
1461 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1462 bound_pixel_unpack_transfer_buffer_id_
,
1463 "glCompressedTexImage2D", offset
, image_size
);
1464 if (buffer
&& buffer
->shm_id() != -1) {
1465 helper_
->CompressedTexImage2D(
1466 target
, level
, internalformat
, width
, height
, image_size
,
1467 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1468 buffer
->set_last_usage_token(helper_
->InsertToken());
1472 SetBucketContents(kResultBucketId
, data
, image_size
);
1473 helper_
->CompressedTexImage2DBucket(
1474 target
, level
, internalformat
, width
, height
, kResultBucketId
);
1475 // Free the bucket. This is not required but it does free up the memory.
1476 // and we don't have to wait for the result so from the client's perspective
1478 helper_
->SetBucketSize(kResultBucketId
, 0);
1482 void GLES2Implementation::CompressedTexSubImage2D(
1483 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
1484 GLsizei height
, GLenum format
, GLsizei image_size
, const void* data
) {
1485 GPU_CLIENT_SINGLE_THREAD_CHECK();
1486 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1487 << GLES2Util::GetStringTextureTarget(target
) << ", "
1489 << xoffset
<< ", " << yoffset
<< ", "
1490 << width
<< ", " << height
<< ", "
1491 << GLES2Util::GetStringCompressedTextureFormat(format
) << ", "
1492 << image_size
<< ", "
1493 << static_cast<const void*>(data
) << ")");
1494 if (width
< 0 || height
< 0 || level
< 0) {
1495 SetGLError(GL_INVALID_VALUE
, "glCompressedTexSubImage2D", "dimension < 0");
1498 // If there's a pixel unpack buffer bound use it when issuing
1499 // CompressedTexSubImage2D.
1500 if (bound_pixel_unpack_transfer_buffer_id_
) {
1501 GLuint offset
= ToGLuint(data
);
1502 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1503 bound_pixel_unpack_transfer_buffer_id_
,
1504 "glCompressedTexSubImage2D", offset
, image_size
);
1505 if (buffer
&& buffer
->shm_id() != -1) {
1506 helper_
->CompressedTexSubImage2D(
1507 target
, level
, xoffset
, yoffset
, width
, height
, format
, image_size
,
1508 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1509 buffer
->set_last_usage_token(helper_
->InsertToken());
1514 SetBucketContents(kResultBucketId
, data
, image_size
);
1515 helper_
->CompressedTexSubImage2DBucket(
1516 target
, level
, xoffset
, yoffset
, width
, height
, format
, kResultBucketId
);
1517 // Free the bucket. This is not required but it does free up the memory.
1518 // and we don't have to wait for the result so from the client's perspective
1520 helper_
->SetBucketSize(kResultBucketId
, 0);
1526 void CopyRectToBuffer(
1529 uint32 unpadded_row_size
,
1530 uint32 pixels_padded_row_size
,
1533 uint32 buffer_padded_row_size
) {
1534 const int8
* source
= static_cast<const int8
*>(pixels
);
1535 int8
* dest
= static_cast<int8
*>(buffer
);
1536 if (flip_y
|| pixels_padded_row_size
!= buffer_padded_row_size
) {
1538 dest
+= buffer_padded_row_size
* (height
- 1);
1540 // the last row is copied unpadded at the end
1541 for (; height
> 1; --height
) {
1542 memcpy(dest
, source
, buffer_padded_row_size
);
1544 dest
-= buffer_padded_row_size
;
1546 dest
+= buffer_padded_row_size
;
1548 source
+= pixels_padded_row_size
;
1550 memcpy(dest
, source
, unpadded_row_size
);
1552 uint32 size
= (height
- 1) * pixels_padded_row_size
+ unpadded_row_size
;
1553 memcpy(dest
, source
, size
);
1557 } // anonymous namespace
1559 void GLES2Implementation::TexImage2D(
1560 GLenum target
, GLint level
, GLint internalformat
, GLsizei width
,
1561 GLsizei height
, GLint border
, GLenum format
, GLenum type
,
1562 const void* pixels
) {
1563 GPU_CLIENT_SINGLE_THREAD_CHECK();
1564 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1565 << GLES2Util::GetStringTextureTarget(target
) << ", "
1567 << GLES2Util::GetStringTextureInternalFormat(internalformat
) << ", "
1568 << width
<< ", " << height
<< ", " << border
<< ", "
1569 << GLES2Util::GetStringTextureFormat(format
) << ", "
1570 << GLES2Util::GetStringPixelType(type
) << ", "
1571 << static_cast<const void*>(pixels
) << ")");
1572 if (level
< 0 || height
< 0 || width
< 0) {
1573 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "dimension < 0");
1577 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "border != 0");
1581 uint32 unpadded_row_size
;
1582 uint32 padded_row_size
;
1583 if (!GLES2Util::ComputeImageDataSizes(
1584 width
, height
, format
, type
, unpack_alignment_
, &size
,
1585 &unpadded_row_size
, &padded_row_size
)) {
1586 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "image size too large");
1590 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1591 if (bound_pixel_unpack_transfer_buffer_id_
) {
1592 GLuint offset
= ToGLuint(pixels
);
1593 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1594 bound_pixel_unpack_transfer_buffer_id_
,
1595 "glTexImage2D", offset
, size
);
1596 if (buffer
&& buffer
->shm_id() != -1) {
1597 helper_
->TexImage2D(
1598 target
, level
, internalformat
, width
, height
, format
, type
,
1599 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1600 buffer
->set_last_usage_token(helper_
->InsertToken());
1606 // If there's no data just issue TexImage2D
1608 helper_
->TexImage2D(
1609 target
, level
, internalformat
, width
, height
, format
, type
,
1615 // compute the advance bytes per row for the src pixels
1616 uint32 src_padded_row_size
;
1617 if (unpack_row_length_
> 0) {
1618 if (!GLES2Util::ComputeImagePaddedRowSize(
1619 unpack_row_length_
, format
, type
, unpack_alignment_
,
1620 &src_padded_row_size
)) {
1622 GL_INVALID_VALUE
, "glTexImage2D", "unpack row length too large");
1626 src_padded_row_size
= padded_row_size
;
1629 // advance pixels pointer past the skip rows and skip pixels
1630 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1631 unpack_skip_rows_
* src_padded_row_size
;
1632 if (unpack_skip_pixels_
) {
1633 uint32 group_size
= GLES2Util::ComputeImageGroupSize(format
, type
);
1634 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1635 unpack_skip_pixels_
* group_size
;
1638 // Check if we can send it all at once.
1639 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1640 if (!buffer
.valid()) {
1644 if (buffer
.size() >= size
) {
1646 pixels
, height
, unpadded_row_size
, src_padded_row_size
, unpack_flip_y_
,
1647 buffer
.address(), padded_row_size
);
1648 helper_
->TexImage2D(
1649 target
, level
, internalformat
, width
, height
, format
, type
,
1650 buffer
.shm_id(), buffer
.offset());
1655 // No, so send it using TexSubImage2D.
1656 helper_
->TexImage2D(
1657 target
, level
, internalformat
, width
, height
, format
, type
,
1660 target
, level
, 0, 0, width
, height
, format
, type
, unpadded_row_size
,
1661 pixels
, src_padded_row_size
, GL_TRUE
, &buffer
, padded_row_size
);
1665 void GLES2Implementation::TexSubImage2D(
1666 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
1667 GLsizei height
, GLenum format
, GLenum type
, const void* pixels
) {
1668 GPU_CLIENT_SINGLE_THREAD_CHECK();
1669 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1670 << GLES2Util::GetStringTextureTarget(target
) << ", "
1672 << xoffset
<< ", " << yoffset
<< ", "
1673 << width
<< ", " << height
<< ", "
1674 << GLES2Util::GetStringTextureFormat(format
) << ", "
1675 << GLES2Util::GetStringPixelType(type
) << ", "
1676 << static_cast<const void*>(pixels
) << ")");
1678 if (level
< 0 || height
< 0 || width
< 0) {
1679 SetGLError(GL_INVALID_VALUE
, "glTexSubImage2D", "dimension < 0");
1682 if (height
== 0 || width
== 0) {
1687 uint32 unpadded_row_size
;
1688 uint32 padded_row_size
;
1689 if (!GLES2Util::ComputeImageDataSizes(
1690 width
, height
, format
, type
, unpack_alignment_
, &temp_size
,
1691 &unpadded_row_size
, &padded_row_size
)) {
1692 SetGLError(GL_INVALID_VALUE
, "glTexSubImage2D", "size to large");
1696 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1697 if (bound_pixel_unpack_transfer_buffer_id_
) {
1698 GLuint offset
= ToGLuint(pixels
);
1699 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1700 bound_pixel_unpack_transfer_buffer_id_
,
1701 "glTexSubImage2D", offset
, temp_size
);
1702 if (buffer
&& buffer
->shm_id() != -1) {
1703 helper_
->TexSubImage2D(
1704 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
,
1705 buffer
->shm_id(), buffer
->shm_offset() + offset
, false);
1706 buffer
->set_last_usage_token(helper_
->InsertToken());
1712 // compute the advance bytes per row for the src pixels
1713 uint32 src_padded_row_size
;
1714 if (unpack_row_length_
> 0) {
1715 if (!GLES2Util::ComputeImagePaddedRowSize(
1716 unpack_row_length_
, format
, type
, unpack_alignment_
,
1717 &src_padded_row_size
)) {
1719 GL_INVALID_VALUE
, "glTexImage2D", "unpack row length too large");
1723 src_padded_row_size
= padded_row_size
;
1726 // advance pixels pointer past the skip rows and skip pixels
1727 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1728 unpack_skip_rows_
* src_padded_row_size
;
1729 if (unpack_skip_pixels_
) {
1730 uint32 group_size
= GLES2Util::ComputeImageGroupSize(format
, type
);
1731 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1732 unpack_skip_pixels_
* group_size
;
1735 ScopedTransferBufferPtr
buffer(temp_size
, helper_
, transfer_buffer_
);
1737 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
,
1738 unpadded_row_size
, pixels
, src_padded_row_size
, GL_FALSE
, &buffer
,
1743 static GLint
ComputeNumRowsThatFitInBuffer(
1744 uint32 padded_row_size
, uint32 unpadded_row_size
,
1745 unsigned int size
) {
1746 DCHECK_GE(unpadded_row_size
, 0u);
1747 if (padded_row_size
== 0) {
1750 GLint num_rows
= size
/ padded_row_size
;
1751 return num_rows
+ (size
- num_rows
* padded_row_size
) / unpadded_row_size
;
1754 void GLES2Implementation::TexSubImage2DImpl(
1755 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
1756 GLsizei height
, GLenum format
, GLenum type
, uint32 unpadded_row_size
,
1757 const void* pixels
, uint32 pixels_padded_row_size
, GLboolean internal
,
1758 ScopedTransferBufferPtr
* buffer
, uint32 buffer_padded_row_size
) {
1760 DCHECK_GE(level
, 0);
1761 DCHECK_GT(height
, 0);
1762 DCHECK_GT(width
, 0);
1764 const int8
* source
= reinterpret_cast<const int8
*>(pixels
);
1765 GLint original_yoffset
= yoffset
;
1766 // Transfer by rows.
1768 unsigned int desired_size
=
1769 buffer_padded_row_size
* (height
- 1) + unpadded_row_size
;
1770 if (!buffer
->valid() || buffer
->size() == 0) {
1771 buffer
->Reset(desired_size
);
1772 if (!buffer
->valid()) {
1777 GLint num_rows
= ComputeNumRowsThatFitInBuffer(
1778 buffer_padded_row_size
, unpadded_row_size
, buffer
->size());
1779 num_rows
= std::min(num_rows
, height
);
1781 source
, num_rows
, unpadded_row_size
, pixels_padded_row_size
,
1782 unpack_flip_y_
, buffer
->address(), buffer_padded_row_size
);
1783 GLint y
= unpack_flip_y_
? original_yoffset
+ height
- num_rows
: yoffset
;
1784 helper_
->TexSubImage2D(
1785 target
, level
, xoffset
, y
, width
, num_rows
, format
, type
,
1786 buffer
->shm_id(), buffer
->offset(), internal
);
1788 yoffset
+= num_rows
;
1789 source
+= num_rows
* pixels_padded_row_size
;
1794 bool GLES2Implementation::GetActiveAttribHelper(
1795 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
1796 GLenum
* type
, char* name
) {
1797 // Clear the bucket so if the command fails nothing will be in it.
1798 helper_
->SetBucketSize(kResultBucketId
, 0);
1799 typedef cmds::GetActiveAttrib::Result Result
;
1800 Result
* result
= GetResultAs
<Result
*>();
1804 // Set as failed so if the command fails we'll recover.
1805 result
->success
= false;
1806 helper_
->GetActiveAttrib(program
, index
, kResultBucketId
,
1807 GetResultShmId(), GetResultShmOffset());
1809 if (result
->success
) {
1811 *size
= result
->size
;
1814 *type
= result
->type
;
1816 if (length
|| name
) {
1817 std::vector
<int8
> str
;
1818 GetBucketContents(kResultBucketId
, &str
);
1819 GLsizei max_size
= std::min(static_cast<size_t>(bufsize
) - 1,
1820 std::max(static_cast<size_t>(0),
1825 if (name
&& bufsize
> 0) {
1826 memcpy(name
, &str
[0], max_size
);
1827 name
[max_size
] = '\0';
1831 return result
->success
!= 0;
1834 void GLES2Implementation::GetActiveAttrib(
1835 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
1836 GLenum
* type
, char* name
) {
1837 GPU_CLIENT_SINGLE_THREAD_CHECK();
1838 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
1839 << program
<< ", " << index
<< ", " << bufsize
<< ", "
1840 << static_cast<const void*>(length
) << ", "
1841 << static_cast<const void*>(size
) << ", "
1842 << static_cast<const void*>(type
) << ", "
1843 << static_cast<const void*>(name
) << ", ");
1845 SetGLError(GL_INVALID_VALUE
, "glGetActiveAttrib", "bufsize < 0");
1848 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
1849 bool success
= share_group_
->program_info_manager()->GetActiveAttrib(
1850 this, program
, index
, bufsize
, length
, size
, type
, name
);
1853 GPU_CLIENT_LOG(" size: " << *size
);
1856 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type
));
1859 GPU_CLIENT_LOG(" name: " << name
);
1865 bool GLES2Implementation::GetActiveUniformHelper(
1866 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
1867 GLenum
* type
, char* name
) {
1868 // Clear the bucket so if the command fails nothing will be in it.
1869 helper_
->SetBucketSize(kResultBucketId
, 0);
1870 typedef cmds::GetActiveUniform::Result Result
;
1871 Result
* result
= GetResultAs
<Result
*>();
1875 // Set as failed so if the command fails we'll recover.
1876 result
->success
= false;
1877 helper_
->GetActiveUniform(program
, index
, kResultBucketId
,
1878 GetResultShmId(), GetResultShmOffset());
1880 if (result
->success
) {
1882 *size
= result
->size
;
1885 *type
= result
->type
;
1887 if (length
|| name
) {
1888 std::vector
<int8
> str
;
1889 GetBucketContents(kResultBucketId
, &str
);
1890 GLsizei max_size
= std::min(static_cast<size_t>(bufsize
) - 1,
1891 std::max(static_cast<size_t>(0),
1896 if (name
&& bufsize
> 0) {
1897 memcpy(name
, &str
[0], max_size
);
1898 name
[max_size
] = '\0';
1902 return result
->success
!= 0;
1905 void GLES2Implementation::GetActiveUniform(
1906 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
1907 GLenum
* type
, char* name
) {
1908 GPU_CLIENT_SINGLE_THREAD_CHECK();
1909 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
1910 << program
<< ", " << index
<< ", " << bufsize
<< ", "
1911 << static_cast<const void*>(length
) << ", "
1912 << static_cast<const void*>(size
) << ", "
1913 << static_cast<const void*>(type
) << ", "
1914 << static_cast<const void*>(name
) << ", ");
1916 SetGLError(GL_INVALID_VALUE
, "glGetActiveUniform", "bufsize < 0");
1919 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
1920 bool success
= share_group_
->program_info_manager()->GetActiveUniform(
1921 this, program
, index
, bufsize
, length
, size
, type
, name
);
1924 GPU_CLIENT_LOG(" size: " << *size
);
1927 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type
));
1930 GPU_CLIENT_LOG(" name: " << name
);
1936 void GLES2Implementation::GetAttachedShaders(
1937 GLuint program
, GLsizei maxcount
, GLsizei
* count
, GLuint
* shaders
) {
1938 GPU_CLIENT_SINGLE_THREAD_CHECK();
1939 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
1940 << program
<< ", " << maxcount
<< ", "
1941 << static_cast<const void*>(count
) << ", "
1942 << static_cast<const void*>(shaders
) << ", ");
1944 SetGLError(GL_INVALID_VALUE
, "glGetAttachedShaders", "maxcount < 0");
1947 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
1948 typedef cmds::GetAttachedShaders::Result Result
;
1949 uint32 size
= Result::ComputeSize(maxcount
);
1950 Result
* result
= static_cast<Result
*>(transfer_buffer_
->Alloc(size
));
1954 result
->SetNumResults(0);
1955 helper_
->GetAttachedShaders(
1957 transfer_buffer_
->GetShmId(),
1958 transfer_buffer_
->GetOffset(result
),
1960 int32 token
= helper_
->InsertToken();
1963 *count
= result
->GetNumResults();
1965 result
->CopyResult(shaders
);
1966 GPU_CLIENT_LOG_CODE_BLOCK({
1967 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
1968 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
1971 transfer_buffer_
->FreePendingToken(result
, token
);
1975 void GLES2Implementation::GetShaderPrecisionFormat(
1976 GLenum shadertype
, GLenum precisiontype
, GLint
* range
, GLint
* precision
) {
1977 GPU_CLIENT_SINGLE_THREAD_CHECK();
1978 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
1979 << GLES2Util::GetStringShaderType(shadertype
) << ", "
1980 << GLES2Util::GetStringShaderPrecision(precisiontype
) << ", "
1981 << static_cast<const void*>(range
) << ", "
1982 << static_cast<const void*>(precision
) << ", ");
1983 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
1984 typedef cmds::GetShaderPrecisionFormat::Result Result
;
1985 Result
* result
= GetResultAs
<Result
*>();
1990 GLStaticState::ShaderPrecisionKey
key(shadertype
, precisiontype
);
1991 GLStaticState::ShaderPrecisionMap::iterator i
=
1992 static_state_
.shader_precisions
.find(key
);
1993 if (i
!= static_state_
.shader_precisions
.end()) {
1994 *result
= i
->second
;
1996 result
->success
= false;
1997 helper_
->GetShaderPrecisionFormat(
1998 shadertype
, precisiontype
, GetResultShmId(), GetResultShmOffset());
2000 if (result
->success
)
2001 static_state_
.shader_precisions
[key
] = *result
;
2004 if (result
->success
) {
2006 range
[0] = result
->min_range
;
2007 range
[1] = result
->max_range
;
2008 GPU_CLIENT_LOG(" min_range: " << range
[0]);
2009 GPU_CLIENT_LOG(" min_range: " << range
[1]);
2012 precision
[0] = result
->precision
;
2013 GPU_CLIENT_LOG(" min_range: " << precision
[0]);
2019 const GLubyte
* GLES2Implementation::GetStringHelper(GLenum name
) {
2020 const char* result
= NULL
;
2021 // Clears the bucket so if the command fails nothing will be in it.
2022 helper_
->SetBucketSize(kResultBucketId
, 0);
2023 helper_
->GetString(name
, kResultBucketId
);
2025 if (GetBucketAsString(kResultBucketId
, &str
)) {
2026 // Adds extensions implemented on client side only.
2029 str
+= std::string(str
.empty() ? "" : " ") +
2030 "GL_CHROMIUM_flipy "
2031 "GL_EXT_unpack_subimage "
2032 "GL_CHROMIUM_map_sub";
2033 if (capabilities_
.image
)
2034 str
+= " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
2035 if (capabilities_
.future_sync_points
)
2036 str
+= " GL_CHROMIUM_future_sync_point";
2042 // Because of WebGL the extensions can change. We have to cache each unique
2043 // result since we don't know when the client will stop referring to a
2044 // previous one it queries.
2045 GLStringMap::iterator it
= gl_strings_
.find(name
);
2046 if (it
== gl_strings_
.end()) {
2047 std::set
<std::string
> strings
;
2048 std::pair
<GLStringMap::iterator
, bool> insert_result
=
2049 gl_strings_
.insert(std::make_pair(name
, strings
));
2050 DCHECK(insert_result
.second
);
2051 it
= insert_result
.first
;
2053 std::set
<std::string
>& string_set
= it
->second
;
2054 std::set
<std::string
>::const_iterator sit
= string_set
.find(str
);
2055 if (sit
!= string_set
.end()) {
2056 result
= sit
->c_str();
2058 std::pair
<std::set
<std::string
>::const_iterator
, bool> insert_result
=
2059 string_set
.insert(str
);
2060 DCHECK(insert_result
.second
);
2061 result
= insert_result
.first
->c_str();
2064 return reinterpret_cast<const GLubyte
*>(result
);
2067 const GLubyte
* GLES2Implementation::GetString(GLenum name
) {
2068 GPU_CLIENT_SINGLE_THREAD_CHECK();
2069 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2070 << GLES2Util::GetStringStringType(name
) << ")");
2071 TRACE_EVENT0("gpu", "GLES2::GetString");
2072 const GLubyte
* result
= GetStringHelper(name
);
2073 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result
));
2078 void GLES2Implementation::GetUniformfv(
2079 GLuint program
, GLint location
, GLfloat
* params
) {
2080 GPU_CLIENT_SINGLE_THREAD_CHECK();
2081 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2082 << program
<< ", " << location
<< ", "
2083 << static_cast<const void*>(params
) << ")");
2084 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2085 typedef cmds::GetUniformfv::Result Result
;
2086 Result
* result
= GetResultAs
<Result
*>();
2090 result
->SetNumResults(0);
2091 helper_
->GetUniformfv(
2092 program
, location
, GetResultShmId(), GetResultShmOffset());
2094 result
->CopyResult(params
);
2095 GPU_CLIENT_LOG_CODE_BLOCK({
2096 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2097 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2103 void GLES2Implementation::GetUniformiv(
2104 GLuint program
, GLint location
, GLint
* params
) {
2105 GPU_CLIENT_SINGLE_THREAD_CHECK();
2106 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2107 << program
<< ", " << location
<< ", "
2108 << static_cast<const void*>(params
) << ")");
2109 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2110 typedef cmds::GetUniformiv::Result Result
;
2111 Result
* result
= GetResultAs
<Result
*>();
2115 result
->SetNumResults(0);
2116 helper_
->GetUniformiv(
2117 program
, location
, GetResultShmId(), GetResultShmOffset());
2119 GetResultAs
<cmds::GetUniformfv::Result
*>()->CopyResult(params
);
2120 GPU_CLIENT_LOG_CODE_BLOCK({
2121 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2122 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2128 void GLES2Implementation::ReadPixels(
2129 GLint xoffset
, GLint yoffset
, GLsizei width
, GLsizei height
, GLenum format
,
2130 GLenum type
, void* pixels
) {
2131 GPU_CLIENT_SINGLE_THREAD_CHECK();
2132 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2133 << xoffset
<< ", " << yoffset
<< ", "
2134 << width
<< ", " << height
<< ", "
2135 << GLES2Util::GetStringReadPixelFormat(format
) << ", "
2136 << GLES2Util::GetStringPixelType(type
) << ", "
2137 << static_cast<const void*>(pixels
) << ")");
2138 if (width
< 0 || height
< 0) {
2139 SetGLError(GL_INVALID_VALUE
, "glReadPixels", "dimensions < 0");
2142 if (width
== 0 || height
== 0) {
2146 // glReadPixel pads the size of each row of pixels by an amount specified by
2147 // glPixelStorei. So, we have to take that into account both in the fact that
2148 // the pixels returned from the ReadPixel command will include that padding
2149 // and that when we copy the results to the user's buffer we need to not
2150 // write those padding bytes but leave them as they are.
2152 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2153 typedef cmds::ReadPixels::Result Result
;
2155 int8
* dest
= reinterpret_cast<int8
*>(pixels
);
2157 uint32 unpadded_row_size
;
2158 uint32 padded_row_size
;
2159 if (!GLES2Util::ComputeImageDataSizes(
2160 width
, 2, format
, type
, pack_alignment_
, &temp_size
, &unpadded_row_size
,
2161 &padded_row_size
)) {
2162 SetGLError(GL_INVALID_VALUE
, "glReadPixels", "size too large.");
2166 if (bound_pixel_pack_transfer_buffer_id_
) {
2167 GLuint offset
= ToGLuint(pixels
);
2168 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
2169 bound_pixel_pack_transfer_buffer_id_
,
2170 "glReadPixels", offset
, padded_row_size
* height
);
2171 if (buffer
&& buffer
->shm_id() != -1) {
2172 helper_
->ReadPixels(xoffset
, yoffset
, width
, height
, format
, type
,
2173 buffer
->shm_id(), buffer
->shm_offset(),
2181 SetGLError(GL_INVALID_OPERATION
, "glReadPixels", "pixels = NULL");
2185 // Transfer by rows.
2186 // The max rows we can transfer.
2188 GLsizei desired_size
= padded_row_size
* height
- 1 + unpadded_row_size
;
2189 ScopedTransferBufferPtr
buffer(desired_size
, helper_
, transfer_buffer_
);
2190 if (!buffer
.valid()) {
2193 GLint num_rows
= ComputeNumRowsThatFitInBuffer(
2194 padded_row_size
, unpadded_row_size
, buffer
.size());
2195 num_rows
= std::min(num_rows
, height
);
2196 // NOTE: We must look up the address of the result area AFTER allocation
2197 // of the transfer buffer since the transfer buffer may be reallocated.
2198 Result
* result
= GetResultAs
<Result
*>();
2202 *result
= 0; // mark as failed.
2203 helper_
->ReadPixels(
2204 xoffset
, yoffset
, width
, num_rows
, format
, type
,
2205 buffer
.shm_id(), buffer
.offset(),
2206 GetResultShmId(), GetResultShmOffset(),
2210 // when doing a y-flip we have to iterate through top-to-bottom chunks
2211 // of the dst. The service side handles reversing the rows within a
2214 if (pack_reverse_row_order_
) {
2215 rows_dst
= dest
+ (height
- num_rows
) * padded_row_size
;
2219 // We have to copy 1 row at a time to avoid writing pad bytes.
2220 const int8
* src
= static_cast<const int8
*>(buffer
.address());
2221 for (GLint yy
= 0; yy
< num_rows
; ++yy
) {
2222 memcpy(rows_dst
, src
, unpadded_row_size
);
2223 rows_dst
+= padded_row_size
;
2224 src
+= padded_row_size
;
2226 if (!pack_reverse_row_order_
) {
2230 // If it was not marked as successful exit.
2234 yoffset
+= num_rows
;
2240 void GLES2Implementation::ActiveTexture(GLenum texture
) {
2241 GPU_CLIENT_SINGLE_THREAD_CHECK();
2242 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2243 << GLES2Util::GetStringEnum(texture
) << ")");
2244 GLuint texture_index
= texture
- GL_TEXTURE0
;
2245 if (texture_index
>=
2246 static_cast<GLuint
>(capabilities_
.max_combined_texture_image_units
)) {
2247 SetGLErrorInvalidEnum(
2248 "glActiveTexture", texture
, "texture");
2252 active_texture_unit_
= texture_index
;
2253 helper_
->ActiveTexture(texture
);
2257 void GLES2Implementation::GenBuffersHelper(
2258 GLsizei
/* n */, const GLuint
* /* buffers */) {
2261 void GLES2Implementation::GenFramebuffersHelper(
2262 GLsizei
/* n */, const GLuint
* /* framebuffers */) {
2265 void GLES2Implementation::GenRenderbuffersHelper(
2266 GLsizei
/* n */, const GLuint
* /* renderbuffers */) {
2269 void GLES2Implementation::GenTexturesHelper(
2270 GLsizei
/* n */, const GLuint
* /* textures */) {
2273 void GLES2Implementation::GenVertexArraysOESHelper(
2274 GLsizei n
, const GLuint
* arrays
) {
2275 vertex_array_object_manager_
->GenVertexArrays(n
, arrays
);
2278 void GLES2Implementation::GenQueriesEXTHelper(
2279 GLsizei
/* n */, const GLuint
* /* queries */) {
2282 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
2284 const GLuint
* /* valuebuffers */) {
2287 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
2288 // generates a new resource. On newer versions of OpenGL they don't. The code
2289 // related to binding below will need to change if we switch to the new OpenGL
2290 // model. Specifically it assumes a bind will succeed which is always true in
2291 // the old model but possibly not true in the new model if another context has
2292 // deleted the resource.
2294 bool GLES2Implementation::BindBufferHelper(
2295 GLenum target
, GLuint buffer_id
) {
2296 // TODO(gman): See note #1 above.
2297 bool changed
= false;
2299 case GL_ARRAY_BUFFER
:
2300 if (bound_array_buffer_id_
!= buffer_id
) {
2301 bound_array_buffer_id_
= buffer_id
;
2305 case GL_ELEMENT_ARRAY_BUFFER
:
2306 changed
= vertex_array_object_manager_
->BindElementArray(buffer_id
);
2308 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
:
2309 bound_pixel_pack_transfer_buffer_id_
= buffer_id
;
2311 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
:
2312 bound_pixel_unpack_transfer_buffer_id_
= buffer_id
;
2318 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2319 // used even though it's marked it as used here.
2320 GetIdHandler(id_namespaces::kBuffers
)->MarkAsUsedForBind(buffer_id
);
2324 bool GLES2Implementation::BindFramebufferHelper(
2325 GLenum target
, GLuint framebuffer
) {
2326 // TODO(gman): See note #1 above.
2327 bool changed
= false;
2329 case GL_FRAMEBUFFER
:
2330 if (bound_framebuffer_
!= framebuffer
||
2331 bound_read_framebuffer_
!= framebuffer
) {
2332 bound_framebuffer_
= framebuffer
;
2333 bound_read_framebuffer_
= framebuffer
;
2337 case GL_READ_FRAMEBUFFER
:
2338 if (!IsChromiumFramebufferMultisampleAvailable()) {
2339 SetGLErrorInvalidEnum("glBindFramebuffer", target
, "target");
2342 if (bound_read_framebuffer_
!= framebuffer
) {
2343 bound_read_framebuffer_
= framebuffer
;
2347 case GL_DRAW_FRAMEBUFFER
:
2348 if (!IsChromiumFramebufferMultisampleAvailable()) {
2349 SetGLErrorInvalidEnum("glBindFramebuffer", target
, "target");
2352 if (bound_framebuffer_
!= framebuffer
) {
2353 bound_framebuffer_
= framebuffer
;
2358 SetGLErrorInvalidEnum("glBindFramebuffer", target
, "target");
2361 GetIdHandler(id_namespaces::kFramebuffers
)->MarkAsUsedForBind(framebuffer
);
2365 bool GLES2Implementation::BindRenderbufferHelper(
2366 GLenum target
, GLuint renderbuffer
) {
2367 // TODO(gman): See note #1 above.
2368 bool changed
= false;
2370 case GL_RENDERBUFFER
:
2371 if (bound_renderbuffer_
!= renderbuffer
) {
2372 bound_renderbuffer_
= renderbuffer
;
2380 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2381 // used even though it's marked it as used here.
2382 GetIdHandler(id_namespaces::kRenderbuffers
)->MarkAsUsedForBind(renderbuffer
);
2386 bool GLES2Implementation::BindTextureHelper(GLenum target
, GLuint texture
) {
2387 // TODO(gman): See note #1 above.
2388 // TODO(gman): Change this to false once we figure out why it's failing
2390 bool changed
= true;
2391 TextureUnit
& unit
= texture_units_
[active_texture_unit_
];
2394 if (unit
.bound_texture_2d
!= texture
) {
2395 unit
.bound_texture_2d
= texture
;
2399 case GL_TEXTURE_CUBE_MAP
:
2400 if (unit
.bound_texture_cube_map
!= texture
) {
2401 unit
.bound_texture_cube_map
= texture
;
2405 case GL_TEXTURE_EXTERNAL_OES
:
2406 if (unit
.bound_texture_external_oes
!= texture
) {
2407 unit
.bound_texture_external_oes
= texture
;
2415 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2416 // used. even though it's marked it as used here.
2417 GetIdHandler(id_namespaces::kTextures
)->MarkAsUsedForBind(texture
);
2421 bool GLES2Implementation::BindVertexArrayOESHelper(GLuint array
) {
2422 // TODO(gman): See note #1 above.
2423 bool changed
= false;
2424 if (!vertex_array_object_manager_
->BindVertexArray(array
, &changed
)) {
2426 GL_INVALID_OPERATION
, "glBindVertexArrayOES",
2427 "id was not generated with glGenVertexArrayOES");
2429 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
2430 // because unlike other resources VertexArrayObject ids must
2431 // be generated by GenVertexArrays. A random id to Bind will not
2432 // generate a new object.
2436 bool GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target
,
2437 GLuint valuebuffer
) {
2438 bool changed
= false;
2440 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM
:
2441 if (bound_valuebuffer_
!= valuebuffer
) {
2442 bound_valuebuffer_
= valuebuffer
;
2450 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2451 // used even though it's marked it as used here.
2452 GetIdHandler(id_namespaces::kValuebuffers
)->MarkAsUsedForBind(valuebuffer
);
2456 bool GLES2Implementation::UseProgramHelper(GLuint program
) {
2457 bool changed
= false;
2458 if (current_program_
!= program
) {
2459 current_program_
= program
;
2465 bool GLES2Implementation::IsBufferReservedId(GLuint id
) {
2466 return vertex_array_object_manager_
->IsReservedId(id
);
2469 void GLES2Implementation::DeleteBuffersHelper(
2470 GLsizei n
, const GLuint
* buffers
) {
2471 if (!GetIdHandler(id_namespaces::kBuffers
)->FreeIds(
2472 this, n
, buffers
, &GLES2Implementation::DeleteBuffersStub
)) {
2475 "glDeleteBuffers", "id not created by this context.");
2478 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
2479 if (buffers
[ii
] == bound_array_buffer_id_
) {
2480 bound_array_buffer_id_
= 0;
2482 vertex_array_object_manager_
->UnbindBuffer(buffers
[ii
]);
2484 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffers
[ii
]);
2486 RemoveTransferBuffer(buffer
);
2488 if (buffers
[ii
] == bound_pixel_unpack_transfer_buffer_id_
) {
2489 bound_pixel_unpack_transfer_buffer_id_
= 0;
2494 void GLES2Implementation::DeleteBuffersStub(
2495 GLsizei n
, const GLuint
* buffers
) {
2496 helper_
->DeleteBuffersImmediate(n
, buffers
);
2500 void GLES2Implementation::DeleteFramebuffersHelper(
2501 GLsizei n
, const GLuint
* framebuffers
) {
2502 if (!GetIdHandler(id_namespaces::kFramebuffers
)->FreeIds(
2503 this, n
, framebuffers
, &GLES2Implementation::DeleteFramebuffersStub
)) {
2506 "glDeleteFramebuffers", "id not created by this context.");
2509 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
2510 if (framebuffers
[ii
] == bound_framebuffer_
) {
2511 bound_framebuffer_
= 0;
2513 if (framebuffers
[ii
] == bound_read_framebuffer_
) {
2514 bound_read_framebuffer_
= 0;
2519 void GLES2Implementation::DeleteFramebuffersStub(
2520 GLsizei n
, const GLuint
* framebuffers
) {
2521 helper_
->DeleteFramebuffersImmediate(n
, framebuffers
);
2524 void GLES2Implementation::DeleteRenderbuffersHelper(
2525 GLsizei n
, const GLuint
* renderbuffers
) {
2526 if (!GetIdHandler(id_namespaces::kRenderbuffers
)->FreeIds(
2527 this, n
, renderbuffers
, &GLES2Implementation::DeleteRenderbuffersStub
)) {
2530 "glDeleteRenderbuffers", "id not created by this context.");
2533 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
2534 if (renderbuffers
[ii
] == bound_renderbuffer_
) {
2535 bound_renderbuffer_
= 0;
2540 void GLES2Implementation::DeleteRenderbuffersStub(
2541 GLsizei n
, const GLuint
* renderbuffers
) {
2542 helper_
->DeleteRenderbuffersImmediate(n
, renderbuffers
);
2545 void GLES2Implementation::DeleteTexturesHelper(
2546 GLsizei n
, const GLuint
* textures
) {
2547 if (!GetIdHandler(id_namespaces::kTextures
)->FreeIds(
2548 this, n
, textures
, &GLES2Implementation::DeleteTexturesStub
)) {
2551 "glDeleteTextures", "id not created by this context.");
2554 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
2555 for (GLint tt
= 0; tt
< capabilities_
.max_combined_texture_image_units
;
2557 TextureUnit
& unit
= texture_units_
[tt
];
2558 if (textures
[ii
] == unit
.bound_texture_2d
) {
2559 unit
.bound_texture_2d
= 0;
2561 if (textures
[ii
] == unit
.bound_texture_cube_map
) {
2562 unit
.bound_texture_cube_map
= 0;
2564 if (textures
[ii
] == unit
.bound_texture_external_oes
) {
2565 unit
.bound_texture_external_oes
= 0;
2571 void GLES2Implementation::DeleteTexturesStub(GLsizei n
,
2572 const GLuint
* textures
) {
2573 helper_
->DeleteTexturesImmediate(n
, textures
);
2576 void GLES2Implementation::DeleteVertexArraysOESHelper(
2577 GLsizei n
, const GLuint
* arrays
) {
2578 vertex_array_object_manager_
->DeleteVertexArrays(n
, arrays
);
2579 if (!GetIdHandler(id_namespaces::kVertexArrays
)->FreeIds(
2580 this, n
, arrays
, &GLES2Implementation::DeleteVertexArraysOESStub
)) {
2583 "glDeleteVertexArraysOES", "id not created by this context.");
2588 void GLES2Implementation::DeleteVertexArraysOESStub(
2589 GLsizei n
, const GLuint
* arrays
) {
2590 helper_
->DeleteVertexArraysOESImmediate(n
, arrays
);
2593 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
2595 const GLuint
* valuebuffers
) {
2596 if (!GetIdHandler(id_namespaces::kValuebuffers
)
2597 ->FreeIds(this, n
, valuebuffers
,
2598 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub
)) {
2599 SetGLError(GL_INVALID_VALUE
, "glDeleteValuebuffersCHROMIUM",
2600 "id not created by this context.");
2603 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
2604 if (valuebuffers
[ii
] == bound_valuebuffer_
) {
2605 bound_valuebuffer_
= 0;
2610 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
2612 const GLuint
* valuebuffers
) {
2613 helper_
->DeleteValuebuffersCHROMIUMImmediate(n
, valuebuffers
);
2616 void GLES2Implementation::DisableVertexAttribArray(GLuint index
) {
2617 GPU_CLIENT_SINGLE_THREAD_CHECK();
2619 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index
<< ")");
2620 vertex_array_object_manager_
->SetAttribEnable(index
, false);
2621 helper_
->DisableVertexAttribArray(index
);
2625 void GLES2Implementation::EnableVertexAttribArray(GLuint index
) {
2626 GPU_CLIENT_SINGLE_THREAD_CHECK();
2627 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
2629 vertex_array_object_manager_
->SetAttribEnable(index
, true);
2630 helper_
->EnableVertexAttribArray(index
);
2634 void GLES2Implementation::DrawArrays(GLenum mode
, GLint first
, GLsizei count
) {
2635 GPU_CLIENT_SINGLE_THREAD_CHECK();
2636 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
2637 << GLES2Util::GetStringDrawMode(mode
) << ", "
2638 << first
<< ", " << count
<< ")");
2640 SetGLError(GL_INVALID_VALUE
, "glDrawArrays", "count < 0");
2643 bool simulated
= false;
2644 if (!vertex_array_object_manager_
->SetupSimulatedClientSideBuffers(
2645 "glDrawArrays", this, helper_
, first
+ count
, 0, &simulated
)) {
2648 helper_
->DrawArrays(mode
, first
, count
);
2649 RestoreArrayBuffer(simulated
);
2653 void GLES2Implementation::GetVertexAttribfv(
2654 GLuint index
, GLenum pname
, GLfloat
* params
) {
2655 GPU_CLIENT_SINGLE_THREAD_CHECK();
2656 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
2658 << GLES2Util::GetStringVertexAttribute(pname
) << ", "
2659 << static_cast<const void*>(params
) << ")");
2661 if (vertex_array_object_manager_
->GetVertexAttrib(index
, pname
, &value
)) {
2662 *params
= static_cast<float>(value
);
2665 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
2666 typedef cmds::GetVertexAttribfv::Result Result
;
2667 Result
* result
= GetResultAs
<Result
*>();
2671 result
->SetNumResults(0);
2672 helper_
->GetVertexAttribfv(
2673 index
, pname
, GetResultShmId(), GetResultShmOffset());
2675 result
->CopyResult(params
);
2676 GPU_CLIENT_LOG_CODE_BLOCK({
2677 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2678 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2684 void GLES2Implementation::GetVertexAttribiv(
2685 GLuint index
, GLenum pname
, GLint
* params
) {
2686 GPU_CLIENT_SINGLE_THREAD_CHECK();
2687 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
2689 << GLES2Util::GetStringVertexAttribute(pname
) << ", "
2690 << static_cast<const void*>(params
) << ")");
2692 if (vertex_array_object_manager_
->GetVertexAttrib(index
, pname
, &value
)) {
2696 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
2697 typedef cmds::GetVertexAttribiv::Result Result
;
2698 Result
* result
= GetResultAs
<Result
*>();
2702 result
->SetNumResults(0);
2703 helper_
->GetVertexAttribiv(
2704 index
, pname
, GetResultShmId(), GetResultShmOffset());
2706 result
->CopyResult(params
);
2707 GPU_CLIENT_LOG_CODE_BLOCK({
2708 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2709 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2715 void GLES2Implementation::Swap() {
2719 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect
& sub_buffer
) {
2720 PostSubBufferCHROMIUM(
2721 sub_buffer
.x(), sub_buffer
.y(), sub_buffer
.width(), sub_buffer
.height());
2724 static GLenum
GetGLESOverlayTransform(gfx::OverlayTransform plane_transform
) {
2725 switch (plane_transform
) {
2726 case gfx::OVERLAY_TRANSFORM_INVALID
:
2728 case gfx::OVERLAY_TRANSFORM_NONE
:
2729 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM
;
2730 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL
:
2731 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM
;
2732 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL
:
2733 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM
;
2734 case gfx::OVERLAY_TRANSFORM_ROTATE_90
:
2735 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM
;
2736 case gfx::OVERLAY_TRANSFORM_ROTATE_180
:
2737 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM
;
2738 case gfx::OVERLAY_TRANSFORM_ROTATE_270
:
2739 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM
;
2742 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM
;
2745 void GLES2Implementation::ScheduleOverlayPlane(
2747 gfx::OverlayTransform plane_transform
,
2748 unsigned overlay_texture_id
,
2749 const gfx::Rect
& display_bounds
,
2750 const gfx::RectF
& uv_rect
) {
2751 ScheduleOverlayPlaneCHROMIUM(plane_z_order
,
2752 GetGLESOverlayTransform(plane_transform
),
2756 display_bounds
.width(),
2757 display_bounds
.height(),
2764 GLboolean
GLES2Implementation::EnableFeatureCHROMIUM(
2765 const char* feature
) {
2766 GPU_CLIENT_SINGLE_THREAD_CHECK();
2767 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
2769 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
2770 typedef cmds::EnableFeatureCHROMIUM::Result Result
;
2771 Result
* result
= GetResultAs
<Result
*>();
2776 SetBucketAsCString(kResultBucketId
, feature
);
2777 helper_
->EnableFeatureCHROMIUM(
2778 kResultBucketId
, GetResultShmId(), GetResultShmOffset());
2780 helper_
->SetBucketSize(kResultBucketId
, 0);
2781 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result
));
2782 return *result
!= 0;
2785 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
2786 GLuint target
, GLintptr offset
, GLsizeiptr size
, GLenum access
) {
2787 GPU_CLIENT_SINGLE_THREAD_CHECK();
2788 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
2789 << target
<< ", " << offset
<< ", " << size
<< ", "
2790 << GLES2Util::GetStringEnum(access
) << ")");
2791 // NOTE: target is NOT checked because the service will check it
2792 // and we don't know what targets are valid.
2793 if (access
!= GL_WRITE_ONLY
) {
2794 SetGLErrorInvalidEnum(
2795 "glMapBufferSubDataCHROMIUM", access
, "access");
2798 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size
) ||
2799 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset
)) {
2804 unsigned int shm_offset
;
2805 void* mem
= mapped_memory_
->Alloc(size
, &shm_id
, &shm_offset
);
2807 SetGLError(GL_OUT_OF_MEMORY
, "glMapBufferSubDataCHROMIUM", "out of memory");
2811 std::pair
<MappedBufferMap::iterator
, bool> result
=
2812 mapped_buffers_
.insert(std::make_pair(
2815 access
, shm_id
, mem
, shm_offset
, target
, offset
, size
)));
2816 DCHECK(result
.second
);
2817 GPU_CLIENT_LOG(" returned " << mem
);
2821 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem
) {
2822 GPU_CLIENT_SINGLE_THREAD_CHECK();
2824 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem
<< ")");
2825 MappedBufferMap::iterator it
= mapped_buffers_
.find(mem
);
2826 if (it
== mapped_buffers_
.end()) {
2828 GL_INVALID_VALUE
, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
2831 const MappedBuffer
& mb
= it
->second
;
2832 helper_
->BufferSubData(
2833 mb
.target
, mb
.offset
, mb
.size
, mb
.shm_id
, mb
.shm_offset
);
2834 mapped_memory_
->FreePendingToken(mb
.shm_memory
, helper_
->InsertToken());
2835 mapped_buffers_
.erase(it
);
2839 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
2849 GPU_CLIENT_SINGLE_THREAD_CHECK();
2850 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
2851 << target
<< ", " << level
<< ", "
2852 << xoffset
<< ", " << yoffset
<< ", "
2853 << width
<< ", " << height
<< ", "
2854 << GLES2Util::GetStringTextureFormat(format
) << ", "
2855 << GLES2Util::GetStringPixelType(type
) << ", "
2856 << GLES2Util::GetStringEnum(access
) << ")");
2857 if (access
!= GL_WRITE_ONLY
) {
2858 SetGLErrorInvalidEnum(
2859 "glMapTexSubImage2DCHROMIUM", access
, "access");
2862 // NOTE: target is NOT checked because the service will check it
2863 // and we don't know what targets are valid.
2864 if (level
< 0 || xoffset
< 0 || yoffset
< 0 || width
< 0 || height
< 0) {
2866 GL_INVALID_VALUE
, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
2870 if (!GLES2Util::ComputeImageDataSizes(
2871 width
, height
, format
, type
, unpack_alignment_
, &size
, NULL
, NULL
)) {
2873 GL_INVALID_VALUE
, "glMapTexSubImage2DCHROMIUM", "image size too large");
2877 unsigned int shm_offset
;
2878 void* mem
= mapped_memory_
->Alloc(size
, &shm_id
, &shm_offset
);
2880 SetGLError(GL_OUT_OF_MEMORY
, "glMapTexSubImage2DCHROMIUM", "out of memory");
2884 std::pair
<MappedTextureMap::iterator
, bool> result
=
2885 mapped_textures_
.insert(std::make_pair(
2888 access
, shm_id
, mem
, shm_offset
,
2889 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
)));
2890 DCHECK(result
.second
);
2891 GPU_CLIENT_LOG(" returned " << mem
);
2895 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem
) {
2896 GPU_CLIENT_SINGLE_THREAD_CHECK();
2898 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem
<< ")");
2899 MappedTextureMap::iterator it
= mapped_textures_
.find(mem
);
2900 if (it
== mapped_textures_
.end()) {
2902 GL_INVALID_VALUE
, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
2905 const MappedTexture
& mt
= it
->second
;
2906 helper_
->TexSubImage2D(
2907 mt
.target
, mt
.level
, mt
.xoffset
, mt
.yoffset
, mt
.width
, mt
.height
,
2908 mt
.format
, mt
.type
, mt
.shm_id
, mt
.shm_offset
, GL_FALSE
);
2909 mapped_memory_
->FreePendingToken(mt
.shm_memory
, helper_
->InsertToken());
2910 mapped_textures_
.erase(it
);
2914 void GLES2Implementation::ResizeCHROMIUM(GLuint width
, GLuint height
,
2915 float scale_factor
) {
2916 GPU_CLIENT_SINGLE_THREAD_CHECK();
2917 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
2918 << width
<< ", " << height
<< ", " << scale_factor
<< ")");
2919 helper_
->ResizeCHROMIUM(width
, height
, scale_factor
);
2923 const GLchar
* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
2924 GPU_CLIENT_SINGLE_THREAD_CHECK();
2925 GPU_CLIENT_LOG("[" << GetLogPrefix()
2926 << "] glGetRequestableExtensionsCHROMIUM()");
2928 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
2929 const char* result
= NULL
;
2930 // Clear the bucket so if the command fails nothing will be in it.
2931 helper_
->SetBucketSize(kResultBucketId
, 0);
2932 helper_
->GetRequestableExtensionsCHROMIUM(kResultBucketId
);
2934 if (GetBucketAsString(kResultBucketId
, &str
)) {
2935 // The set of requestable extensions shrinks as we enable
2936 // them. Because we don't know when the client will stop referring
2937 // to a previous one it queries (see GetString) we need to cache
2938 // the unique results.
2939 std::set
<std::string
>::const_iterator sit
=
2940 requestable_extensions_set_
.find(str
);
2941 if (sit
!= requestable_extensions_set_
.end()) {
2942 result
= sit
->c_str();
2944 std::pair
<std::set
<std::string
>::const_iterator
, bool> insert_result
=
2945 requestable_extensions_set_
.insert(str
);
2946 DCHECK(insert_result
.second
);
2947 result
= insert_result
.first
->c_str();
2950 GPU_CLIENT_LOG(" returned " << result
);
2951 return reinterpret_cast<const GLchar
*>(result
);
2954 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
2955 // with VirtualGL contexts.
2956 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension
) {
2957 GPU_CLIENT_SINGLE_THREAD_CHECK();
2958 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
2959 << extension
<< ")");
2960 SetBucketAsCString(kResultBucketId
, extension
);
2961 helper_
->RequestExtensionCHROMIUM(kResultBucketId
);
2962 helper_
->SetBucketSize(kResultBucketId
, 0);
2964 struct ExtensionCheck
{
2965 const char* extension
;
2966 ExtensionStatus
* status
;
2968 const ExtensionCheck checks
[] = {
2970 "GL_ANGLE_pack_reverse_row_order",
2971 &angle_pack_reverse_row_order_status_
,
2974 "GL_CHROMIUM_framebuffer_multisample",
2975 &chromium_framebuffer_multisample_
,
2978 const size_t kNumChecks
= sizeof(checks
)/sizeof(checks
[0]);
2979 for (size_t ii
= 0; ii
< kNumChecks
; ++ii
) {
2980 const ExtensionCheck
& check
= checks
[ii
];
2981 if (*check
.status
== kUnavailableExtensionStatus
&&
2982 !strcmp(extension
, check
.extension
)) {
2983 *check
.status
= kUnknownExtensionStatus
;
2988 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
2989 GPU_CLIENT_SINGLE_THREAD_CHECK();
2990 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
2991 // Wait if this would add too many rate limit tokens.
2992 if (rate_limit_tokens_
.size() == kMaxSwapBuffers
) {
2993 helper_
->WaitForToken(rate_limit_tokens_
.front());
2994 rate_limit_tokens_
.pop();
2996 rate_limit_tokens_
.push(helper_
->InsertToken());
2999 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3000 GLuint program
, std::vector
<int8
>* result
) {
3002 // Clear the bucket so if the command fails nothing will be in it.
3003 helper_
->SetBucketSize(kResultBucketId
, 0);
3004 helper_
->GetProgramInfoCHROMIUM(program
, kResultBucketId
);
3005 GetBucketContents(kResultBucketId
, result
);
3008 void GLES2Implementation::GetProgramInfoCHROMIUM(
3009 GLuint program
, GLsizei bufsize
, GLsizei
* size
, void* info
) {
3010 GPU_CLIENT_SINGLE_THREAD_CHECK();
3013 GL_INVALID_VALUE
, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3017 SetGLError(GL_INVALID_VALUE
, "glProgramInfoCHROMIUM", "size is null.");
3020 // Make sure they've set size to 0 else the value will be undefined on
3022 DCHECK_EQ(0, *size
);
3023 std::vector
<int8
> result
;
3024 GetProgramInfoCHROMIUMHelper(program
, &result
);
3025 if (result
.empty()) {
3028 *size
= result
.size();
3032 if (static_cast<size_t>(bufsize
) < result
.size()) {
3033 SetGLError(GL_INVALID_OPERATION
,
3034 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3037 memcpy(info
, &result
[0], result
.size());
3040 GLuint
GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture
) {
3041 GPU_CLIENT_SINGLE_THREAD_CHECK();
3042 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
3044 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
3045 helper_
->CommandBufferHelper::Flush();
3046 return gpu_control_
->CreateStreamTexture(texture
);
3049 void GLES2Implementation::PostSubBufferCHROMIUM(
3050 GLint x
, GLint y
, GLint width
, GLint height
) {
3051 GPU_CLIENT_SINGLE_THREAD_CHECK();
3052 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
3053 << x
<< ", " << y
<< ", " << width
<< ", " << height
<< ")");
3054 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
3055 "width", width
, "height", height
);
3057 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
3058 swap_buffers_tokens_
.push(helper_
->InsertToken());
3059 helper_
->PostSubBufferCHROMIUM(x
, y
, width
, height
);
3060 helper_
->CommandBufferHelper::Flush();
3061 if (swap_buffers_tokens_
.size() > kMaxSwapBuffers
+ 1) {
3062 helper_
->WaitForToken(swap_buffers_tokens_
.front());
3063 swap_buffers_tokens_
.pop();
3067 void GLES2Implementation::DeleteQueriesEXTHelper(
3068 GLsizei n
, const GLuint
* queries
) {
3069 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
3070 query_tracker_
->RemoveQuery(queries
[ii
]);
3071 query_id_allocator_
->FreeID(queries
[ii
]);
3074 helper_
->DeleteQueriesEXTImmediate(n
, queries
);
3077 GLboolean
GLES2Implementation::IsQueryEXT(GLuint id
) {
3078 GPU_CLIENT_SINGLE_THREAD_CHECK();
3079 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id
<< ")");
3081 // TODO(gman): To be spec compliant IDs from other contexts sharing
3082 // resources need to return true here even though you can't share
3083 // queries across contexts?
3084 return query_tracker_
->GetQuery(id
) != NULL
;
3087 void GLES2Implementation::BeginQueryEXT(GLenum target
, GLuint id
) {
3088 GPU_CLIENT_SINGLE_THREAD_CHECK();
3089 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
3090 << GLES2Util::GetStringQueryTarget(target
)
3091 << ", " << id
<< ")");
3093 // if any outstanding queries INV_OP
3094 QueryMap::iterator it
= current_queries_
.find(target
);
3095 if (it
!= current_queries_
.end()) {
3097 GL_INVALID_OPERATION
, "glBeginQueryEXT", "query already in progress");
3103 SetGLError(GL_INVALID_OPERATION
, "glBeginQueryEXT", "id is 0");
3107 // if not GENned INV_OPERATION
3108 if (!query_id_allocator_
->InUse(id
)) {
3109 SetGLError(GL_INVALID_OPERATION
, "glBeginQueryEXT", "invalid id");
3113 // if id does not have an object
3114 QueryTracker::Query
* query
= query_tracker_
->GetQuery(id
);
3116 query
= query_tracker_
->CreateQuery(id
, target
);
3118 SetGLError(GL_OUT_OF_MEMORY
,
3120 "transfer buffer allocation failed");
3123 } else if (query
->target() != target
) {
3125 GL_INVALID_OPERATION
, "glBeginQueryEXT", "target does not match");
3129 current_queries_
[target
] = query
;
3135 void GLES2Implementation::EndQueryEXT(GLenum target
) {
3136 GPU_CLIENT_SINGLE_THREAD_CHECK();
3137 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
3138 << GLES2Util::GetStringQueryTarget(target
) << ")");
3139 // Don't do anything if the context is lost.
3140 if (helper_
->IsContextLost()) {
3144 QueryMap::iterator it
= current_queries_
.find(target
);
3145 if (it
== current_queries_
.end()) {
3146 SetGLError(GL_INVALID_OPERATION
, "glEndQueryEXT", "no active query");
3150 QueryTracker::Query
* query
= it
->second
;
3152 current_queries_
.erase(it
);
3156 void GLES2Implementation::GetQueryivEXT(
3157 GLenum target
, GLenum pname
, GLint
* params
) {
3158 GPU_CLIENT_SINGLE_THREAD_CHECK();
3159 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
3160 << GLES2Util::GetStringQueryTarget(target
) << ", "
3161 << GLES2Util::GetStringQueryParameter(pname
) << ", "
3162 << static_cast<const void*>(params
) << ")");
3164 if (pname
!= GL_CURRENT_QUERY_EXT
) {
3165 SetGLErrorInvalidEnum("glGetQueryivEXT", pname
, "pname");
3168 QueryMap::iterator it
= current_queries_
.find(target
);
3169 if (it
!= current_queries_
.end()) {
3170 QueryTracker::Query
* query
= it
->second
;
3171 *params
= query
->id();
3175 GPU_CLIENT_LOG(" " << *params
);
3179 void GLES2Implementation::GetQueryObjectuivEXT(
3180 GLuint id
, GLenum pname
, GLuint
* params
) {
3181 GPU_CLIENT_SINGLE_THREAD_CHECK();
3182 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id
<< ", "
3183 << GLES2Util::GetStringQueryObjectParameter(pname
) << ", "
3184 << static_cast<const void*>(params
) << ")");
3186 QueryTracker::Query
* query
= query_tracker_
->GetQuery(id
);
3188 SetGLError(GL_INVALID_OPERATION
, "glQueryObjectuivEXT", "unknown query id");
3192 QueryMap::iterator it
= current_queries_
.find(query
->target());
3193 if (it
!= current_queries_
.end()) {
3195 GL_INVALID_OPERATION
,
3196 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
3200 if (query
->NeverUsed()) {
3202 GL_INVALID_OPERATION
,
3203 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
3208 case GL_QUERY_RESULT_EXT
:
3209 if (!query
->CheckResultsAvailable(helper_
)) {
3210 helper_
->WaitForToken(query
->token());
3211 if (!query
->CheckResultsAvailable(helper_
)) {
3213 CHECK(query
->CheckResultsAvailable(helper_
));
3216 *params
= query
->GetResult();
3218 case GL_QUERY_RESULT_AVAILABLE_EXT
:
3219 *params
= query
->CheckResultsAvailable(helper_
);
3222 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname
, "pname");
3225 GPU_CLIENT_LOG(" " << *params
);
3229 void GLES2Implementation::DrawArraysInstancedANGLE(
3230 GLenum mode
, GLint first
, GLsizei count
, GLsizei primcount
) {
3231 GPU_CLIENT_SINGLE_THREAD_CHECK();
3232 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
3233 << GLES2Util::GetStringDrawMode(mode
) << ", "
3234 << first
<< ", " << count
<< ", " << primcount
<< ")");
3236 SetGLError(GL_INVALID_VALUE
, "glDrawArraysInstancedANGLE", "count < 0");
3239 if (primcount
< 0) {
3240 SetGLError(GL_INVALID_VALUE
, "glDrawArraysInstancedANGLE", "primcount < 0");
3243 if (primcount
== 0) {
3246 bool simulated
= false;
3247 if (!vertex_array_object_manager_
->SetupSimulatedClientSideBuffers(
3248 "glDrawArraysInstancedANGLE", this, helper_
, first
+ count
, primcount
,
3252 helper_
->DrawArraysInstancedANGLE(mode
, first
, count
, primcount
);
3253 RestoreArrayBuffer(simulated
);
3257 void GLES2Implementation::DrawElementsInstancedANGLE(
3258 GLenum mode
, GLsizei count
, GLenum type
, const void* indices
,
3259 GLsizei primcount
) {
3260 GPU_CLIENT_SINGLE_THREAD_CHECK();
3261 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
3262 << GLES2Util::GetStringDrawMode(mode
) << ", "
3264 << GLES2Util::GetStringIndexType(type
) << ", "
3265 << static_cast<const void*>(indices
) << ", "
3266 << primcount
<< ")");
3268 SetGLError(GL_INVALID_VALUE
,
3269 "glDrawElementsInstancedANGLE", "count less than 0.");
3275 if (primcount
< 0) {
3276 SetGLError(GL_INVALID_VALUE
,
3277 "glDrawElementsInstancedANGLE", "primcount < 0");
3280 if (primcount
== 0) {
3283 if (vertex_array_object_manager_
->bound_element_array_buffer() != 0 &&
3284 !ValidateOffset("glDrawElementsInstancedANGLE",
3285 reinterpret_cast<GLintptr
>(indices
))) {
3289 bool simulated
= false;
3290 if (!vertex_array_object_manager_
->SetupSimulatedIndexAndClientSideBuffers(
3291 "glDrawElementsInstancedANGLE", this, helper_
, count
, type
, primcount
,
3292 indices
, &offset
, &simulated
)) {
3295 helper_
->DrawElementsInstancedANGLE(mode
, count
, type
, offset
, primcount
);
3296 RestoreElementAndArrayBuffers(simulated
);
3300 void GLES2Implementation::GenMailboxCHROMIUM(
3302 GPU_CLIENT_SINGLE_THREAD_CHECK();
3303 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
3304 << static_cast<const void*>(mailbox
) << ")");
3305 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
3307 gpu::Mailbox result
= gpu::Mailbox::Generate();
3308 memcpy(mailbox
, result
.name
, sizeof(result
.name
));
3311 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target
,
3312 const GLbyte
* data
) {
3313 GPU_CLIENT_SINGLE_THREAD_CHECK();
3314 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
3315 << static_cast<const void*>(data
) << ")");
3316 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
3317 DCHECK(mailbox
.Verify()) << "ProduceTextureCHROMIUM was passed a "
3318 "mailbox that was not generated by "
3319 "GenMailboxCHROMIUM.";
3320 helper_
->ProduceTextureCHROMIUMImmediate(target
, data
);
3324 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
3325 GLuint texture
, GLenum target
, const GLbyte
* data
) {
3326 GPU_CLIENT_SINGLE_THREAD_CHECK();
3327 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
3328 << static_cast<const void*>(data
) << ")");
3329 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
3330 DCHECK(mailbox
.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
3331 "mailbox that was not generated by "
3332 "GenMailboxCHROMIUM.";
3333 helper_
->ProduceTextureDirectCHROMIUMImmediate(texture
, target
, data
);
3337 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target
,
3338 const GLbyte
* data
) {
3339 GPU_CLIENT_SINGLE_THREAD_CHECK();
3340 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
3341 << static_cast<const void*>(data
) << ")");
3342 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
3343 DCHECK(mailbox
.Verify()) << "ConsumeTextureCHROMIUM was passed a "
3344 "mailbox that was not generated by "
3345 "GenMailboxCHROMIUM.";
3346 helper_
->ConsumeTextureCHROMIUMImmediate(target
, data
);
3350 GLuint
GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
3351 GLenum target
, const GLbyte
* data
) {
3352 GPU_CLIENT_SINGLE_THREAD_CHECK();
3353 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
3354 << static_cast<const void*>(data
) << ")");
3355 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
3356 DCHECK(mailbox
.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
3357 "mailbox that was not generated by "
3358 "GenMailboxCHROMIUM.";
3360 GetIdHandler(id_namespaces::kTextures
)->MakeIds(this, 0, 1, &client_id
);
3361 helper_
->CreateAndConsumeTextureCHROMIUMImmediate(target
,
3363 if (share_group_
->bind_generates_resource())
3364 helper_
->CommandBufferHelper::Flush();
3369 void GLES2Implementation::PushGroupMarkerEXT(
3370 GLsizei length
, const GLchar
* marker
) {
3371 GPU_CLIENT_SINGLE_THREAD_CHECK();
3372 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
3373 << length
<< ", " << marker
<< ")");
3379 (length
? std::string(marker
, length
) : std::string(marker
)));
3380 helper_
->PushGroupMarkerEXT(kResultBucketId
);
3381 helper_
->SetBucketSize(kResultBucketId
, 0);
3382 debug_marker_manager_
.PushGroup(
3383 length
? std::string(marker
, length
) : std::string(marker
));
3386 void GLES2Implementation::InsertEventMarkerEXT(
3387 GLsizei length
, const GLchar
* marker
) {
3388 GPU_CLIENT_SINGLE_THREAD_CHECK();
3389 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
3390 << length
<< ", " << marker
<< ")");
3396 (length
? std::string(marker
, length
) : std::string(marker
)));
3397 helper_
->InsertEventMarkerEXT(kResultBucketId
);
3398 helper_
->SetBucketSize(kResultBucketId
, 0);
3399 debug_marker_manager_
.SetMarker(
3400 length
? std::string(marker
, length
) : std::string(marker
));
3403 void GLES2Implementation::PopGroupMarkerEXT() {
3404 GPU_CLIENT_SINGLE_THREAD_CHECK();
3405 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
3406 helper_
->PopGroupMarkerEXT();
3407 debug_marker_manager_
.PopGroup();
3410 void GLES2Implementation::TraceBeginCHROMIUM(const char* name
) {
3411 GPU_CLIENT_SINGLE_THREAD_CHECK();
3412 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
3414 if (current_trace_name_
.get()) {
3415 SetGLError(GL_INVALID_OPERATION
, "glTraceBeginCHROMIUM",
3416 "trace already running");
3419 TRACE_EVENT_COPY_ASYNC_BEGIN0("gpu", name
, this);
3420 SetBucketAsCString(kResultBucketId
, name
);
3421 helper_
->TraceBeginCHROMIUM(kResultBucketId
);
3422 helper_
->SetBucketSize(kResultBucketId
, 0);
3423 current_trace_name_
.reset(new std::string(name
));
3426 void GLES2Implementation::TraceEndCHROMIUM() {
3427 GPU_CLIENT_SINGLE_THREAD_CHECK();
3428 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
3429 if (!current_trace_name_
.get()) {
3430 SetGLError(GL_INVALID_OPERATION
, "glTraceEndCHROMIUM",
3431 "missing begin trace");
3434 helper_
->TraceEndCHROMIUM();
3435 TRACE_EVENT_COPY_ASYNC_END0("gpu", current_trace_name_
->c_str(), this);
3436 current_trace_name_
.reset();
3439 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target
, GLenum access
) {
3440 GPU_CLIENT_SINGLE_THREAD_CHECK();
3441 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
3442 << target
<< ", " << GLES2Util::GetStringEnum(access
) << ")");
3444 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
:
3445 if (access
!= GL_READ_ONLY
) {
3446 SetGLError(GL_INVALID_ENUM
, "glMapBufferCHROMIUM", "bad access mode");
3450 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
:
3451 if (access
!= GL_WRITE_ONLY
) {
3452 SetGLError(GL_INVALID_ENUM
, "glMapBufferCHROMIUM", "bad access mode");
3458 GL_INVALID_ENUM
, "glMapBufferCHROMIUM", "invalid target");
3462 GetBoundPixelTransferBuffer(target
, "glMapBufferCHROMIUM", &buffer_id
);
3466 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
3468 SetGLError(GL_INVALID_OPERATION
, "glMapBufferCHROMIUM", "invalid buffer");
3471 if (buffer
->mapped()) {
3472 SetGLError(GL_INVALID_OPERATION
, "glMapBufferCHROMIUM", "already mapped");
3475 // Here we wait for previous transfer operations to be finished.
3476 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
3477 // with this method of synchronization. Until this is fixed,
3478 // MapBufferCHROMIUM will not block even if the transfer is not ready
3480 if (buffer
->last_usage_token()) {
3481 helper_
->WaitForToken(buffer
->last_usage_token());
3482 buffer
->set_last_usage_token(0);
3484 buffer
->set_mapped(true);
3486 GPU_CLIENT_LOG(" returned " << buffer
->address());
3488 return buffer
->address();
3491 GLboolean
GLES2Implementation::UnmapBufferCHROMIUM(GLuint target
) {
3492 GPU_CLIENT_SINGLE_THREAD_CHECK();
3494 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target
<< ")");
3496 if (!GetBoundPixelTransferBuffer(target
, "glMapBufferCHROMIUM", &buffer_id
)) {
3497 SetGLError(GL_INVALID_ENUM
, "glUnmapBufferCHROMIUM", "invalid target");
3502 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
3504 SetGLError(GL_INVALID_OPERATION
, "glUnmapBufferCHROMIUM", "invalid buffer");
3507 if (!buffer
->mapped()) {
3508 SetGLError(GL_INVALID_OPERATION
, "glUnmapBufferCHROMIUM", "not mapped");
3511 buffer
->set_mapped(false);
3516 bool GLES2Implementation::EnsureAsyncUploadSync() {
3517 if (async_upload_sync_
)
3521 unsigned int shm_offset
;
3522 void* mem
= mapped_memory_
->Alloc(sizeof(AsyncUploadSync
),
3528 async_upload_sync_shm_id_
= shm_id
;
3529 async_upload_sync_shm_offset_
= shm_offset
;
3530 async_upload_sync_
= static_cast<AsyncUploadSync
*>(mem
);
3531 async_upload_sync_
->Reset();
3536 uint32
GLES2Implementation::NextAsyncUploadToken() {
3537 async_upload_token_
++;
3538 if (async_upload_token_
== 0)
3539 async_upload_token_
++;
3540 return async_upload_token_
;
3543 void GLES2Implementation::PollAsyncUploads() {
3544 if (!async_upload_sync_
)
3547 if (helper_
->IsContextLost()) {
3548 DetachedAsyncUploadMemoryList::iterator it
=
3549 detached_async_upload_memory_
.begin();
3550 while (it
!= detached_async_upload_memory_
.end()) {
3551 mapped_memory_
->Free(it
->first
);
3552 it
= detached_async_upload_memory_
.erase(it
);
3557 DetachedAsyncUploadMemoryList::iterator it
=
3558 detached_async_upload_memory_
.begin();
3559 while (it
!= detached_async_upload_memory_
.end()) {
3560 if (HasAsyncUploadTokenPassed(it
->second
)) {
3561 mapped_memory_
->Free(it
->first
);
3562 it
= detached_async_upload_memory_
.erase(it
);
3569 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
3570 // Free all completed unmanaged async uploads buffers.
3573 // Synchronously free rest of the unmanaged async upload buffers.
3574 if (!detached_async_upload_memory_
.empty()) {
3575 WaitAllAsyncTexImage2DCHROMIUM();
3581 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
3582 GLenum target
, GLint level
, GLenum internalformat
, GLsizei width
,
3583 GLsizei height
, GLint border
, GLenum format
, GLenum type
,
3584 const void* pixels
) {
3585 GPU_CLIENT_SINGLE_THREAD_CHECK();
3586 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
3587 << GLES2Util::GetStringTextureTarget(target
) << ", "
3589 << GLES2Util::GetStringTextureInternalFormat(internalformat
) << ", "
3590 << width
<< ", " << height
<< ", " << border
<< ", "
3591 << GLES2Util::GetStringTextureFormat(format
) << ", "
3592 << GLES2Util::GetStringPixelType(type
) << ", "
3593 << static_cast<const void*>(pixels
) << ")");
3594 if (level
< 0 || height
< 0 || width
< 0) {
3595 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "dimension < 0");
3599 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "border != 0");
3603 uint32 unpadded_row_size
;
3604 uint32 padded_row_size
;
3605 if (!GLES2Util::ComputeImageDataSizes(
3606 width
, height
, format
, type
, unpack_alignment_
, &size
,
3607 &unpadded_row_size
, &padded_row_size
)) {
3608 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "image size too large");
3612 // If there's no data/buffer just issue the AsyncTexImage2D
3613 if (!pixels
&& !bound_pixel_unpack_transfer_buffer_id_
) {
3614 helper_
->AsyncTexImage2DCHROMIUM(
3615 target
, level
, internalformat
, width
, height
, format
, type
,
3620 if (!EnsureAsyncUploadSync()) {
3621 SetGLError(GL_OUT_OF_MEMORY
, "glTexImage2D", "out of memory");
3625 // Otherwise, async uploads require a transfer buffer to be bound.
3626 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3627 // the buffer before the transfer is finished. (Currently such
3628 // synchronization has to be handled manually.)
3629 GLuint offset
= ToGLuint(pixels
);
3630 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
3631 bound_pixel_unpack_transfer_buffer_id_
,
3632 "glAsyncTexImage2DCHROMIUM", offset
, size
);
3633 if (buffer
&& buffer
->shm_id() != -1) {
3634 uint32 async_token
= NextAsyncUploadToken();
3635 buffer
->set_last_async_upload_token(async_token
);
3636 helper_
->AsyncTexImage2DCHROMIUM(
3637 target
, level
, internalformat
, width
, height
, format
, type
,
3638 buffer
->shm_id(), buffer
->shm_offset() + offset
,
3640 async_upload_sync_shm_id_
, async_upload_sync_shm_offset_
);
3644 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
3645 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
3646 GLsizei height
, GLenum format
, GLenum type
, const void* pixels
) {
3647 GPU_CLIENT_SINGLE_THREAD_CHECK();
3648 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
3649 << GLES2Util::GetStringTextureTarget(target
) << ", "
3651 << xoffset
<< ", " << yoffset
<< ", "
3652 << width
<< ", " << height
<< ", "
3653 << GLES2Util::GetStringTextureFormat(format
) << ", "
3654 << GLES2Util::GetStringPixelType(type
) << ", "
3655 << static_cast<const void*>(pixels
) << ")");
3656 if (level
< 0 || height
< 0 || width
< 0) {
3658 GL_INVALID_VALUE
, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
3663 uint32 unpadded_row_size
;
3664 uint32 padded_row_size
;
3665 if (!GLES2Util::ComputeImageDataSizes(
3666 width
, height
, format
, type
, unpack_alignment_
, &size
,
3667 &unpadded_row_size
, &padded_row_size
)) {
3669 GL_INVALID_VALUE
, "glAsyncTexSubImage2DCHROMIUM", "size to large");
3673 if (!EnsureAsyncUploadSync()) {
3674 SetGLError(GL_OUT_OF_MEMORY
, "glTexImage2D", "out of memory");
3678 // Async uploads require a transfer buffer to be bound.
3679 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3680 // the buffer before the transfer is finished. (Currently such
3681 // synchronization has to be handled manually.)
3682 GLuint offset
= ToGLuint(pixels
);
3683 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
3684 bound_pixel_unpack_transfer_buffer_id_
,
3685 "glAsyncTexSubImage2DCHROMIUM", offset
, size
);
3686 if (buffer
&& buffer
->shm_id() != -1) {
3687 uint32 async_token
= NextAsyncUploadToken();
3688 buffer
->set_last_async_upload_token(async_token
);
3689 helper_
->AsyncTexSubImage2DCHROMIUM(
3690 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
,
3691 buffer
->shm_id(), buffer
->shm_offset() + offset
,
3693 async_upload_sync_shm_id_
, async_upload_sync_shm_offset_
);
3697 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target
) {
3698 GPU_CLIENT_SINGLE_THREAD_CHECK();
3699 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
3700 << GLES2Util::GetStringTextureTarget(target
) << ")");
3701 helper_
->WaitAsyncTexImage2DCHROMIUM(target
);
3705 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
3706 GPU_CLIENT_SINGLE_THREAD_CHECK();
3707 GPU_CLIENT_LOG("[" << GetLogPrefix()
3708 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
3709 helper_
->WaitAllAsyncTexImage2DCHROMIUM();
3713 GLuint
GLES2Implementation::InsertSyncPointCHROMIUM() {
3714 GPU_CLIENT_SINGLE_THREAD_CHECK();
3715 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
3716 helper_
->CommandBufferHelper::Flush();
3717 return gpu_control_
->InsertSyncPoint();
3720 GLuint
GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
3721 GPU_CLIENT_SINGLE_THREAD_CHECK();
3722 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
3723 DCHECK(capabilities_
.future_sync_points
);
3724 return gpu_control_
->InsertFutureSyncPoint();
3727 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point
) {
3728 GPU_CLIENT_SINGLE_THREAD_CHECK();
3729 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
3730 << sync_point
<< ")");
3731 DCHECK(capabilities_
.future_sync_points
);
3732 helper_
->CommandBufferHelper::Flush();
3733 gpu_control_
->RetireSyncPoint(sync_point
);
3738 bool ValidImageFormat(GLenum internalformat
) {
3739 switch (internalformat
) {
3748 bool ValidImageUsage(GLenum usage
) {
3750 case GL_MAP_CHROMIUM
:
3751 case GL_SCANOUT_CHROMIUM
:
3760 GLuint
GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer
,
3763 GLenum internalformat
) {
3765 SetGLError(GL_INVALID_VALUE
, "glCreateImageCHROMIUM", "width <= 0");
3770 SetGLError(GL_INVALID_VALUE
, "glCreateImageCHROMIUM", "height <= 0");
3774 if (!ValidImageFormat(internalformat
)) {
3775 SetGLError(GL_INVALID_VALUE
, "glCreateImageCHROMIUM", "invalid format");
3780 gpu_control_
->CreateImage(buffer
, width
, height
, internalformat
);
3782 SetGLError(GL_OUT_OF_MEMORY
, "glCreateImageCHROMIUM", "image_id < 0");
3788 GLuint
GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer
,
3791 GLenum internalformat
) {
3792 GPU_CLIENT_SINGLE_THREAD_CHECK();
3793 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
3794 << ", " << height
<< ", "
3795 << GLES2Util::GetStringImageInternalFormat(internalformat
)
3798 CreateImageCHROMIUMHelper(buffer
, width
, height
, internalformat
);
3803 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id
) {
3804 // Flush the command stream to make sure all pending commands
3805 // that may refer to the image_id are executed on the service side.
3806 helper_
->CommandBufferHelper::Flush();
3807 gpu_control_
->DestroyImage(image_id
);
3810 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id
) {
3811 GPU_CLIENT_SINGLE_THREAD_CHECK();
3812 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
3813 << image_id
<< ")");
3814 DestroyImageCHROMIUMHelper(image_id
);
3818 GLuint
GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
3821 GLenum internalformat
,
3825 GL_INVALID_VALUE
, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
3830 SetGLError(GL_INVALID_VALUE
,
3831 "glCreateGpuMemoryBufferImageCHROMIUM",
3836 if (!ValidImageFormat(internalformat
)) {
3837 SetGLError(GL_INVALID_VALUE
,
3838 "glCreateGpuMemoryBufferImageCHROMIUM",
3843 if (!ValidImageUsage(usage
)) {
3844 SetGLError(GL_INVALID_VALUE
,
3845 "glCreateGpuMemoryBufferImageCHROMIUM",
3850 // Flush the command stream to ensure ordering in case the newly
3851 // returned image_id has recently been in use with a different buffer.
3852 helper_
->CommandBufferHelper::Flush();
3853 int32_t image_id
= gpu_control_
->CreateGpuMemoryBufferImage(
3854 width
, height
, internalformat
, usage
);
3856 SetGLError(GL_OUT_OF_MEMORY
,
3857 "glCreateGpuMemoryBufferImageCHROMIUM",
3864 GLuint
GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
3867 GLenum internalformat
,
3869 GPU_CLIENT_SINGLE_THREAD_CHECK();
3870 GPU_CLIENT_LOG("[" << GetLogPrefix()
3871 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
3872 << ", " << height
<< ", "
3873 << GLES2Util::GetStringImageInternalFormat(internalformat
)
3874 << ", " << GLES2Util::GetStringImageUsage(usage
) << ")");
3875 GLuint image_id
= CreateGpuMemoryBufferImageCHROMIUMHelper(
3876 width
, height
, internalformat
, usage
);
3881 bool GLES2Implementation::ValidateSize(const char* func
, GLsizeiptr size
) {
3883 SetGLError(GL_INVALID_VALUE
, func
, "size < 0");
3886 if (!FitInt32NonNegative
<GLsizeiptr
>(size
)) {
3887 SetGLError(GL_INVALID_OPERATION
, func
, "size more than 32-bit");
3893 bool GLES2Implementation::ValidateOffset(const char* func
, GLintptr offset
) {
3895 SetGLError(GL_INVALID_VALUE
, func
, "offset < 0");
3898 if (!FitInt32NonNegative
<GLintptr
>(offset
)) {
3899 SetGLError(GL_INVALID_OPERATION
, func
, "offset more than 32-bit");
3905 // Include the auto-generated part of this file. We split this because it means
3906 // we can easily edit the non-auto generated parts right here in this file
3907 // instead of having to edit some template or the code generator.
3908 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
3910 } // namespace gles2