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>
11 #include <GLES3/gl3.h>
19 #include "base/bind.h"
20 #include "base/compiler_specific.h"
21 #include "base/numerics/safe_math.h"
22 #include "gpu/command_buffer/client/buffer_tracker.h"
23 #include "gpu/command_buffer/client/gpu_control.h"
24 #include "gpu/command_buffer/client/program_info_manager.h"
25 #include "gpu/command_buffer/client/query_tracker.h"
26 #include "gpu/command_buffer/client/transfer_buffer.h"
27 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
28 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
29 #include "gpu/command_buffer/common/trace_event.h"
31 #if defined(GPU_CLIENT_DEBUG)
32 #include "base/command_line.h"
33 #include "gpu/command_buffer/client/gpu_switches.h"
39 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
40 static GLuint
ToGLuint(const void* ptr
) {
41 return static_cast<GLuint
>(reinterpret_cast<size_t>(ptr
));
44 #if !defined(_MSC_VER)
45 const size_t GLES2Implementation::kMaxSizeOfSimpleResult
;
46 const unsigned int GLES2Implementation::kStartingOffset
;
49 GLES2Implementation::GLStaticState::GLStaticState() {
52 GLES2Implementation::GLStaticState::~GLStaticState() {
55 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
56 GLES2Implementation
* gles2_implementation
)
57 : gles2_implementation_(gles2_implementation
) {
58 CHECK_EQ(0, gles2_implementation_
->use_count_
);
59 ++gles2_implementation_
->use_count_
;
62 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
63 --gles2_implementation_
->use_count_
;
64 CHECK_EQ(0, gles2_implementation_
->use_count_
);
67 GLES2Implementation::GLES2Implementation(
68 GLES2CmdHelper
* helper
,
69 ShareGroup
* share_group
,
70 TransferBufferInterface
* transfer_buffer
,
71 bool bind_generates_resource
,
72 bool lose_context_when_out_of_memory
,
73 bool support_client_side_arrays
,
74 GpuControl
* gpu_control
)
76 transfer_buffer_(transfer_buffer
),
77 angle_pack_reverse_row_order_status_(kUnknownExtensionStatus
),
78 chromium_framebuffer_multisample_(kUnknownExtensionStatus
),
81 unpack_flip_y_(false),
82 unpack_row_length_(0),
83 unpack_image_height_(0),
85 unpack_skip_pixels_(0),
86 unpack_skip_images_(0),
87 pack_reverse_row_order_(false),
88 active_texture_unit_(0),
89 bound_framebuffer_(0),
90 bound_read_framebuffer_(0),
91 bound_renderbuffer_(0),
92 bound_valuebuffer_(0),
94 bound_array_buffer_id_(0),
95 bound_pixel_pack_transfer_buffer_id_(0),
96 bound_pixel_unpack_transfer_buffer_id_(0),
97 async_upload_token_(0),
98 async_upload_sync_(NULL
),
99 async_upload_sync_shm_id_(0),
100 async_upload_sync_shm_offset_(0),
103 lose_context_when_out_of_memory_(lose_context_when_out_of_memory
),
104 support_client_side_arrays_(support_client_side_arrays
),
106 error_message_callback_(NULL
),
107 current_trace_stack_(0),
108 gpu_control_(gpu_control
),
109 capabilities_(gpu_control
->GetCapabilities()),
110 weak_ptr_factory_(this) {
112 DCHECK(transfer_buffer
);
115 std::stringstream ss
;
116 ss
<< std::hex
<< this;
117 this_in_hex_
= ss
.str();
119 GPU_CLIENT_LOG_CODE_BLOCK({
120 debug_
= base::CommandLine::ForCurrentProcess()->HasSwitch(
121 switches::kEnableGPUClientLogging
);
125 (share_group
? share_group
: new ShareGroup(bind_generates_resource
));
126 DCHECK(share_group_
->bind_generates_resource() == bind_generates_resource
);
128 memset(&reserved_ids_
, 0, sizeof(reserved_ids_
));
131 bool GLES2Implementation::Initialize(
132 unsigned int starting_transfer_buffer_size
,
133 unsigned int min_transfer_buffer_size
,
134 unsigned int max_transfer_buffer_size
,
135 unsigned int mapped_memory_limit
) {
136 TRACE_EVENT0("gpu", "GLES2Implementation::Initialize");
137 DCHECK_GE(starting_transfer_buffer_size
, min_transfer_buffer_size
);
138 DCHECK_LE(starting_transfer_buffer_size
, max_transfer_buffer_size
);
139 DCHECK_GE(min_transfer_buffer_size
, kStartingOffset
);
141 if (!transfer_buffer_
->Initialize(
142 starting_transfer_buffer_size
,
144 min_transfer_buffer_size
,
145 max_transfer_buffer_size
,
151 mapped_memory_
.reset(
152 new MappedMemoryManager(
154 base::Bind(&GLES2Implementation::PollAsyncUploads
,
155 // The mapped memory manager is owned by |this| here, and
156 // since its destroyed before before we destroy ourselves
157 // we don't need extra safety measures for this closure.
158 base::Unretained(this)),
159 mapped_memory_limit
));
161 unsigned chunk_size
= 2 * 1024 * 1024;
162 if (mapped_memory_limit
!= kNoLimit
) {
163 // Use smaller chunks if the client is very memory conscientious.
164 chunk_size
= std::min(mapped_memory_limit
/ 4, chunk_size
);
166 mapped_memory_
->set_chunk_size_multiple(chunk_size
);
168 GLStaticState::ShaderPrecisionMap
* shader_precisions
=
169 &static_state_
.shader_precisions
;
170 capabilities_
.VisitPrecisions([shader_precisions
](
171 GLenum shader
, GLenum type
, Capabilities::ShaderPrecision
* result
) {
172 const GLStaticState::ShaderPrecisionKey
key(shader
, type
);
173 cmds::GetShaderPrecisionFormat::Result cached_result
= {
174 true, result
->min_range
, result
->max_range
, result
->precision
};
175 shader_precisions
->insert(std::make_pair(key
, cached_result
));
178 util_
.set_num_compressed_texture_formats(
179 capabilities_
.num_compressed_texture_formats
);
180 util_
.set_num_shader_binary_formats(capabilities_
.num_shader_binary_formats
);
182 texture_units_
.reset(
183 new TextureUnit
[capabilities_
.max_combined_texture_image_units
]);
185 query_tracker_
.reset(new QueryTracker(mapped_memory_
.get()));
186 buffer_tracker_
.reset(new BufferTracker(mapped_memory_
.get()));
188 query_id_allocator_
.reset(new IdAllocator());
189 if (support_client_side_arrays_
) {
190 GetIdHandler(id_namespaces::kBuffers
)->MakeIds(
191 this, kClientSideArrayId
, arraysize(reserved_ids_
), &reserved_ids_
[0]);
194 vertex_array_object_manager_
.reset(new VertexArrayObjectManager(
195 capabilities_
.max_vertex_attribs
, reserved_ids_
[0], reserved_ids_
[1],
196 support_client_side_arrays_
));
198 // GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
199 // on Client & Service.
200 if (capabilities_
.bind_generates_resource_chromium
!=
201 (share_group_
->bind_generates_resource() ? 1 : 0)) {
202 SetGLError(GL_INVALID_OPERATION
,
204 "Service bind_generates_resource mismatch.");
211 GLES2Implementation::~GLES2Implementation() {
212 // Make sure the queries are finished otherwise we'll delete the
213 // shared memory (mapped_memory_) which will free the memory used
214 // by the queries. The GPU process when validating that memory is still
215 // shared will fail and abort (ie, it will stop running).
217 query_tracker_
.reset();
219 // GLES2Implementation::Initialize() could fail before allocating
220 // reserved_ids_, so we need delete them carefully.
221 if (support_client_side_arrays_
&& reserved_ids_
[0]) {
222 DeleteBuffers(arraysize(reserved_ids_
), &reserved_ids_
[0]);
225 // Release any per-context data in share group.
226 share_group_
->FreeContext(this);
228 buffer_tracker_
.reset();
230 FreeAllAsyncUploadBuffers();
232 if (async_upload_sync_
) {
233 mapped_memory_
->Free(async_upload_sync_
);
234 async_upload_sync_
= NULL
;
237 // Make sure the commands make it the service.
241 GLES2CmdHelper
* GLES2Implementation::helper() const {
245 IdHandlerInterface
* GLES2Implementation::GetIdHandler(int namespace_id
) const {
246 return share_group_
->GetIdHandler(namespace_id
);
249 IdAllocator
* GLES2Implementation::GetIdAllocator(int namespace_id
) const {
250 if (namespace_id
== id_namespaces::kQueries
)
251 return query_id_allocator_
.get();
256 void* GLES2Implementation::GetResultBuffer() {
257 return transfer_buffer_
->GetResultBuffer();
260 int32
GLES2Implementation::GetResultShmId() {
261 return transfer_buffer_
->GetShmId();
264 uint32
GLES2Implementation::GetResultShmOffset() {
265 return transfer_buffer_
->GetResultOffset();
268 void GLES2Implementation::FreeUnusedSharedMemory() {
269 mapped_memory_
->FreeUnused();
272 void GLES2Implementation::FreeEverything() {
273 FreeAllAsyncUploadBuffers();
275 query_tracker_
->Shrink();
276 FreeUnusedSharedMemory();
277 transfer_buffer_
->Free();
278 helper_
->FreeRingBuffer();
281 void GLES2Implementation::RunIfContextNotLost(const base::Closure
& callback
) {
282 if (!helper_
->IsContextLost())
286 void GLES2Implementation::SignalSyncPoint(uint32 sync_point
,
287 const base::Closure
& callback
) {
288 gpu_control_
->SignalSyncPoint(
290 base::Bind(&GLES2Implementation::RunIfContextNotLost
,
291 weak_ptr_factory_
.GetWeakPtr(),
295 void GLES2Implementation::SignalQuery(uint32 query
,
296 const base::Closure
& callback
) {
297 // Flush previously entered commands to ensure ordering with any
298 // glBeginQueryEXT() calls that may have been put into the context.
299 ShallowFlushCHROMIUM();
300 gpu_control_
->SignalQuery(
302 base::Bind(&GLES2Implementation::RunIfContextNotLost
,
303 weak_ptr_factory_
.GetWeakPtr(),
307 void GLES2Implementation::SetSurfaceVisible(bool visible
) {
309 "gpu", "GLES2Implementation::SetSurfaceVisible", "visible", visible
);
310 // TODO(piman): This probably should be ShallowFlushCHROMIUM().
312 gpu_control_
->SetSurfaceVisible(visible
);
317 void GLES2Implementation::WaitForCmd() {
318 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
319 helper_
->CommandBufferHelper::Finish();
322 bool GLES2Implementation::IsExtensionAvailable(const char* ext
) {
323 const char* extensions
=
324 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS
));
328 int length
= strlen(ext
);
330 int n
= strcspn(extensions
, " ");
331 if (n
== length
&& 0 == strncmp(ext
, extensions
, length
)) {
334 if ('\0' == extensions
[n
]) {
341 bool GLES2Implementation::IsExtensionAvailableHelper(
342 const char* extension
, ExtensionStatus
* status
) {
344 case kAvailableExtensionStatus
:
346 case kUnavailableExtensionStatus
:
349 bool available
= IsExtensionAvailable(extension
);
350 *status
= available
? kAvailableExtensionStatus
:
351 kUnavailableExtensionStatus
;
357 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
358 return IsExtensionAvailableHelper(
359 "GL_ANGLE_pack_reverse_row_order",
360 &angle_pack_reverse_row_order_status_
);
363 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
364 return IsExtensionAvailableHelper(
365 "GL_CHROMIUM_framebuffer_multisample",
366 &chromium_framebuffer_multisample_
);
369 const std::string
& GLES2Implementation::GetLogPrefix() const {
370 const std::string
& prefix(debug_marker_manager_
.GetMarker());
371 return prefix
.empty() ? this_in_hex_
: prefix
;
374 GLenum
GLES2Implementation::GetError() {
375 GPU_CLIENT_SINGLE_THREAD_CHECK();
376 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
377 GLenum err
= GetGLError();
378 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err
));
382 GLenum
GLES2Implementation::GetClientSideGLError() {
383 if (error_bits_
== 0) {
387 GLenum error
= GL_NO_ERROR
;
388 for (uint32 mask
= 1; mask
!= 0; mask
= mask
<< 1) {
389 if ((error_bits_
& mask
) != 0) {
390 error
= GLES2Util::GLErrorBitToGLError(mask
);
394 error_bits_
&= ~GLES2Util::GLErrorToErrorBit(error
);
398 GLenum
GLES2Implementation::GetGLError() {
399 TRACE_EVENT0("gpu", "GLES2::GetGLError");
400 // Check the GL error first, then our wrapped error.
401 typedef cmds::GetError::Result Result
;
402 Result
* result
= GetResultAs
<Result
*>();
403 // If we couldn't allocate a result the context is lost.
407 *result
= GL_NO_ERROR
;
408 helper_
->GetError(GetResultShmId(), GetResultShmOffset());
410 GLenum error
= *result
;
411 if (error
== GL_NO_ERROR
) {
412 error
= GetClientSideGLError();
414 // There was an error, clear the corresponding wrapped error.
415 error_bits_
&= ~GLES2Util::GLErrorToErrorBit(error
);
420 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
421 void GLES2Implementation::FailGLError(GLenum error
) {
422 if (error
!= GL_NO_ERROR
) {
423 NOTREACHED() << "Error";
426 // NOTE: Calling GetGLError overwrites data in the result buffer.
427 void GLES2Implementation::CheckGLError() {
428 FailGLError(GetGLError());
430 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
432 void GLES2Implementation::SetGLError(
433 GLenum error
, const char* function_name
, const char* msg
) {
434 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
435 << GLES2Util::GetStringError(error
) << ": "
436 << function_name
<< ": " << msg
);
441 if (error_message_callback_
) {
442 std::string
temp(GLES2Util::GetStringError(error
) + " : " +
443 function_name
+ ": " + (msg
? msg
: ""));
444 error_message_callback_
->OnErrorMessage(temp
.c_str(), 0);
446 error_bits_
|= GLES2Util::GLErrorToErrorBit(error
);
448 if (error
== GL_OUT_OF_MEMORY
&& lose_context_when_out_of_memory_
) {
449 helper_
->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
450 GL_UNKNOWN_CONTEXT_RESET_ARB
);
454 void GLES2Implementation::SetGLErrorInvalidEnum(
455 const char* function_name
, GLenum value
, const char* label
) {
456 SetGLError(GL_INVALID_ENUM
, function_name
,
457 (std::string(label
) + " was " +
458 GLES2Util::GetStringEnum(value
)).c_str());
461 bool GLES2Implementation::GetBucketContents(uint32 bucket_id
,
462 std::vector
<int8
>* data
) {
463 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
465 const uint32 kStartSize
= 32 * 1024;
466 ScopedTransferBufferPtr
buffer(kStartSize
, helper_
, transfer_buffer_
);
467 if (!buffer
.valid()) {
470 typedef cmd::GetBucketStart::Result Result
;
471 Result
* result
= GetResultAs
<Result
*>();
476 helper_
->GetBucketStart(
477 bucket_id
, GetResultShmId(), GetResultShmOffset(),
478 buffer
.size(), buffer
.shm_id(), buffer
.offset());
480 uint32 size
= *result
;
485 if (!buffer
.valid()) {
487 if (!buffer
.valid()) {
490 helper_
->GetBucketData(
491 bucket_id
, offset
, buffer
.size(), buffer
.shm_id(), buffer
.offset());
494 uint32 size_to_copy
= std::min(size
, buffer
.size());
495 memcpy(&(*data
)[offset
], buffer
.address(), size_to_copy
);
496 offset
+= size_to_copy
;
497 size
-= size_to_copy
;
500 // Free the bucket. This is not required but it does free up the memory.
501 // and we don't have to wait for the result so from the client's perspective
503 helper_
->SetBucketSize(bucket_id
, 0);
508 void GLES2Implementation::SetBucketContents(
509 uint32 bucket_id
, const void* data
, size_t size
) {
511 helper_
->SetBucketSize(bucket_id
, size
);
515 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
516 if (!buffer
.valid()) {
519 memcpy(buffer
.address(), static_cast<const int8
*>(data
) + offset
,
521 helper_
->SetBucketData(
522 bucket_id
, offset
, buffer
.size(), buffer
.shm_id(), buffer
.offset());
523 offset
+= buffer
.size();
524 size
-= buffer
.size();
529 void GLES2Implementation::SetBucketAsCString(
530 uint32 bucket_id
, const char* str
) {
531 // NOTE: strings are passed NULL terminated. That means the empty
532 // string will have a size of 1 and no-string will have a size of 0
534 SetBucketContents(bucket_id
, str
, strlen(str
) + 1);
536 helper_
->SetBucketSize(bucket_id
, 0);
540 bool GLES2Implementation::GetBucketAsString(
541 uint32 bucket_id
, std::string
* str
) {
543 std::vector
<int8
> data
;
544 // NOTE: strings are passed NULL terminated. That means the empty
545 // string will have a size of 1 and no-string will have a size of 0
546 if (!GetBucketContents(bucket_id
, &data
)) {
552 str
->assign(&data
[0], &data
[0] + data
.size() - 1);
556 void GLES2Implementation::SetBucketAsString(
557 uint32 bucket_id
, const std::string
& str
) {
558 // NOTE: strings are passed NULL terminated. That means the empty
559 // string will have a size of 1 and no-string will have a size of 0
560 SetBucketContents(bucket_id
, str
.c_str(), str
.size() + 1);
563 void GLES2Implementation::Disable(GLenum cap
) {
564 GPU_CLIENT_SINGLE_THREAD_CHECK();
565 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
566 << GLES2Util::GetStringCapability(cap
) << ")");
567 bool changed
= false;
568 if (!state_
.SetCapabilityState(cap
, false, &changed
) || changed
) {
569 helper_
->Disable(cap
);
574 void GLES2Implementation::Enable(GLenum cap
) {
575 GPU_CLIENT_SINGLE_THREAD_CHECK();
576 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
577 << GLES2Util::GetStringCapability(cap
) << ")");
578 bool changed
= false;
579 if (!state_
.SetCapabilityState(cap
, true, &changed
) || changed
) {
580 helper_
->Enable(cap
);
585 GLboolean
GLES2Implementation::IsEnabled(GLenum cap
) {
586 GPU_CLIENT_SINGLE_THREAD_CHECK();
587 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
588 << GLES2Util::GetStringCapability(cap
) << ")");
590 if (!state_
.GetEnabled(cap
, &state
)) {
591 typedef cmds::IsEnabled::Result Result
;
592 Result
* result
= GetResultAs
<Result
*>();
597 helper_
->IsEnabled(cap
, GetResultShmId(), GetResultShmOffset());
599 state
= (*result
) != 0;
602 GPU_CLIENT_LOG("returned " << state
);
607 bool GLES2Implementation::GetHelper(GLenum pname
, GLint
* params
) {
609 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
:
610 *params
= capabilities_
.max_combined_texture_image_units
;
612 case GL_MAX_CUBE_MAP_TEXTURE_SIZE
:
613 *params
= capabilities_
.max_cube_map_texture_size
;
615 case GL_MAX_FRAGMENT_UNIFORM_VECTORS
:
616 *params
= capabilities_
.max_fragment_uniform_vectors
;
618 case GL_MAX_RENDERBUFFER_SIZE
:
619 *params
= capabilities_
.max_renderbuffer_size
;
621 case GL_MAX_TEXTURE_IMAGE_UNITS
:
622 *params
= capabilities_
.max_texture_image_units
;
624 case GL_MAX_TEXTURE_SIZE
:
625 *params
= capabilities_
.max_texture_size
;
627 case GL_MAX_VARYING_VECTORS
:
628 *params
= capabilities_
.max_varying_vectors
;
630 case GL_MAX_VERTEX_ATTRIBS
:
631 *params
= capabilities_
.max_vertex_attribs
;
633 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
:
634 *params
= capabilities_
.max_vertex_texture_image_units
;
636 case GL_MAX_VERTEX_UNIFORM_VECTORS
:
637 *params
= capabilities_
.max_vertex_uniform_vectors
;
639 case GL_NUM_COMPRESSED_TEXTURE_FORMATS
:
640 *params
= capabilities_
.num_compressed_texture_formats
;
642 case GL_NUM_SHADER_BINARY_FORMATS
:
643 *params
= capabilities_
.num_shader_binary_formats
;
645 case GL_ARRAY_BUFFER_BINDING
:
646 if (share_group_
->bind_generates_resource()) {
647 *params
= bound_array_buffer_id_
;
651 case GL_ELEMENT_ARRAY_BUFFER_BINDING
:
652 if (share_group_
->bind_generates_resource()) {
654 vertex_array_object_manager_
->bound_element_array_buffer();
658 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM
:
659 *params
= bound_pixel_pack_transfer_buffer_id_
;
661 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM
:
662 *params
= bound_pixel_unpack_transfer_buffer_id_
;
664 case GL_ACTIVE_TEXTURE
:
665 *params
= active_texture_unit_
+ GL_TEXTURE0
;
667 case GL_TEXTURE_BINDING_2D
:
668 if (share_group_
->bind_generates_resource()) {
669 *params
= texture_units_
[active_texture_unit_
].bound_texture_2d
;
673 case GL_TEXTURE_BINDING_CUBE_MAP
:
674 if (share_group_
->bind_generates_resource()) {
675 *params
= texture_units_
[active_texture_unit_
].bound_texture_cube_map
;
679 case GL_TEXTURE_BINDING_EXTERNAL_OES
:
680 if (share_group_
->bind_generates_resource()) {
682 texture_units_
[active_texture_unit_
].bound_texture_external_oes
;
686 case GL_FRAMEBUFFER_BINDING
:
687 if (share_group_
->bind_generates_resource()) {
688 *params
= bound_framebuffer_
;
692 case GL_READ_FRAMEBUFFER_BINDING
:
693 if (IsChromiumFramebufferMultisampleAvailable() &&
694 share_group_
->bind_generates_resource()) {
695 *params
= bound_read_framebuffer_
;
699 case GL_RENDERBUFFER_BINDING
:
700 if (share_group_
->bind_generates_resource()) {
701 *params
= bound_renderbuffer_
;
705 case GL_MAX_UNIFORM_BUFFER_BINDINGS
:
706 *params
= capabilities_
.max_uniform_buffer_bindings
;
708 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS
:
709 *params
= capabilities_
.max_transform_feedback_separate_attribs
;
711 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
:
712 *params
= capabilities_
.uniform_buffer_offset_alignment
;
719 bool GLES2Implementation::GetBooleanvHelper(GLenum pname
, GLboolean
* params
) {
720 // TODO(gman): Make this handle pnames that return more than 1 value.
722 if (!GetHelper(pname
, &value
)) {
725 *params
= static_cast<GLboolean
>(value
);
729 bool GLES2Implementation::GetFloatvHelper(GLenum pname
, GLfloat
* params
) {
730 // TODO(gman): Make this handle pnames that return more than 1 value.
732 if (!GetHelper(pname
, &value
)) {
735 *params
= static_cast<GLfloat
>(value
);
739 bool GLES2Implementation::GetIntegervHelper(GLenum pname
, GLint
* params
) {
740 return GetHelper(pname
, params
);
743 bool GLES2Implementation::GetInternalformativHelper(
744 GLenum target
, GLenum format
, GLenum pname
, GLsizei bufSize
,
746 // TODO(zmo): Implement the client side caching.
750 bool GLES2Implementation::GetSyncivHelper(
751 GLsync sync
, GLenum pname
, GLsizei bufsize
, GLsizei
* length
,
756 value
= GL_SYNC_FENCE
;
758 case GL_SYNC_CONDITION
:
759 value
= GL_SYNC_GPU_COMMANDS_COMPLETE
;
777 GLuint
GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
778 GLuint buffer_id
, GLsizei count
, GLenum type
, GLuint offset
) {
779 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result
;
780 Result
* result
= GetResultAs
<Result
*>();
785 helper_
->GetMaxValueInBufferCHROMIUM(
786 buffer_id
, count
, type
, offset
, GetResultShmId(), GetResultShmOffset());
791 GLuint
GLES2Implementation::GetMaxValueInBufferCHROMIUM(
792 GLuint buffer_id
, GLsizei count
, GLenum type
, GLuint offset
) {
793 GPU_CLIENT_SINGLE_THREAD_CHECK();
794 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
795 << buffer_id
<< ", " << count
<< ", "
796 << GLES2Util::GetStringGetMaxIndexType(type
)
797 << ", " << offset
<< ")");
798 GLuint result
= GetMaxValueInBufferCHROMIUMHelper(
799 buffer_id
, count
, type
, offset
);
800 GPU_CLIENT_LOG("returned " << result
);
805 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore
) {
807 RestoreArrayBuffer(restore
);
808 // Restore the element array binding.
809 // We only need to restore it if it wasn't a client side array.
810 if (vertex_array_object_manager_
->bound_element_array_buffer() == 0) {
811 helper_
->BindBuffer(GL_ELEMENT_ARRAY_BUFFER
, 0);
816 void GLES2Implementation::RestoreArrayBuffer(bool restore
) {
818 // Restore the user's current binding.
819 helper_
->BindBuffer(GL_ARRAY_BUFFER
, bound_array_buffer_id_
);
823 void GLES2Implementation::DrawElements(
824 GLenum mode
, GLsizei count
, GLenum type
, const void* indices
) {
825 GPU_CLIENT_SINGLE_THREAD_CHECK();
826 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
827 << GLES2Util::GetStringDrawMode(mode
) << ", "
829 << GLES2Util::GetStringIndexType(type
) << ", "
830 << static_cast<const void*>(indices
) << ")");
832 SetGLError(GL_INVALID_VALUE
, "glDrawElements", "count less than 0.");
838 if (vertex_array_object_manager_
->bound_element_array_buffer() != 0 &&
839 !ValidateOffset("glDrawElements", reinterpret_cast<GLintptr
>(indices
))) {
843 bool simulated
= false;
844 if (!vertex_array_object_manager_
->SetupSimulatedIndexAndClientSideBuffers(
845 "glDrawElements", this, helper_
, count
, type
, 0, indices
,
846 &offset
, &simulated
)) {
849 helper_
->DrawElements(mode
, count
, type
, offset
);
850 RestoreElementAndArrayBuffers(simulated
);
854 void GLES2Implementation::Flush() {
855 GPU_CLIENT_SINGLE_THREAD_CHECK();
856 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
857 // Insert the cmd to call glFlush
859 // Flush our command buffer
860 // (tell the service to execute up to the flush cmd.)
861 helper_
->CommandBufferHelper::Flush();
864 void GLES2Implementation::ShallowFlushCHROMIUM() {
865 GPU_CLIENT_SINGLE_THREAD_CHECK();
866 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
867 // Flush our command buffer
868 // (tell the service to execute up to the flush cmd.)
869 helper_
->CommandBufferHelper::Flush();
870 // TODO(piman): Add the FreeEverything() logic here.
873 void GLES2Implementation::OrderingBarrierCHROMIUM() {
874 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOrderingBarrierCHROMIUM");
875 // Flush command buffer at the GPU channel level. May be implemented as
877 helper_
->CommandBufferHelper::OrderingBarrier();
880 void GLES2Implementation::Finish() {
881 GPU_CLIENT_SINGLE_THREAD_CHECK();
885 void GLES2Implementation::ShallowFinishCHROMIUM() {
886 GPU_CLIENT_SINGLE_THREAD_CHECK();
887 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
888 // Flush our command buffer (tell the service to execute up to the flush cmd
889 // and don't return until it completes).
890 helper_
->CommandBufferHelper::Finish();
893 void GLES2Implementation::FinishHelper() {
894 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
895 TRACE_EVENT0("gpu", "GLES2::Finish");
896 // Insert the cmd to call glFinish
898 // Finish our command buffer
899 // (tell the service to execute up to the Finish cmd and wait for it to
901 helper_
->CommandBufferHelper::Finish();
904 void GLES2Implementation::SwapBuffers() {
905 GPU_CLIENT_SINGLE_THREAD_CHECK();
906 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
907 // TODO(piman): Strictly speaking we'd want to insert the token after the
908 // swap, but the state update with the updated token might not have happened
909 // by the time the SwapBuffer callback gets called, forcing us to synchronize
910 // with the GPU process more than needed. So instead, make it happen before.
911 // All it means is that we could be slightly looser on the kMaxSwapBuffers
912 // semantics if the client doesn't use the callback mechanism, and by chance
913 // the scheduler yields between the InsertToken and the SwapBuffers.
914 swap_buffers_tokens_
.push(helper_
->InsertToken());
915 helper_
->SwapBuffers();
916 helper_
->CommandBufferHelper::Flush();
917 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
918 // compensate for TODO above.
919 if (swap_buffers_tokens_
.size() > kMaxSwapBuffers
+ 1) {
920 helper_
->WaitForToken(swap_buffers_tokens_
.front());
921 swap_buffers_tokens_
.pop();
925 void GLES2Implementation::SwapInterval(int interval
) {
926 GPU_CLIENT_SINGLE_THREAD_CHECK();
927 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapInterval("
929 helper_
->SwapInterval(interval
);
932 void GLES2Implementation::BindAttribLocation(
933 GLuint program
, GLuint index
, const char* name
) {
934 GPU_CLIENT_SINGLE_THREAD_CHECK();
935 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
936 << program
<< ", " << index
<< ", " << name
<< ")");
937 SetBucketAsString(kResultBucketId
, name
);
938 helper_
->BindAttribLocationBucket(program
, index
, kResultBucketId
);
939 helper_
->SetBucketSize(kResultBucketId
, 0);
943 void GLES2Implementation::BindUniformLocationCHROMIUM(
944 GLuint program
, GLint location
, const char* name
) {
945 GPU_CLIENT_SINGLE_THREAD_CHECK();
946 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
947 << program
<< ", " << location
<< ", " << name
<< ")");
948 SetBucketAsString(kResultBucketId
, name
);
949 helper_
->BindUniformLocationCHROMIUMBucket(
950 program
, location
, kResultBucketId
);
951 helper_
->SetBucketSize(kResultBucketId
, 0);
955 void GLES2Implementation::GetVertexAttribPointerv(
956 GLuint index
, GLenum pname
, void** ptr
) {
957 GPU_CLIENT_SINGLE_THREAD_CHECK();
958 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
959 << index
<< ", " << GLES2Util::GetStringVertexPointer(pname
) << ", "
960 << static_cast<void*>(ptr
) << ")");
961 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results
= 1);
962 if (!vertex_array_object_manager_
->GetAttribPointer(index
, pname
, ptr
)) {
963 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
964 typedef cmds::GetVertexAttribPointerv::Result Result
;
965 Result
* result
= GetResultAs
<Result
*>();
969 result
->SetNumResults(0);
970 helper_
->GetVertexAttribPointerv(
971 index
, pname
, GetResultShmId(), GetResultShmOffset());
973 result
->CopyResult(ptr
);
974 GPU_CLIENT_LOG_CODE_BLOCK(num_results
= result
->GetNumResults());
976 GPU_CLIENT_LOG_CODE_BLOCK({
977 for (int32 i
= 0; i
< num_results
; ++i
) {
978 GPU_CLIENT_LOG(" " << i
<< ": " << ptr
[i
]);
984 bool GLES2Implementation::DeleteProgramHelper(GLuint program
) {
985 if (!GetIdHandler(id_namespaces::kProgramsAndShaders
)->FreeIds(
986 this, 1, &program
, &GLES2Implementation::DeleteProgramStub
)) {
989 "glDeleteProgram", "id not created by this context.");
992 if (program
== current_program_
) {
993 current_program_
= 0;
998 void GLES2Implementation::DeleteProgramStub(
999 GLsizei n
, const GLuint
* programs
) {
1001 share_group_
->program_info_manager()->DeleteInfo(programs
[0]);
1002 helper_
->DeleteProgram(programs
[0]);
1005 bool GLES2Implementation::DeleteShaderHelper(GLuint shader
) {
1006 if (!GetIdHandler(id_namespaces::kProgramsAndShaders
)->FreeIds(
1007 this, 1, &shader
, &GLES2Implementation::DeleteShaderStub
)) {
1010 "glDeleteShader", "id not created by this context.");
1016 void GLES2Implementation::DeleteShaderStub(
1017 GLsizei n
, const GLuint
* shaders
) {
1019 share_group_
->program_info_manager()->DeleteInfo(shaders
[0]);
1020 helper_
->DeleteShader(shaders
[0]);
1023 void GLES2Implementation::DeleteSyncHelper(GLsync sync
) {
1024 GLuint sync_uint
= ToGLuint(sync
);
1025 if (!GetIdHandler(id_namespaces::kSyncs
)->FreeIds(
1026 this, 1, &sync_uint
, &GLES2Implementation::DeleteSyncStub
)) {
1029 "glDeleteSync", "id not created by this context.");
1033 void GLES2Implementation::DeleteSyncStub(GLsizei n
, const GLuint
* syncs
) {
1035 helper_
->DeleteSync(syncs
[0]);
1038 GLint
GLES2Implementation::GetAttribLocationHelper(
1039 GLuint program
, const char* name
) {
1040 typedef cmds::GetAttribLocation::Result Result
;
1041 Result
* result
= GetResultAs
<Result
*>();
1046 SetBucketAsCString(kResultBucketId
, name
);
1047 helper_
->GetAttribLocation(
1048 program
, kResultBucketId
, GetResultShmId(), GetResultShmOffset());
1050 helper_
->SetBucketSize(kResultBucketId
, 0);
1054 GLint
GLES2Implementation::GetAttribLocation(
1055 GLuint program
, const char* name
) {
1056 GPU_CLIENT_SINGLE_THREAD_CHECK();
1057 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1058 << ", " << name
<< ")");
1059 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1060 GLint loc
= share_group_
->program_info_manager()->GetAttribLocation(
1061 this, program
, name
);
1062 GPU_CLIENT_LOG("returned " << loc
);
1067 GLint
GLES2Implementation::GetUniformLocationHelper(
1068 GLuint program
, const char* name
) {
1069 typedef cmds::GetUniformLocation::Result Result
;
1070 Result
* result
= GetResultAs
<Result
*>();
1075 SetBucketAsCString(kResultBucketId
, name
);
1076 helper_
->GetUniformLocation(program
, kResultBucketId
,
1077 GetResultShmId(), GetResultShmOffset());
1079 helper_
->SetBucketSize(kResultBucketId
, 0);
1083 GLint
GLES2Implementation::GetUniformLocation(
1084 GLuint program
, const char* name
) {
1085 GPU_CLIENT_SINGLE_THREAD_CHECK();
1086 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1087 << ", " << name
<< ")");
1088 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1089 GLint loc
= share_group_
->program_info_manager()->GetUniformLocation(
1090 this, program
, name
);
1091 GPU_CLIENT_LOG("returned " << loc
);
1096 bool GLES2Implementation::GetUniformIndicesHelper(
1097 GLuint program
, GLsizei count
, const char* const* names
, GLuint
* indices
) {
1098 typedef cmds::GetUniformIndices::Result Result
;
1099 Result
* result
= GetResultAs
<Result
*>();
1103 result
->SetNumResults(0);
1104 if (!PackStringsToBucket(count
, names
, NULL
, "glGetUniformIndices")) {
1107 helper_
->GetUniformIndices(program
, kResultBucketId
,
1108 GetResultShmId(), GetResultShmOffset());
1110 if (result
->GetNumResults() != count
) {
1113 result
->CopyResult(indices
);
1117 void GLES2Implementation::GetUniformIndices(
1118 GLuint program
, GLsizei count
, const char* const* names
, GLuint
* indices
) {
1119 GPU_CLIENT_SINGLE_THREAD_CHECK();
1120 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
1121 << ", " << count
<< ", " << names
<< ", " << indices
<< ")");
1122 TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
1124 SetGLError(GL_INVALID_VALUE
, "glGetUniformIndices", "count < 0");
1130 bool success
= share_group_
->program_info_manager()->GetUniformIndices(
1131 this, program
, count
, names
, indices
);
1133 GPU_CLIENT_LOG_CODE_BLOCK({
1134 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1135 GPU_CLIENT_LOG(" " << ii
<< ": " << indices
[ii
]);
1142 bool GLES2Implementation::GetProgramivHelper(
1143 GLuint program
, GLenum pname
, GLint
* params
) {
1144 bool got_value
= share_group_
->program_info_manager()->GetProgramiv(
1145 this, program
, pname
, params
);
1146 GPU_CLIENT_LOG_CODE_BLOCK({
1148 GPU_CLIENT_LOG(" 0: " << *params
);
1154 GLint
GLES2Implementation::GetFragDataLocationHelper(
1155 GLuint program
, const char* name
) {
1156 typedef cmds::GetFragDataLocation::Result Result
;
1157 Result
* result
= GetResultAs
<Result
*>();
1162 SetBucketAsCString(kResultBucketId
, name
);
1163 helper_
->GetFragDataLocation(
1164 program
, kResultBucketId
, GetResultShmId(), GetResultShmOffset());
1166 helper_
->SetBucketSize(kResultBucketId
, 0);
1170 GLint
GLES2Implementation::GetFragDataLocation(
1171 GLuint program
, const char* name
) {
1172 GPU_CLIENT_SINGLE_THREAD_CHECK();
1173 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataLocation("
1174 << program
<< ", " << name
<< ")");
1175 TRACE_EVENT0("gpu", "GLES2::GetFragDataLocation");
1176 GLint loc
= share_group_
->program_info_manager()->GetFragDataLocation(
1177 this, program
, name
);
1178 GPU_CLIENT_LOG("returned " << loc
);
1183 GLuint
GLES2Implementation::GetUniformBlockIndexHelper(
1184 GLuint program
, const char* name
) {
1185 typedef cmds::GetUniformBlockIndex::Result Result
;
1186 Result
* result
= GetResultAs
<Result
*>();
1188 return GL_INVALID_INDEX
;
1190 *result
= GL_INVALID_INDEX
;
1191 SetBucketAsCString(kResultBucketId
, name
);
1192 helper_
->GetUniformBlockIndex(
1193 program
, kResultBucketId
, GetResultShmId(), GetResultShmOffset());
1195 helper_
->SetBucketSize(kResultBucketId
, 0);
1199 GLuint
GLES2Implementation::GetUniformBlockIndex(
1200 GLuint program
, const char* name
) {
1201 GPU_CLIENT_SINGLE_THREAD_CHECK();
1202 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformBlockIndex("
1203 << program
<< ", " << name
<< ")");
1204 TRACE_EVENT0("gpu", "GLES2::GetUniformBlockIndex");
1205 GLuint index
= share_group_
->program_info_manager()->GetUniformBlockIndex(
1206 this, program
, name
);
1207 GPU_CLIENT_LOG("returned " << index
);
1212 void GLES2Implementation::LinkProgram(GLuint program
) {
1213 GPU_CLIENT_SINGLE_THREAD_CHECK();
1214 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program
<< ")");
1215 helper_
->LinkProgram(program
);
1216 share_group_
->program_info_manager()->CreateInfo(program
);
1220 void GLES2Implementation::ShaderBinary(
1221 GLsizei n
, const GLuint
* shaders
, GLenum binaryformat
, const void* binary
,
1223 GPU_CLIENT_SINGLE_THREAD_CHECK();
1224 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n
<< ", "
1225 << static_cast<const void*>(shaders
) << ", "
1226 << GLES2Util::GetStringEnum(binaryformat
) << ", "
1227 << static_cast<const void*>(binary
) << ", "
1230 SetGLError(GL_INVALID_VALUE
, "glShaderBinary", "n < 0.");
1234 SetGLError(GL_INVALID_VALUE
, "glShaderBinary", "length < 0.");
1237 // TODO(gman): ShaderBinary should use buckets.
1238 unsigned int shader_id_size
= n
* sizeof(*shaders
);
1239 ScopedTransferBufferArray
<GLint
> buffer(
1240 shader_id_size
+ length
, helper_
, transfer_buffer_
);
1241 if (!buffer
.valid() || buffer
.num_elements() != shader_id_size
+ length
) {
1242 SetGLError(GL_OUT_OF_MEMORY
, "glShaderBinary", "out of memory.");
1245 void* shader_ids
= buffer
.elements();
1246 void* shader_data
= buffer
.elements() + shader_id_size
;
1247 memcpy(shader_ids
, shaders
, shader_id_size
);
1248 memcpy(shader_data
, binary
, length
);
1249 helper_
->ShaderBinary(
1255 buffer
.offset() + shader_id_size
,
1260 void GLES2Implementation::PixelStorei(GLenum pname
, GLint param
) {
1261 GPU_CLIENT_SINGLE_THREAD_CHECK();
1262 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1263 << GLES2Util::GetStringPixelStore(pname
) << ", "
1266 case GL_PACK_ALIGNMENT
:
1267 pack_alignment_
= param
;
1269 case GL_UNPACK_ALIGNMENT
:
1270 unpack_alignment_
= param
;
1272 case GL_UNPACK_ROW_LENGTH_EXT
:
1273 unpack_row_length_
= param
;
1275 case GL_UNPACK_IMAGE_HEIGHT
:
1276 unpack_image_height_
= param
;
1278 case GL_UNPACK_SKIP_ROWS_EXT
:
1279 unpack_skip_rows_
= param
;
1281 case GL_UNPACK_SKIP_PIXELS_EXT
:
1282 unpack_skip_pixels_
= param
;
1284 case GL_UNPACK_SKIP_IMAGES
:
1285 unpack_skip_images_
= param
;
1287 case GL_UNPACK_FLIP_Y_CHROMIUM
:
1288 unpack_flip_y_
= (param
!= 0);
1290 case GL_PACK_REVERSE_ROW_ORDER_ANGLE
:
1291 pack_reverse_row_order_
=
1292 IsAnglePackReverseRowOrderAvailable() ? (param
!= 0) : false;
1297 helper_
->PixelStorei(pname
, param
);
1301 void GLES2Implementation::VertexAttribIPointer(
1302 GLuint index
, GLint size
, GLenum type
, GLsizei stride
, const void* ptr
) {
1303 GPU_CLIENT_SINGLE_THREAD_CHECK();
1304 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1307 << GLES2Util::GetStringVertexAttribType(type
) << ", "
1310 helper_
->VertexAttribIPointer(index
, size
, type
, stride
, ToGLuint(ptr
));
1314 void GLES2Implementation::VertexAttribPointer(
1315 GLuint index
, GLint size
, GLenum type
, GLboolean normalized
, GLsizei stride
,
1317 GPU_CLIENT_SINGLE_THREAD_CHECK();
1318 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1321 << GLES2Util::GetStringVertexAttribType(type
) << ", "
1322 << GLES2Util::GetStringBool(normalized
) << ", "
1325 // Record the info on the client side.
1326 if (!vertex_array_object_manager_
->SetAttribPointer(
1327 bound_array_buffer_id_
, index
, size
, type
, normalized
, stride
, ptr
)) {
1328 SetGLError(GL_INVALID_OPERATION
, "glVertexAttribPointer",
1329 "client side arrays are not allowed in vertex array objects.");
1332 if (!support_client_side_arrays_
|| bound_array_buffer_id_
!= 0) {
1333 // Only report NON client side buffers to the service.
1334 if (!ValidateOffset("glVertexAttribPointer",
1335 reinterpret_cast<GLintptr
>(ptr
))) {
1338 helper_
->VertexAttribPointer(index
, size
, type
, normalized
, stride
,
1344 void GLES2Implementation::VertexAttribDivisorANGLE(
1345 GLuint index
, GLuint divisor
) {
1346 GPU_CLIENT_SINGLE_THREAD_CHECK();
1347 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1349 << divisor
<< ") ");
1350 // Record the info on the client side.
1351 vertex_array_object_manager_
->SetAttribDivisor(index
, divisor
);
1352 helper_
->VertexAttribDivisorANGLE(index
, divisor
);
1356 void GLES2Implementation::BufferDataHelper(
1357 GLenum target
, GLsizeiptr size
, const void* data
, GLenum usage
) {
1358 if (!ValidateSize("glBufferData", size
))
1361 #if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
1362 // Do not upload uninitialized data. Even if it's not a bug, it can cause a
1363 // bogus MSan report during a readback later. This is because MSan doesn't
1364 // understand shared memory and would assume we were reading back the same
1365 // unintialized data.
1366 if (data
) __msan_check_mem_is_initialized(data
, size
);
1370 if (GetBoundPixelTransferBuffer(target
, "glBufferData", &buffer_id
)) {
1375 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
1377 RemoveTransferBuffer(buffer
);
1379 // Create new buffer.
1380 buffer
= buffer_tracker_
->CreateBuffer(buffer_id
, size
);
1382 if (buffer
->address() && data
)
1383 memcpy(buffer
->address(), data
, size
);
1391 // If there is no data just send BufferData
1393 helper_
->BufferData(target
, size
, 0, 0, usage
);
1397 // See if we can send all at once.
1398 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1399 if (!buffer
.valid()) {
1403 if (buffer
.size() >= static_cast<unsigned int>(size
)) {
1404 memcpy(buffer
.address(), data
, size
);
1405 helper_
->BufferData(
1414 // Make the buffer with BufferData then send via BufferSubData
1415 helper_
->BufferData(target
, size
, 0, 0, usage
);
1416 BufferSubDataHelperImpl(target
, 0, size
, data
, &buffer
);
1420 void GLES2Implementation::BufferData(
1421 GLenum target
, GLsizeiptr size
, const void* data
, GLenum usage
) {
1422 GPU_CLIENT_SINGLE_THREAD_CHECK();
1423 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1424 << GLES2Util::GetStringBufferTarget(target
) << ", "
1426 << static_cast<const void*>(data
) << ", "
1427 << GLES2Util::GetStringBufferUsage(usage
) << ")");
1428 BufferDataHelper(target
, size
, data
, usage
);
1432 void GLES2Implementation::BufferSubDataHelper(
1433 GLenum target
, GLintptr offset
, GLsizeiptr size
, const void* data
) {
1438 if (!ValidateSize("glBufferSubData", size
) ||
1439 !ValidateOffset("glBufferSubData", offset
)) {
1444 if (GetBoundPixelTransferBuffer(target
, "glBufferSubData", &buffer_id
)) {
1448 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
1450 SetGLError(GL_INVALID_VALUE
, "glBufferSubData", "unknown buffer");
1455 int32 buffer_size
= buffer
->size();
1456 if (!SafeAddInt32(offset
, size
, &end
) || end
> buffer_size
) {
1457 SetGLError(GL_INVALID_VALUE
, "glBufferSubData", "out of range");
1461 if (buffer
->address() && data
)
1462 memcpy(static_cast<uint8
*>(buffer
->address()) + offset
, data
, size
);
1466 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1467 BufferSubDataHelperImpl(target
, offset
, size
, data
, &buffer
);
1470 void GLES2Implementation::BufferSubDataHelperImpl(
1471 GLenum target
, GLintptr offset
, GLsizeiptr size
, const void* data
,
1472 ScopedTransferBufferPtr
* buffer
) {
1476 const int8
* source
= static_cast<const int8
*>(data
);
1478 if (!buffer
->valid() || buffer
->size() == 0) {
1479 buffer
->Reset(size
);
1480 if (!buffer
->valid()) {
1484 memcpy(buffer
->address(), source
, buffer
->size());
1485 helper_
->BufferSubData(
1486 target
, offset
, buffer
->size(), buffer
->shm_id(), buffer
->offset());
1487 offset
+= buffer
->size();
1488 source
+= buffer
->size();
1489 size
-= buffer
->size();
1494 void GLES2Implementation::BufferSubData(
1495 GLenum target
, GLintptr offset
, GLsizeiptr size
, const void* data
) {
1496 GPU_CLIENT_SINGLE_THREAD_CHECK();
1497 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1498 << GLES2Util::GetStringBufferTarget(target
) << ", "
1499 << offset
<< ", " << size
<< ", "
1500 << static_cast<const void*>(data
) << ")");
1501 BufferSubDataHelper(target
, offset
, size
, data
);
1505 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer
* buffer
) {
1506 int32 token
= buffer
->last_usage_token();
1507 uint32 async_token
= buffer
->last_async_upload_token();
1510 if (HasAsyncUploadTokenPassed(async_token
)) {
1511 buffer_tracker_
->Free(buffer
);
1513 detached_async_upload_memory_
.push_back(
1514 std::make_pair(buffer
->address(), async_token
));
1515 buffer_tracker_
->Unmanage(buffer
);
1518 if (helper_
->HasTokenPassed(token
))
1519 buffer_tracker_
->Free(buffer
);
1521 buffer_tracker_
->FreePendingToken(buffer
, token
);
1523 buffer_tracker_
->Free(buffer
);
1526 buffer_tracker_
->RemoveBuffer(buffer
->id());
1529 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1531 const char* function_name
,
1532 GLuint
* buffer_id
) {
1536 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
:
1537 *buffer_id
= bound_pixel_pack_transfer_buffer_id_
;
1539 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
:
1540 *buffer_id
= bound_pixel_unpack_transfer_buffer_id_
;
1547 SetGLError(GL_INVALID_OPERATION
, function_name
, "no buffer bound");
1552 BufferTracker::Buffer
*
1553 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1555 const char* function_name
,
1556 GLuint offset
, GLsizei size
) {
1558 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
1560 SetGLError(GL_INVALID_OPERATION
, function_name
, "invalid buffer");
1563 if (buffer
->mapped()) {
1564 SetGLError(GL_INVALID_OPERATION
, function_name
, "buffer mapped");
1567 if ((buffer
->size() - offset
) < static_cast<GLuint
>(size
)) {
1568 SetGLError(GL_INVALID_VALUE
, function_name
, "unpack size to large");
1574 void GLES2Implementation::CompressedTexImage2D(
1575 GLenum target
, GLint level
, GLenum internalformat
, GLsizei width
,
1576 GLsizei height
, GLint border
, GLsizei image_size
, const void* data
) {
1577 GPU_CLIENT_SINGLE_THREAD_CHECK();
1578 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1579 << GLES2Util::GetStringTextureTarget(target
) << ", "
1581 << GLES2Util::GetStringCompressedTextureFormat(internalformat
) << ", "
1582 << width
<< ", " << height
<< ", " << border
<< ", "
1583 << image_size
<< ", "
1584 << static_cast<const void*>(data
) << ")");
1585 if (width
< 0 || height
< 0 || level
< 0) {
1586 SetGLError(GL_INVALID_VALUE
, "glCompressedTexImage2D", "dimension < 0");
1590 SetGLError(GL_INVALID_VALUE
, "glCompressedTexImage2D", "border != 0");
1593 if (height
== 0 || width
== 0) {
1596 // If there's a pixel unpack buffer bound use it when issuing
1597 // CompressedTexImage2D.
1598 if (bound_pixel_unpack_transfer_buffer_id_
) {
1599 GLuint offset
= ToGLuint(data
);
1600 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1601 bound_pixel_unpack_transfer_buffer_id_
,
1602 "glCompressedTexImage2D", offset
, image_size
);
1603 if (buffer
&& buffer
->shm_id() != -1) {
1604 helper_
->CompressedTexImage2D(
1605 target
, level
, internalformat
, width
, height
, image_size
,
1606 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1607 buffer
->set_last_usage_token(helper_
->InsertToken());
1611 SetBucketContents(kResultBucketId
, data
, image_size
);
1612 helper_
->CompressedTexImage2DBucket(
1613 target
, level
, internalformat
, width
, height
, kResultBucketId
);
1614 // Free the bucket. This is not required but it does free up the memory.
1615 // and we don't have to wait for the result so from the client's perspective
1617 helper_
->SetBucketSize(kResultBucketId
, 0);
1621 void GLES2Implementation::CompressedTexSubImage2D(
1622 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
1623 GLsizei height
, GLenum format
, GLsizei image_size
, const void* data
) {
1624 GPU_CLIENT_SINGLE_THREAD_CHECK();
1625 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1626 << GLES2Util::GetStringTextureTarget(target
) << ", "
1628 << xoffset
<< ", " << yoffset
<< ", "
1629 << width
<< ", " << height
<< ", "
1630 << GLES2Util::GetStringCompressedTextureFormat(format
) << ", "
1631 << image_size
<< ", "
1632 << static_cast<const void*>(data
) << ")");
1633 if (width
< 0 || height
< 0 || level
< 0) {
1634 SetGLError(GL_INVALID_VALUE
, "glCompressedTexSubImage2D", "dimension < 0");
1637 // If there's a pixel unpack buffer bound use it when issuing
1638 // CompressedTexSubImage2D.
1639 if (bound_pixel_unpack_transfer_buffer_id_
) {
1640 GLuint offset
= ToGLuint(data
);
1641 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1642 bound_pixel_unpack_transfer_buffer_id_
,
1643 "glCompressedTexSubImage2D", offset
, image_size
);
1644 if (buffer
&& buffer
->shm_id() != -1) {
1645 helper_
->CompressedTexSubImage2D(
1646 target
, level
, xoffset
, yoffset
, width
, height
, format
, image_size
,
1647 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1648 buffer
->set_last_usage_token(helper_
->InsertToken());
1653 SetBucketContents(kResultBucketId
, data
, image_size
);
1654 helper_
->CompressedTexSubImage2DBucket(
1655 target
, level
, xoffset
, yoffset
, width
, height
, format
, kResultBucketId
);
1656 // Free the bucket. This is not required but it does free up the memory.
1657 // and we don't have to wait for the result so from the client's perspective
1659 helper_
->SetBucketSize(kResultBucketId
, 0);
1665 void CopyRectToBuffer(
1668 uint32 unpadded_row_size
,
1669 uint32 pixels_padded_row_size
,
1672 uint32 buffer_padded_row_size
) {
1673 const int8
* source
= static_cast<const int8
*>(pixels
);
1674 int8
* dest
= static_cast<int8
*>(buffer
);
1675 if (flip_y
|| pixels_padded_row_size
!= buffer_padded_row_size
) {
1677 dest
+= buffer_padded_row_size
* (height
- 1);
1679 // the last row is copied unpadded at the end
1680 for (; height
> 1; --height
) {
1681 memcpy(dest
, source
, buffer_padded_row_size
);
1683 dest
-= buffer_padded_row_size
;
1685 dest
+= buffer_padded_row_size
;
1687 source
+= pixels_padded_row_size
;
1689 memcpy(dest
, source
, unpadded_row_size
);
1691 uint32 size
= (height
- 1) * pixels_padded_row_size
+ unpadded_row_size
;
1692 memcpy(dest
, source
, size
);
1696 } // anonymous namespace
1698 void GLES2Implementation::TexImage2D(
1699 GLenum target
, GLint level
, GLint internalformat
, GLsizei width
,
1700 GLsizei height
, GLint border
, GLenum format
, GLenum type
,
1701 const void* pixels
) {
1702 GPU_CLIENT_SINGLE_THREAD_CHECK();
1703 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1704 << GLES2Util::GetStringTextureTarget(target
) << ", "
1706 << GLES2Util::GetStringTextureInternalFormat(internalformat
) << ", "
1707 << width
<< ", " << height
<< ", " << border
<< ", "
1708 << GLES2Util::GetStringTextureFormat(format
) << ", "
1709 << GLES2Util::GetStringPixelType(type
) << ", "
1710 << static_cast<const void*>(pixels
) << ")");
1711 if (level
< 0 || height
< 0 || width
< 0) {
1712 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "dimension < 0");
1716 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "border != 0");
1720 uint32 unpadded_row_size
;
1721 uint32 padded_row_size
;
1722 if (!GLES2Util::ComputeImageDataSizes(
1723 width
, height
, 1, format
, type
, unpack_alignment_
, &size
,
1724 &unpadded_row_size
, &padded_row_size
)) {
1725 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "image size too large");
1729 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1730 if (bound_pixel_unpack_transfer_buffer_id_
) {
1731 GLuint offset
= ToGLuint(pixels
);
1732 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1733 bound_pixel_unpack_transfer_buffer_id_
,
1734 "glTexImage2D", offset
, size
);
1735 if (buffer
&& buffer
->shm_id() != -1) {
1736 helper_
->TexImage2D(
1737 target
, level
, internalformat
, width
, height
, format
, type
,
1738 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1739 buffer
->set_last_usage_token(helper_
->InsertToken());
1745 // If there's no data just issue TexImage2D
1747 helper_
->TexImage2D(
1748 target
, level
, internalformat
, width
, height
, format
, type
,
1754 // compute the advance bytes per row for the src pixels
1755 uint32 src_padded_row_size
;
1756 if (unpack_row_length_
> 0) {
1757 if (!GLES2Util::ComputeImagePaddedRowSize(
1758 unpack_row_length_
, format
, type
, unpack_alignment_
,
1759 &src_padded_row_size
)) {
1761 GL_INVALID_VALUE
, "glTexImage2D", "unpack row length too large");
1765 src_padded_row_size
= padded_row_size
;
1768 // advance pixels pointer past the skip rows and skip pixels
1769 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1770 unpack_skip_rows_
* src_padded_row_size
;
1771 if (unpack_skip_pixels_
) {
1772 uint32 group_size
= GLES2Util::ComputeImageGroupSize(format
, type
);
1773 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1774 unpack_skip_pixels_
* group_size
;
1777 // Check if we can send it all at once.
1778 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1779 if (!buffer
.valid()) {
1783 if (buffer
.size() >= size
) {
1785 pixels
, height
, unpadded_row_size
, src_padded_row_size
, unpack_flip_y_
,
1786 buffer
.address(), padded_row_size
);
1787 helper_
->TexImage2D(
1788 target
, level
, internalformat
, width
, height
, format
, type
,
1789 buffer
.shm_id(), buffer
.offset());
1794 // No, so send it using TexSubImage2D.
1795 helper_
->TexImage2D(
1796 target
, level
, internalformat
, width
, height
, format
, type
,
1799 target
, level
, 0, 0, width
, height
, format
, type
, unpadded_row_size
,
1800 pixels
, src_padded_row_size
, GL_TRUE
, &buffer
, padded_row_size
);
1804 void GLES2Implementation::TexImage3D(
1805 GLenum target
, GLint level
, GLint internalformat
, GLsizei width
,
1806 GLsizei height
, GLsizei depth
, GLint border
, GLenum format
, GLenum type
,
1807 const void* pixels
) {
1808 GPU_CLIENT_SINGLE_THREAD_CHECK();
1809 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D("
1810 << GLES2Util::GetStringTextureTarget(target
) << ", "
1812 << GLES2Util::GetStringTextureInternalFormat(internalformat
) << ", "
1813 << width
<< ", " << height
<< ", " << depth
<< ", " << border
<< ", "
1814 << GLES2Util::GetStringTextureFormat(format
) << ", "
1815 << GLES2Util::GetStringPixelType(type
) << ", "
1816 << static_cast<const void*>(pixels
) << ")");
1817 if (level
< 0 || height
< 0 || width
< 0 || depth
< 0) {
1818 SetGLError(GL_INVALID_VALUE
, "glTexImage3D", "dimension < 0");
1822 SetGLError(GL_INVALID_VALUE
, "glTexImage3D", "border != 0");
1826 uint32 unpadded_row_size
;
1827 uint32 padded_row_size
;
1828 if (!GLES2Util::ComputeImageDataSizes(
1829 width
, height
, depth
, format
, type
, unpack_alignment_
, &size
,
1830 &unpadded_row_size
, &padded_row_size
)) {
1831 SetGLError(GL_INVALID_VALUE
, "glTexImage3D", "image size too large");
1835 // If there's a pixel unpack buffer bound use it when issuing TexImage3D.
1836 if (bound_pixel_unpack_transfer_buffer_id_
) {
1837 GLuint offset
= ToGLuint(pixels
);
1838 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1839 bound_pixel_unpack_transfer_buffer_id_
,
1840 "glTexImage3D", offset
, size
);
1841 if (buffer
&& buffer
->shm_id() != -1) {
1842 helper_
->TexImage3D(
1843 target
, level
, internalformat
, width
, height
, depth
, format
, type
,
1844 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1845 buffer
->set_last_usage_token(helper_
->InsertToken());
1851 // If there's no data just issue TexImage3D
1853 helper_
->TexImage3D(
1854 target
, level
, internalformat
, width
, height
, depth
, format
, type
,
1860 // compute the advance bytes per row for the src pixels
1861 uint32 src_padded_row_size
;
1862 if (unpack_row_length_
> 0) {
1863 if (!GLES2Util::ComputeImagePaddedRowSize(
1864 unpack_row_length_
, format
, type
, unpack_alignment_
,
1865 &src_padded_row_size
)) {
1867 GL_INVALID_VALUE
, "glTexImage3D", "unpack row length too large");
1871 src_padded_row_size
= padded_row_size
;
1873 uint32 src_height
= unpack_image_height_
> 0 ? unpack_image_height_
: height
;
1875 // advance pixels pointer past the skip images/rows/pixels
1876 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1877 unpack_skip_images_
* src_padded_row_size
* src_height
+
1878 unpack_skip_rows_
* src_padded_row_size
;
1879 if (unpack_skip_pixels_
) {
1880 uint32 group_size
= GLES2Util::ComputeImageGroupSize(format
, type
);
1881 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1882 unpack_skip_pixels_
* group_size
;
1885 // Check if we can send it all at once.
1886 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1887 if (!buffer
.valid()) {
1891 if (buffer
.size() >= size
) {
1892 void* buffer_pointer
= buffer
.address();
1893 for (GLsizei z
= 0; z
< depth
; ++z
) {
1894 // Only the last row of the last image is unpadded.
1895 uint32 src_unpadded_row_size
=
1896 (z
== depth
- 1) ? unpadded_row_size
: src_padded_row_size
;
1897 // TODO(zmo): Ignore flip_y flag for now.
1899 pixels
, height
, src_unpadded_row_size
, src_padded_row_size
, false,
1900 buffer_pointer
, padded_row_size
);
1901 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1902 src_padded_row_size
* src_height
;
1903 buffer_pointer
= reinterpret_cast<int8
*>(buffer_pointer
) +
1904 padded_row_size
* height
;
1906 helper_
->TexImage3D(
1907 target
, level
, internalformat
, width
, height
, depth
, format
, type
,
1908 buffer
.shm_id(), buffer
.offset());
1913 // No, so send it using TexSubImage3D.
1914 helper_
->TexImage3D(
1915 target
, level
, internalformat
, width
, height
, depth
, format
, type
,
1918 target
, level
, 0, 0, 0, width
, height
, depth
, format
, type
,
1919 unpadded_row_size
, pixels
, src_padded_row_size
, GL_TRUE
, &buffer
,
1924 void GLES2Implementation::TexSubImage2D(
1925 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
1926 GLsizei height
, GLenum format
, GLenum type
, const void* pixels
) {
1927 GPU_CLIENT_SINGLE_THREAD_CHECK();
1928 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1929 << GLES2Util::GetStringTextureTarget(target
) << ", "
1931 << xoffset
<< ", " << yoffset
<< ", "
1932 << width
<< ", " << height
<< ", "
1933 << GLES2Util::GetStringTextureFormat(format
) << ", "
1934 << GLES2Util::GetStringPixelType(type
) << ", "
1935 << static_cast<const void*>(pixels
) << ")");
1937 if (level
< 0 || height
< 0 || width
< 0) {
1938 SetGLError(GL_INVALID_VALUE
, "glTexSubImage2D", "dimension < 0");
1941 if (height
== 0 || width
== 0) {
1946 uint32 unpadded_row_size
;
1947 uint32 padded_row_size
;
1948 if (!GLES2Util::ComputeImageDataSizes(
1949 width
, height
, 1, format
, type
, unpack_alignment_
, &temp_size
,
1950 &unpadded_row_size
, &padded_row_size
)) {
1951 SetGLError(GL_INVALID_VALUE
, "glTexSubImage2D", "size to large");
1955 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1956 if (bound_pixel_unpack_transfer_buffer_id_
) {
1957 GLuint offset
= ToGLuint(pixels
);
1958 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1959 bound_pixel_unpack_transfer_buffer_id_
,
1960 "glTexSubImage2D", offset
, temp_size
);
1961 if (buffer
&& buffer
->shm_id() != -1) {
1962 helper_
->TexSubImage2D(
1963 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
,
1964 buffer
->shm_id(), buffer
->shm_offset() + offset
, false);
1965 buffer
->set_last_usage_token(helper_
->InsertToken());
1971 // compute the advance bytes per row for the src pixels
1972 uint32 src_padded_row_size
;
1973 if (unpack_row_length_
> 0) {
1974 if (!GLES2Util::ComputeImagePaddedRowSize(
1975 unpack_row_length_
, format
, type
, unpack_alignment_
,
1976 &src_padded_row_size
)) {
1978 GL_INVALID_VALUE
, "glTexImage2D", "unpack row length too large");
1982 src_padded_row_size
= padded_row_size
;
1985 // advance pixels pointer past the skip rows and skip pixels
1986 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1987 unpack_skip_rows_
* src_padded_row_size
;
1988 if (unpack_skip_pixels_
) {
1989 uint32 group_size
= GLES2Util::ComputeImageGroupSize(format
, type
);
1990 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1991 unpack_skip_pixels_
* group_size
;
1994 ScopedTransferBufferPtr
buffer(temp_size
, helper_
, transfer_buffer_
);
1996 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
,
1997 unpadded_row_size
, pixels
, src_padded_row_size
, GL_FALSE
, &buffer
,
2002 void GLES2Implementation::TexSubImage3D(
2003 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLint zoffset
,
2004 GLsizei width
, GLsizei height
, GLsizei depth
, GLenum format
, GLenum type
,
2005 const void* pixels
) {
2006 GPU_CLIENT_SINGLE_THREAD_CHECK();
2007 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D("
2008 << GLES2Util::GetStringTextureTarget(target
) << ", "
2010 << xoffset
<< ", " << yoffset
<< ", " << zoffset
<< ", "
2011 << width
<< ", " << height
<< ", " << depth
<< ", "
2012 << GLES2Util::GetStringTextureFormat(format
) << ", "
2013 << GLES2Util::GetStringPixelType(type
) << ", "
2014 << static_cast<const void*>(pixels
) << ")");
2016 if (level
< 0 || height
< 0 || width
< 0 || depth
< 0) {
2017 SetGLError(GL_INVALID_VALUE
, "glTexSubImage3D", "dimension < 0");
2020 if (height
== 0 || width
== 0 || depth
== 0) {
2025 uint32 unpadded_row_size
;
2026 uint32 padded_row_size
;
2027 if (!GLES2Util::ComputeImageDataSizes(
2028 width
, height
, depth
, format
, type
, unpack_alignment_
, &temp_size
,
2029 &unpadded_row_size
, &padded_row_size
)) {
2030 SetGLError(GL_INVALID_VALUE
, "glTexSubImage3D", "size to large");
2034 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2035 if (bound_pixel_unpack_transfer_buffer_id_
) {
2036 GLuint offset
= ToGLuint(pixels
);
2037 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
2038 bound_pixel_unpack_transfer_buffer_id_
,
2039 "glTexSubImage3D", offset
, temp_size
);
2040 if (buffer
&& buffer
->shm_id() != -1) {
2041 helper_
->TexSubImage3D(
2042 target
, level
, xoffset
, yoffset
, zoffset
, width
, height
, depth
,
2043 format
, type
, buffer
->shm_id(), buffer
->shm_offset() + offset
, false);
2044 buffer
->set_last_usage_token(helper_
->InsertToken());
2050 // compute the advance bytes per row for the src pixels
2051 uint32 src_padded_row_size
;
2052 if (unpack_row_length_
> 0) {
2053 if (!GLES2Util::ComputeImagePaddedRowSize(
2054 unpack_row_length_
, format
, type
, unpack_alignment_
,
2055 &src_padded_row_size
)) {
2057 GL_INVALID_VALUE
, "glTexImage3D", "unpack row length too large");
2061 src_padded_row_size
= padded_row_size
;
2063 uint32 src_height
= unpack_image_height_
> 0 ? unpack_image_height_
: height
;
2065 // advance pixels pointer past the skip images/rows/pixels
2066 pixels
= reinterpret_cast<const int8
*>(pixels
) +
2067 unpack_skip_images_
* src_padded_row_size
* src_height
+
2068 unpack_skip_rows_
* src_padded_row_size
;
2069 if (unpack_skip_pixels_
) {
2070 uint32 group_size
= GLES2Util::ComputeImageGroupSize(format
, type
);
2071 pixels
= reinterpret_cast<const int8
*>(pixels
) +
2072 unpack_skip_pixels_
* group_size
;
2075 ScopedTransferBufferPtr
buffer(temp_size
, helper_
, transfer_buffer_
);
2077 target
, level
, xoffset
, yoffset
, zoffset
, width
, height
, depth
,
2078 format
, type
, unpadded_row_size
, pixels
, src_padded_row_size
, GL_FALSE
,
2079 &buffer
, padded_row_size
);
2083 static GLint
ComputeNumRowsThatFitInBuffer(
2084 uint32 padded_row_size
, uint32 unpadded_row_size
,
2085 unsigned int size
, GLsizei remaining_rows
) {
2086 DCHECK_GE(unpadded_row_size
, 0u);
2087 if (padded_row_size
== 0) {
2090 GLint num_rows
= size
/ padded_row_size
;
2091 if (num_rows
+ 1 == remaining_rows
&&
2092 size
- num_rows
* padded_row_size
>= unpadded_row_size
) {
2098 void GLES2Implementation::TexSubImage2DImpl(
2099 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
2100 GLsizei height
, GLenum format
, GLenum type
, uint32 unpadded_row_size
,
2101 const void* pixels
, uint32 pixels_padded_row_size
, GLboolean internal
,
2102 ScopedTransferBufferPtr
* buffer
, uint32 buffer_padded_row_size
) {
2104 DCHECK_GE(level
, 0);
2105 DCHECK_GT(height
, 0);
2106 DCHECK_GT(width
, 0);
2108 const int8
* source
= reinterpret_cast<const int8
*>(pixels
);
2109 GLint original_yoffset
= yoffset
;
2110 // Transfer by rows.
2112 unsigned int desired_size
=
2113 buffer_padded_row_size
* (height
- 1) + unpadded_row_size
;
2114 if (!buffer
->valid() || buffer
->size() == 0) {
2115 buffer
->Reset(desired_size
);
2116 if (!buffer
->valid()) {
2121 GLint num_rows
= ComputeNumRowsThatFitInBuffer(
2122 buffer_padded_row_size
, unpadded_row_size
, buffer
->size(), height
);
2123 num_rows
= std::min(num_rows
, height
);
2125 source
, num_rows
, unpadded_row_size
, pixels_padded_row_size
,
2126 unpack_flip_y_
, buffer
->address(), buffer_padded_row_size
);
2127 GLint y
= unpack_flip_y_
? original_yoffset
+ height
- num_rows
: yoffset
;
2128 helper_
->TexSubImage2D(
2129 target
, level
, xoffset
, y
, width
, num_rows
, format
, type
,
2130 buffer
->shm_id(), buffer
->offset(), internal
);
2132 yoffset
+= num_rows
;
2133 source
+= num_rows
* pixels_padded_row_size
;
2138 void GLES2Implementation::TexSubImage3DImpl(
2139 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei zoffset
,
2140 GLsizei width
, GLsizei height
, GLsizei depth
, GLenum format
, GLenum type
,
2141 uint32 unpadded_row_size
, const void* pixels
, uint32 pixels_padded_row_size
,
2142 GLboolean internal
, ScopedTransferBufferPtr
* buffer
,
2143 uint32 buffer_padded_row_size
) {
2145 DCHECK_GE(level
, 0);
2146 DCHECK_GT(height
, 0);
2147 DCHECK_GT(width
, 0);
2148 DCHECK_GT(depth
, 0);
2149 const int8
* source
= reinterpret_cast<const int8
*>(pixels
);
2150 GLsizei total_rows
= height
* depth
;
2151 GLint row_index
= 0, depth_index
= 0;
2152 while (total_rows
) {
2153 // Each time, we either copy one or more images, or copy one or more rows
2154 // within a single image, depending on the buffer size limit.
2156 unsigned int desired_size
;
2157 if (row_index
> 0) {
2158 // We are in the middle of an image. Send the remaining of the image.
2159 max_rows
= height
- row_index
;
2160 if (total_rows
<= height
) {
2161 // Last image, so last row is unpadded.
2162 desired_size
= buffer_padded_row_size
* (max_rows
- 1) +
2165 desired_size
= buffer_padded_row_size
* max_rows
;
2168 // Send all the remaining data if possible.
2169 max_rows
= total_rows
;
2171 buffer_padded_row_size
* (max_rows
- 1) + unpadded_row_size
;
2173 if (!buffer
->valid() || buffer
->size() == 0) {
2174 buffer
->Reset(desired_size
);
2175 if (!buffer
->valid()) {
2179 GLint num_rows
= ComputeNumRowsThatFitInBuffer(
2180 buffer_padded_row_size
, unpadded_row_size
, buffer
->size(), total_rows
);
2181 num_rows
= std::min(num_rows
, max_rows
);
2182 GLint num_images
= num_rows
/ height
;
2183 GLsizei my_height
, my_depth
;
2184 if (num_images
> 0) {
2185 num_rows
= num_images
* height
;
2187 my_depth
= num_images
;
2189 my_height
= num_rows
;
2193 // TODO(zmo): Ignore flip_y flag for now.
2194 if (num_images
> 0) {
2195 int8
* buffer_pointer
= reinterpret_cast<int8
*>(buffer
->address());
2197 unpack_image_height_
> 0 ? unpack_image_height_
: height
;
2198 uint32 image_size_dst
= buffer_padded_row_size
* height
;
2199 uint32 image_size_src
= pixels_padded_row_size
* src_height
;
2200 for (GLint ii
= 0; ii
< num_images
; ++ii
) {
2201 uint32 my_unpadded_row_size
;
2202 if (total_rows
== num_rows
&& ii
+ 1 == num_images
)
2203 my_unpadded_row_size
= unpadded_row_size
;
2205 my_unpadded_row_size
= pixels_padded_row_size
;
2207 source
+ ii
* image_size_src
, my_height
, my_unpadded_row_size
,
2208 pixels_padded_row_size
, false, buffer_pointer
+ ii
* image_size_dst
,
2209 buffer_padded_row_size
);
2212 uint32 my_unpadded_row_size
;
2213 if (total_rows
== num_rows
)
2214 my_unpadded_row_size
= unpadded_row_size
;
2216 my_unpadded_row_size
= pixels_padded_row_size
;
2218 source
, my_height
, my_unpadded_row_size
, pixels_padded_row_size
,
2219 false, buffer
->address(), buffer_padded_row_size
);
2221 helper_
->TexSubImage3D(
2222 target
, level
, xoffset
, yoffset
+ row_index
, zoffset
+ depth_index
,
2223 width
, my_height
, my_depth
,
2224 format
, type
, buffer
->shm_id(), buffer
->offset(), internal
);
2227 total_rows
-= num_rows
;
2228 if (total_rows
> 0) {
2229 GLint num_image_paddings
;
2230 if (num_images
> 0) {
2231 DCHECK_EQ(row_index
, 0);
2232 depth_index
+= num_images
;
2233 num_image_paddings
= num_images
;
2235 row_index
= (row_index
+ my_height
) % height
;
2236 num_image_paddings
= 0;
2237 if (my_height
> 0 && row_index
== 0) {
2239 num_image_paddings
++;
2242 source
+= num_rows
* pixels_padded_row_size
;
2243 if (unpack_image_height_
> height
&& num_image_paddings
> 0) {
2244 source
+= num_image_paddings
* (unpack_image_height_
- height
) *
2245 pixels_padded_row_size
;
2251 bool GLES2Implementation::GetActiveAttribHelper(
2252 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2253 GLenum
* type
, char* name
) {
2254 // Clear the bucket so if the command fails nothing will be in it.
2255 helper_
->SetBucketSize(kResultBucketId
, 0);
2256 typedef cmds::GetActiveAttrib::Result Result
;
2257 Result
* result
= GetResultAs
<Result
*>();
2261 // Set as failed so if the command fails we'll recover.
2262 result
->success
= false;
2263 helper_
->GetActiveAttrib(program
, index
, kResultBucketId
,
2264 GetResultShmId(), GetResultShmOffset());
2266 if (result
->success
) {
2268 *size
= result
->size
;
2271 *type
= result
->type
;
2273 if (length
|| name
) {
2274 std::vector
<int8
> str
;
2275 GetBucketContents(kResultBucketId
, &str
);
2276 GLsizei max_size
= std::min(static_cast<size_t>(bufsize
) - 1,
2277 std::max(static_cast<size_t>(0),
2282 if (name
&& bufsize
> 0) {
2283 memcpy(name
, &str
[0], max_size
);
2284 name
[max_size
] = '\0';
2288 return result
->success
!= 0;
2291 void GLES2Implementation::GetActiveAttrib(
2292 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2293 GLenum
* type
, char* name
) {
2294 GPU_CLIENT_SINGLE_THREAD_CHECK();
2295 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2296 << program
<< ", " << index
<< ", " << bufsize
<< ", "
2297 << static_cast<const void*>(length
) << ", "
2298 << static_cast<const void*>(size
) << ", "
2299 << static_cast<const void*>(type
) << ", "
2300 << static_cast<const void*>(name
) << ", ");
2302 SetGLError(GL_INVALID_VALUE
, "glGetActiveAttrib", "bufsize < 0");
2305 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2306 bool success
= share_group_
->program_info_manager()->GetActiveAttrib(
2307 this, program
, index
, bufsize
, length
, size
, type
, name
);
2310 GPU_CLIENT_LOG(" size: " << *size
);
2313 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type
));
2316 GPU_CLIENT_LOG(" name: " << name
);
2322 bool GLES2Implementation::GetActiveUniformHelper(
2323 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2324 GLenum
* type
, char* name
) {
2325 // Clear the bucket so if the command fails nothing will be in it.
2326 helper_
->SetBucketSize(kResultBucketId
, 0);
2327 typedef cmds::GetActiveUniform::Result Result
;
2328 Result
* result
= GetResultAs
<Result
*>();
2332 // Set as failed so if the command fails we'll recover.
2333 result
->success
= false;
2334 helper_
->GetActiveUniform(program
, index
, kResultBucketId
,
2335 GetResultShmId(), GetResultShmOffset());
2337 if (result
->success
) {
2339 *size
= result
->size
;
2342 *type
= result
->type
;
2344 if (length
|| name
) {
2345 std::vector
<int8
> str
;
2346 GetBucketContents(kResultBucketId
, &str
);
2347 GLsizei max_size
= std::min(static_cast<size_t>(bufsize
) - 1,
2348 std::max(static_cast<size_t>(0),
2353 if (name
&& bufsize
> 0) {
2354 memcpy(name
, &str
[0], max_size
);
2355 name
[max_size
] = '\0';
2359 return result
->success
!= 0;
2362 void GLES2Implementation::GetActiveUniform(
2363 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2364 GLenum
* type
, char* name
) {
2365 GPU_CLIENT_SINGLE_THREAD_CHECK();
2366 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2367 << program
<< ", " << index
<< ", " << bufsize
<< ", "
2368 << static_cast<const void*>(length
) << ", "
2369 << static_cast<const void*>(size
) << ", "
2370 << static_cast<const void*>(type
) << ", "
2371 << static_cast<const void*>(name
) << ", ");
2373 SetGLError(GL_INVALID_VALUE
, "glGetActiveUniform", "bufsize < 0");
2376 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2377 bool success
= share_group_
->program_info_manager()->GetActiveUniform(
2378 this, program
, index
, bufsize
, length
, size
, type
, name
);
2381 GPU_CLIENT_LOG(" size: " << *size
);
2384 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type
));
2387 GPU_CLIENT_LOG(" name: " << name
);
2393 bool GLES2Implementation::GetActiveUniformBlockNameHelper(
2394 GLuint program
, GLuint index
, GLsizei bufsize
,
2395 GLsizei
* length
, char* name
) {
2396 DCHECK_LE(0, bufsize
);
2397 // Clear the bucket so if the command fails nothing will be in it.
2398 helper_
->SetBucketSize(kResultBucketId
, 0);
2399 typedef cmds::GetActiveUniformBlockName::Result Result
;
2400 Result
* result
= GetResultAs
<Result
*>();
2404 // Set as failed so if the command fails we'll recover.
2406 helper_
->GetActiveUniformBlockName(program
, index
, kResultBucketId
,
2407 GetResultShmId(), GetResultShmOffset());
2414 } else if (length
|| name
) {
2415 std::vector
<int8
> str
;
2416 GetBucketContents(kResultBucketId
, &str
);
2417 DCHECK(str
.size() > 0);
2419 std::min(bufsize
, static_cast<GLsizei
>(str
.size())) - 1;
2424 memcpy(name
, &str
[0], max_size
);
2425 name
[max_size
] = '\0';
2429 return *result
!= 0;
2432 void GLES2Implementation::GetActiveUniformBlockName(
2433 GLuint program
, GLuint index
, GLsizei bufsize
,
2434 GLsizei
* length
, char* name
) {
2435 GPU_CLIENT_SINGLE_THREAD_CHECK();
2436 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
2437 << program
<< ", " << index
<< ", " << bufsize
<< ", "
2438 << static_cast<const void*>(length
) << ", "
2439 << static_cast<const void*>(name
) << ")");
2441 SetGLError(GL_INVALID_VALUE
, "glGetActiveUniformBlockName", "bufsize < 0");
2444 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockName");
2446 share_group_
->program_info_manager()->GetActiveUniformBlockName(
2447 this, program
, index
, bufsize
, length
, name
);
2450 GPU_CLIENT_LOG(" name: " << name
);
2456 bool GLES2Implementation::GetActiveUniformBlockivHelper(
2457 GLuint program
, GLuint index
, GLenum pname
, GLint
* params
) {
2458 typedef cmds::GetActiveUniformBlockiv::Result Result
;
2459 Result
* result
= GetResultAs
<Result
*>();
2463 result
->SetNumResults(0);
2464 helper_
->GetActiveUniformBlockiv(
2465 program
, index
, pname
, GetResultShmId(), GetResultShmOffset());
2467 if (result
->GetNumResults() > 0) {
2469 result
->CopyResult(params
);
2471 GPU_CLIENT_LOG_CODE_BLOCK({
2472 for (int32_t i
= 0; i
< result
->GetNumResults(); ++i
) {
2473 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2481 void GLES2Implementation::GetActiveUniformBlockiv(
2482 GLuint program
, GLuint index
, GLenum pname
, GLint
* params
) {
2483 GPU_CLIENT_SINGLE_THREAD_CHECK();
2484 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
2485 << program
<< ", " << index
<< ", "
2486 << GLES2Util::GetStringUniformBlockParameter(pname
) << ", "
2487 << static_cast<const void*>(params
) << ")");
2488 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
2490 share_group_
->program_info_manager()->GetActiveUniformBlockiv(
2491 this, program
, index
, pname
, params
);
2494 // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
2495 // be more than one value returned in params.
2496 GPU_CLIENT_LOG(" params: " << params
[0]);
2502 bool GLES2Implementation::GetActiveUniformsivHelper(
2503 GLuint program
, GLsizei count
, const GLuint
* indices
,
2504 GLenum pname
, GLint
* params
) {
2505 typedef cmds::GetActiveUniformsiv::Result Result
;
2506 Result
* result
= GetResultAs
<Result
*>();
2510 result
->SetNumResults(0);
2511 base::CheckedNumeric
<size_t> bytes
= static_cast<size_t>(count
);
2512 bytes
*= sizeof(GLuint
);
2513 if (!bytes
.IsValid()) {
2514 SetGLError(GL_INVALID_VALUE
, "glGetActiveUniformsiv", "count overflow");
2517 SetBucketContents(kResultBucketId
, indices
, bytes
.ValueOrDefault(0));
2518 helper_
->GetActiveUniformsiv(
2519 program
, kResultBucketId
, pname
, GetResultShmId(), GetResultShmOffset());
2521 bool success
= result
->GetNumResults() == count
;
2524 result
->CopyResult(params
);
2526 GPU_CLIENT_LOG_CODE_BLOCK({
2527 for (int32_t i
= 0; i
< result
->GetNumResults(); ++i
) {
2528 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2532 helper_
->SetBucketSize(kResultBucketId
, 0);
2536 void GLES2Implementation::GetActiveUniformsiv(
2537 GLuint program
, GLsizei count
, const GLuint
* indices
,
2538 GLenum pname
, GLint
* params
) {
2539 GPU_CLIENT_SINGLE_THREAD_CHECK();
2540 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv("
2541 << program
<< ", " << count
<< ", "
2542 << static_cast<const void*>(indices
) << ", "
2543 << GLES2Util::GetStringUniformParameter(pname
) << ", "
2544 << static_cast<const void*>(params
) << ")");
2545 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
2547 SetGLError(GL_INVALID_VALUE
, "glGetActiveUniformsiv", "count < 0");
2550 bool success
= share_group_
->program_info_manager()->GetActiveUniformsiv(
2551 this, program
, count
, indices
, pname
, params
);
2554 GPU_CLIENT_LOG_CODE_BLOCK({
2555 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
2556 GPU_CLIENT_LOG(" " << ii
<< ": " << params
[ii
]);
2564 void GLES2Implementation::GetAttachedShaders(
2565 GLuint program
, GLsizei maxcount
, GLsizei
* count
, GLuint
* shaders
) {
2566 GPU_CLIENT_SINGLE_THREAD_CHECK();
2567 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2568 << program
<< ", " << maxcount
<< ", "
2569 << static_cast<const void*>(count
) << ", "
2570 << static_cast<const void*>(shaders
) << ", ");
2572 SetGLError(GL_INVALID_VALUE
, "glGetAttachedShaders", "maxcount < 0");
2575 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2576 typedef cmds::GetAttachedShaders::Result Result
;
2577 uint32 size
= Result::ComputeSize(maxcount
);
2578 Result
* result
= static_cast<Result
*>(transfer_buffer_
->Alloc(size
));
2582 result
->SetNumResults(0);
2583 helper_
->GetAttachedShaders(
2585 transfer_buffer_
->GetShmId(),
2586 transfer_buffer_
->GetOffset(result
),
2588 int32 token
= helper_
->InsertToken();
2591 *count
= result
->GetNumResults();
2593 result
->CopyResult(shaders
);
2594 GPU_CLIENT_LOG_CODE_BLOCK({
2595 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2596 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2599 transfer_buffer_
->FreePendingToken(result
, token
);
2603 void GLES2Implementation::GetShaderPrecisionFormat(
2604 GLenum shadertype
, GLenum precisiontype
, GLint
* range
, GLint
* precision
) {
2605 GPU_CLIENT_SINGLE_THREAD_CHECK();
2606 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2607 << GLES2Util::GetStringShaderType(shadertype
) << ", "
2608 << GLES2Util::GetStringShaderPrecision(precisiontype
) << ", "
2609 << static_cast<const void*>(range
) << ", "
2610 << static_cast<const void*>(precision
) << ", ");
2611 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2612 typedef cmds::GetShaderPrecisionFormat::Result Result
;
2613 Result
* result
= GetResultAs
<Result
*>();
2618 GLStaticState::ShaderPrecisionKey
key(shadertype
, precisiontype
);
2619 GLStaticState::ShaderPrecisionMap::iterator i
=
2620 static_state_
.shader_precisions
.find(key
);
2621 if (i
!= static_state_
.shader_precisions
.end()) {
2622 *result
= i
->second
;
2624 result
->success
= false;
2625 helper_
->GetShaderPrecisionFormat(
2626 shadertype
, precisiontype
, GetResultShmId(), GetResultShmOffset());
2628 if (result
->success
)
2629 static_state_
.shader_precisions
[key
] = *result
;
2632 if (result
->success
) {
2634 range
[0] = result
->min_range
;
2635 range
[1] = result
->max_range
;
2636 GPU_CLIENT_LOG(" min_range: " << range
[0]);
2637 GPU_CLIENT_LOG(" min_range: " << range
[1]);
2640 precision
[0] = result
->precision
;
2641 GPU_CLIENT_LOG(" min_range: " << precision
[0]);
2647 const GLubyte
* GLES2Implementation::GetStringHelper(GLenum name
) {
2648 const char* result
= NULL
;
2649 // Clears the bucket so if the command fails nothing will be in it.
2650 helper_
->SetBucketSize(kResultBucketId
, 0);
2651 helper_
->GetString(name
, kResultBucketId
);
2653 if (GetBucketAsString(kResultBucketId
, &str
)) {
2654 // Adds extensions implemented on client side only.
2657 str
+= std::string(str
.empty() ? "" : " ") +
2658 "GL_CHROMIUM_flipy "
2659 "GL_EXT_unpack_subimage "
2660 "GL_CHROMIUM_map_sub";
2661 if (capabilities_
.image
)
2662 str
+= " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
2663 if (capabilities_
.future_sync_points
)
2664 str
+= " GL_CHROMIUM_future_sync_point";
2670 // Because of WebGL the extensions can change. We have to cache each unique
2671 // result since we don't know when the client will stop referring to a
2672 // previous one it queries.
2673 GLStringMap::iterator it
= gl_strings_
.find(name
);
2674 if (it
== gl_strings_
.end()) {
2675 std::set
<std::string
> strings
;
2676 std::pair
<GLStringMap::iterator
, bool> insert_result
=
2677 gl_strings_
.insert(std::make_pair(name
, strings
));
2678 DCHECK(insert_result
.second
);
2679 it
= insert_result
.first
;
2681 std::set
<std::string
>& string_set
= it
->second
;
2682 std::set
<std::string
>::const_iterator sit
= string_set
.find(str
);
2683 if (sit
!= string_set
.end()) {
2684 result
= sit
->c_str();
2686 std::pair
<std::set
<std::string
>::const_iterator
, bool> insert_result
=
2687 string_set
.insert(str
);
2688 DCHECK(insert_result
.second
);
2689 result
= insert_result
.first
->c_str();
2692 return reinterpret_cast<const GLubyte
*>(result
);
2695 const GLubyte
* GLES2Implementation::GetString(GLenum name
) {
2696 GPU_CLIENT_SINGLE_THREAD_CHECK();
2697 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2698 << GLES2Util::GetStringStringType(name
) << ")");
2699 TRACE_EVENT0("gpu", "GLES2::GetString");
2700 const GLubyte
* result
= GetStringHelper(name
);
2701 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result
));
2706 bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
2707 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2708 GLenum
* type
, char* name
) {
2709 // Clear the bucket so if the command fails nothing will be in it.
2710 helper_
->SetBucketSize(kResultBucketId
, 0);
2711 typedef cmds::GetTransformFeedbackVarying::Result Result
;
2712 Result
* result
= GetResultAs
<Result
*>();
2716 // Set as failed so if the command fails we'll recover.
2717 result
->success
= false;
2718 helper_
->GetTransformFeedbackVarying(
2719 program
, index
, kResultBucketId
, GetResultShmId(), GetResultShmOffset());
2721 if (result
->success
) {
2723 *size
= result
->size
;
2726 *type
= result
->type
;
2728 if (length
|| name
) {
2729 std::vector
<int8
> str
;
2730 GetBucketContents(kResultBucketId
, &str
);
2731 GLsizei max_size
= std::min(bufsize
, static_cast<GLsizei
>(str
.size()));
2740 memcpy(name
, &str
[0], max_size
);
2741 name
[max_size
] = '\0';
2742 } else if (bufsize
> 0) {
2748 return result
->success
!= 0;
2751 void GLES2Implementation::GetTransformFeedbackVarying(
2752 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2753 GLenum
* type
, char* name
) {
2754 GPU_CLIENT_SINGLE_THREAD_CHECK();
2755 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
2756 << program
<< ", " << index
<< ", " << bufsize
<< ", "
2757 << static_cast<const void*>(length
) << ", "
2758 << static_cast<const void*>(size
) << ", "
2759 << static_cast<const void*>(type
) << ", "
2760 << static_cast<const void*>(name
) << ", ");
2762 SetGLError(GL_INVALID_VALUE
, "glGetTransformFeedbackVarying",
2766 TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
2768 share_group_
->program_info_manager()->GetTransformFeedbackVarying(
2769 this, program
, index
, bufsize
, length
, size
, type
, name
);
2772 GPU_CLIENT_LOG(" size: " << *size
);
2775 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type
));
2778 GPU_CLIENT_LOG(" name: " << name
);
2784 void GLES2Implementation::GetUniformfv(
2785 GLuint program
, GLint location
, GLfloat
* params
) {
2786 GPU_CLIENT_SINGLE_THREAD_CHECK();
2787 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2788 << program
<< ", " << location
<< ", "
2789 << static_cast<const void*>(params
) << ")");
2790 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2791 typedef cmds::GetUniformfv::Result Result
;
2792 Result
* result
= GetResultAs
<Result
*>();
2796 result
->SetNumResults(0);
2797 helper_
->GetUniformfv(
2798 program
, location
, GetResultShmId(), GetResultShmOffset());
2800 result
->CopyResult(params
);
2801 GPU_CLIENT_LOG_CODE_BLOCK({
2802 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2803 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2809 void GLES2Implementation::GetUniformiv(
2810 GLuint program
, GLint location
, GLint
* params
) {
2811 GPU_CLIENT_SINGLE_THREAD_CHECK();
2812 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2813 << program
<< ", " << location
<< ", "
2814 << static_cast<const void*>(params
) << ")");
2815 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2816 typedef cmds::GetUniformiv::Result Result
;
2817 Result
* result
= GetResultAs
<Result
*>();
2821 result
->SetNumResults(0);
2822 helper_
->GetUniformiv(
2823 program
, location
, GetResultShmId(), GetResultShmOffset());
2825 GetResultAs
<cmds::GetUniformfv::Result
*>()->CopyResult(params
);
2826 GPU_CLIENT_LOG_CODE_BLOCK({
2827 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2828 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2834 void GLES2Implementation::ReadPixels(
2835 GLint xoffset
, GLint yoffset
, GLsizei width
, GLsizei height
, GLenum format
,
2836 GLenum type
, void* pixels
) {
2837 GPU_CLIENT_SINGLE_THREAD_CHECK();
2838 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2839 << xoffset
<< ", " << yoffset
<< ", "
2840 << width
<< ", " << height
<< ", "
2841 << GLES2Util::GetStringReadPixelFormat(format
) << ", "
2842 << GLES2Util::GetStringPixelType(type
) << ", "
2843 << static_cast<const void*>(pixels
) << ")");
2844 if (width
< 0 || height
< 0) {
2845 SetGLError(GL_INVALID_VALUE
, "glReadPixels", "dimensions < 0");
2848 if (width
== 0 || height
== 0) {
2852 // glReadPixel pads the size of each row of pixels by an amount specified by
2853 // glPixelStorei. So, we have to take that into account both in the fact that
2854 // the pixels returned from the ReadPixel command will include that padding
2855 // and that when we copy the results to the user's buffer we need to not
2856 // write those padding bytes but leave them as they are.
2858 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2859 typedef cmds::ReadPixels::Result Result
;
2861 int8
* dest
= reinterpret_cast<int8
*>(pixels
);
2863 uint32 unpadded_row_size
;
2864 uint32 padded_row_size
;
2865 if (!GLES2Util::ComputeImageDataSizes(
2866 width
, 2, 1, format
, type
, pack_alignment_
, &temp_size
,
2867 &unpadded_row_size
, &padded_row_size
)) {
2868 SetGLError(GL_INVALID_VALUE
, "glReadPixels", "size too large.");
2872 if (bound_pixel_pack_transfer_buffer_id_
) {
2873 GLuint offset
= ToGLuint(pixels
);
2874 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
2875 bound_pixel_pack_transfer_buffer_id_
,
2876 "glReadPixels", offset
, padded_row_size
* height
);
2877 if (buffer
&& buffer
->shm_id() != -1) {
2878 helper_
->ReadPixels(xoffset
, yoffset
, width
, height
, format
, type
,
2879 buffer
->shm_id(), buffer
->shm_offset(),
2887 SetGLError(GL_INVALID_OPERATION
, "glReadPixels", "pixels = NULL");
2891 // Transfer by rows.
2892 // The max rows we can transfer.
2894 GLsizei desired_size
= padded_row_size
* (height
- 1) + unpadded_row_size
;
2895 ScopedTransferBufferPtr
buffer(desired_size
, helper_
, transfer_buffer_
);
2896 if (!buffer
.valid()) {
2899 GLint num_rows
= ComputeNumRowsThatFitInBuffer(
2900 padded_row_size
, unpadded_row_size
, buffer
.size(), height
);
2901 num_rows
= std::min(num_rows
, height
);
2902 // NOTE: We must look up the address of the result area AFTER allocation
2903 // of the transfer buffer since the transfer buffer may be reallocated.
2904 Result
* result
= GetResultAs
<Result
*>();
2908 *result
= 0; // mark as failed.
2909 helper_
->ReadPixels(
2910 xoffset
, yoffset
, width
, num_rows
, format
, type
,
2911 buffer
.shm_id(), buffer
.offset(),
2912 GetResultShmId(), GetResultShmOffset(),
2916 // when doing a y-flip we have to iterate through top-to-bottom chunks
2917 // of the dst. The service side handles reversing the rows within a
2920 if (pack_reverse_row_order_
) {
2921 rows_dst
= dest
+ (height
- num_rows
) * padded_row_size
;
2925 // We have to copy 1 row at a time to avoid writing pad bytes.
2926 const int8
* src
= static_cast<const int8
*>(buffer
.address());
2927 for (GLint yy
= 0; yy
< num_rows
; ++yy
) {
2928 memcpy(rows_dst
, src
, unpadded_row_size
);
2929 rows_dst
+= padded_row_size
;
2930 src
+= padded_row_size
;
2932 if (!pack_reverse_row_order_
) {
2936 // If it was not marked as successful exit.
2940 yoffset
+= num_rows
;
2946 void GLES2Implementation::ActiveTexture(GLenum texture
) {
2947 GPU_CLIENT_SINGLE_THREAD_CHECK();
2948 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2949 << GLES2Util::GetStringEnum(texture
) << ")");
2950 GLuint texture_index
= texture
- GL_TEXTURE0
;
2951 if (texture_index
>=
2952 static_cast<GLuint
>(capabilities_
.max_combined_texture_image_units
)) {
2953 SetGLErrorInvalidEnum(
2954 "glActiveTexture", texture
, "texture");
2958 active_texture_unit_
= texture_index
;
2959 helper_
->ActiveTexture(texture
);
2963 void GLES2Implementation::GenBuffersHelper(
2964 GLsizei
/* n */, const GLuint
* /* buffers */) {
2967 void GLES2Implementation::GenFramebuffersHelper(
2968 GLsizei
/* n */, const GLuint
* /* framebuffers */) {
2971 void GLES2Implementation::GenRenderbuffersHelper(
2972 GLsizei
/* n */, const GLuint
* /* renderbuffers */) {
2975 void GLES2Implementation::GenTexturesHelper(
2976 GLsizei
/* n */, const GLuint
* /* textures */) {
2979 void GLES2Implementation::GenVertexArraysOESHelper(
2980 GLsizei n
, const GLuint
* arrays
) {
2981 vertex_array_object_manager_
->GenVertexArrays(n
, arrays
);
2984 void GLES2Implementation::GenQueriesEXTHelper(
2985 GLsizei
/* n */, const GLuint
* /* queries */) {
2988 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
2990 const GLuint
* /* valuebuffers */) {
2993 void GLES2Implementation::GenSamplersHelper(
2994 GLsizei
/* n */, const GLuint
* /* samplers */) {
2997 void GLES2Implementation::GenTransformFeedbacksHelper(
2998 GLsizei
/* n */, const GLuint
* /* transformfeedbacks */) {
3001 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
3002 // generates a new resource. On newer versions of OpenGL they don't. The code
3003 // related to binding below will need to change if we switch to the new OpenGL
3004 // model. Specifically it assumes a bind will succeed which is always true in
3005 // the old model but possibly not true in the new model if another context has
3006 // deleted the resource.
3008 // NOTE #2: There is a bug in some BindXXXHelpers, that IDs might be marked as
3009 // used even when Bind has failed. However, the bug is minor compared to the
3010 // overhead & duplicated checking in client side.
3012 void GLES2Implementation::BindBufferHelper(
3013 GLenum target
, GLuint buffer_id
) {
3014 // TODO(gman): See note #1 above.
3015 bool changed
= false;
3017 case GL_ARRAY_BUFFER
:
3018 if (bound_array_buffer_id_
!= buffer_id
) {
3019 bound_array_buffer_id_
= buffer_id
;
3023 case GL_ELEMENT_ARRAY_BUFFER
:
3024 changed
= vertex_array_object_manager_
->BindElementArray(buffer_id
);
3026 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
:
3027 bound_pixel_pack_transfer_buffer_id_
= buffer_id
;
3029 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
:
3030 bound_pixel_unpack_transfer_buffer_id_
= buffer_id
;
3036 // TODO(gman): See note #2 above.
3038 GetIdHandler(id_namespaces::kBuffers
)->MarkAsUsedForBind(
3039 this, target
, buffer_id
, &GLES2Implementation::BindBufferStub
);
3043 void GLES2Implementation::BindBufferStub(GLenum target
, GLuint buffer
) {
3044 helper_
->BindBuffer(target
, buffer
);
3045 if (share_group_
->bind_generates_resource())
3046 helper_
->CommandBufferHelper::Flush();
3049 void GLES2Implementation::BindBufferBaseHelper(
3050 GLenum target
, GLuint index
, GLuint buffer_id
) {
3051 // TODO(zmo): See note #1 above.
3052 // TODO(zmo): See note #2 above.
3053 GetIdHandler(id_namespaces::kBuffers
)->MarkAsUsedForBind(
3054 this, target
, index
, buffer_id
, &GLES2Implementation::BindBufferBaseStub
);
3057 void GLES2Implementation::BindBufferBaseStub(
3058 GLenum target
, GLuint index
, GLuint buffer
) {
3059 helper_
->BindBufferBase(target
, index
, buffer
);
3060 if (share_group_
->bind_generates_resource())
3061 helper_
->CommandBufferHelper::Flush();
3064 void GLES2Implementation::BindBufferRangeHelper(
3065 GLenum target
, GLuint index
, GLuint buffer_id
,
3066 GLintptr offset
, GLsizeiptr size
) {
3067 // TODO(zmo): See note #1 above.
3068 // TODO(zmo): See note #2 above.
3069 GetIdHandler(id_namespaces::kBuffers
)->MarkAsUsedForBind(
3070 this, target
, index
, buffer_id
, offset
, size
,
3071 &GLES2Implementation::BindBufferRangeStub
);
3074 void GLES2Implementation::BindBufferRangeStub(
3075 GLenum target
, GLuint index
, GLuint buffer
,
3076 GLintptr offset
, GLsizeiptr size
) {
3077 helper_
->BindBufferRange(target
, index
, buffer
, offset
, size
);
3078 if (share_group_
->bind_generates_resource())
3079 helper_
->CommandBufferHelper::Flush();
3082 void GLES2Implementation::BindFramebufferHelper(
3083 GLenum target
, GLuint framebuffer
) {
3084 // TODO(gman): See note #1 above.
3085 bool changed
= false;
3087 case GL_FRAMEBUFFER
:
3088 if (bound_framebuffer_
!= framebuffer
||
3089 bound_read_framebuffer_
!= framebuffer
) {
3090 bound_framebuffer_
= framebuffer
;
3091 bound_read_framebuffer_
= framebuffer
;
3095 case GL_READ_FRAMEBUFFER
:
3096 if (!IsChromiumFramebufferMultisampleAvailable()) {
3097 SetGLErrorInvalidEnum("glBindFramebuffer", target
, "target");
3100 if (bound_read_framebuffer_
!= framebuffer
) {
3101 bound_read_framebuffer_
= framebuffer
;
3105 case GL_DRAW_FRAMEBUFFER
:
3106 if (!IsChromiumFramebufferMultisampleAvailable()) {
3107 SetGLErrorInvalidEnum("glBindFramebuffer", target
, "target");
3110 if (bound_framebuffer_
!= framebuffer
) {
3111 bound_framebuffer_
= framebuffer
;
3116 SetGLErrorInvalidEnum("glBindFramebuffer", target
, "target");
3121 GetIdHandler(id_namespaces::kFramebuffers
)->MarkAsUsedForBind(
3122 this, target
, framebuffer
, &GLES2Implementation::BindFramebufferStub
);
3126 void GLES2Implementation::BindFramebufferStub(GLenum target
,
3127 GLuint framebuffer
) {
3128 helper_
->BindFramebuffer(target
, framebuffer
);
3129 if (share_group_
->bind_generates_resource())
3130 helper_
->CommandBufferHelper::Flush();
3133 void GLES2Implementation::BindRenderbufferHelper(
3134 GLenum target
, GLuint renderbuffer
) {
3135 // TODO(gman): See note #1 above.
3136 bool changed
= false;
3138 case GL_RENDERBUFFER
:
3139 if (bound_renderbuffer_
!= renderbuffer
) {
3140 bound_renderbuffer_
= renderbuffer
;
3148 // TODO(zmo): See note #2 above.
3150 GetIdHandler(id_namespaces::kRenderbuffers
)->MarkAsUsedForBind(
3151 this, target
, renderbuffer
,
3152 &GLES2Implementation::BindRenderbufferStub
);
3156 void GLES2Implementation::BindRenderbufferStub(GLenum target
,
3157 GLuint renderbuffer
) {
3158 helper_
->BindRenderbuffer(target
, renderbuffer
);
3159 if (share_group_
->bind_generates_resource())
3160 helper_
->CommandBufferHelper::Flush();
3163 void GLES2Implementation::BindSamplerHelper(GLuint unit
,
3165 helper_
->BindSampler(unit
, sampler
);
3168 void GLES2Implementation::BindTextureHelper(GLenum target
, GLuint texture
) {
3169 // TODO(gman): See note #1 above.
3170 // TODO(gman): Change this to false once we figure out why it's failing
3172 bool changed
= true;
3173 TextureUnit
& unit
= texture_units_
[active_texture_unit_
];
3176 if (unit
.bound_texture_2d
!= texture
) {
3177 unit
.bound_texture_2d
= texture
;
3181 case GL_TEXTURE_CUBE_MAP
:
3182 if (unit
.bound_texture_cube_map
!= texture
) {
3183 unit
.bound_texture_cube_map
= texture
;
3187 case GL_TEXTURE_EXTERNAL_OES
:
3188 if (unit
.bound_texture_external_oes
!= texture
) {
3189 unit
.bound_texture_external_oes
= texture
;
3197 // TODO(gman): See note #2 above.
3199 GetIdHandler(id_namespaces::kTextures
)->MarkAsUsedForBind(
3200 this, target
, texture
, &GLES2Implementation::BindTextureStub
);
3204 void GLES2Implementation::BindTextureStub(GLenum target
, GLuint texture
) {
3205 helper_
->BindTexture(target
, texture
);
3206 if (share_group_
->bind_generates_resource())
3207 helper_
->CommandBufferHelper::Flush();
3210 void GLES2Implementation::BindTransformFeedbackHelper(
3211 GLenum target
, GLuint transformfeedback
) {
3212 helper_
->BindTransformFeedback(target
, transformfeedback
);
3215 void GLES2Implementation::BindVertexArrayOESHelper(GLuint array
) {
3216 bool changed
= false;
3217 if (vertex_array_object_manager_
->BindVertexArray(array
, &changed
)) {
3219 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
3220 // because unlike other resources VertexArrayObject ids must
3221 // be generated by GenVertexArrays. A random id to Bind will not
3222 // generate a new object.
3223 helper_
->BindVertexArrayOES(array
);
3227 GL_INVALID_OPERATION
, "glBindVertexArrayOES",
3228 "id was not generated with glGenVertexArrayOES");
3232 void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target
,
3233 GLuint valuebuffer
) {
3234 bool changed
= false;
3236 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM
:
3237 if (bound_valuebuffer_
!= valuebuffer
) {
3238 bound_valuebuffer_
= valuebuffer
;
3246 // TODO(gman): See note #2 above.
3248 GetIdHandler(id_namespaces::kValuebuffers
)->MarkAsUsedForBind(
3249 this, target
, valuebuffer
,
3250 &GLES2Implementation::BindValuebufferCHROMIUMStub
);
3254 void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target
,
3255 GLuint valuebuffer
) {
3256 helper_
->BindValuebufferCHROMIUM(target
, valuebuffer
);
3257 if (share_group_
->bind_generates_resource())
3258 helper_
->CommandBufferHelper::Flush();
3261 void GLES2Implementation::UseProgramHelper(GLuint program
) {
3262 if (current_program_
!= program
) {
3263 current_program_
= program
;
3264 helper_
->UseProgram(program
);
3268 bool GLES2Implementation::IsBufferReservedId(GLuint id
) {
3269 return vertex_array_object_manager_
->IsReservedId(id
);
3272 void GLES2Implementation::DeleteBuffersHelper(
3273 GLsizei n
, const GLuint
* buffers
) {
3274 if (!GetIdHandler(id_namespaces::kBuffers
)->FreeIds(
3275 this, n
, buffers
, &GLES2Implementation::DeleteBuffersStub
)) {
3278 "glDeleteBuffers", "id not created by this context.");
3281 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
3282 if (buffers
[ii
] == bound_array_buffer_id_
) {
3283 bound_array_buffer_id_
= 0;
3285 vertex_array_object_manager_
->UnbindBuffer(buffers
[ii
]);
3287 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffers
[ii
]);
3289 RemoveTransferBuffer(buffer
);
3291 if (buffers
[ii
] == bound_pixel_unpack_transfer_buffer_id_
) {
3292 bound_pixel_unpack_transfer_buffer_id_
= 0;
3297 void GLES2Implementation::DeleteBuffersStub(
3298 GLsizei n
, const GLuint
* buffers
) {
3299 helper_
->DeleteBuffersImmediate(n
, buffers
);
3303 void GLES2Implementation::DeleteFramebuffersHelper(
3304 GLsizei n
, const GLuint
* framebuffers
) {
3305 if (!GetIdHandler(id_namespaces::kFramebuffers
)->FreeIds(
3306 this, n
, framebuffers
, &GLES2Implementation::DeleteFramebuffersStub
)) {
3309 "glDeleteFramebuffers", "id not created by this context.");
3312 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
3313 if (framebuffers
[ii
] == bound_framebuffer_
) {
3314 bound_framebuffer_
= 0;
3316 if (framebuffers
[ii
] == bound_read_framebuffer_
) {
3317 bound_read_framebuffer_
= 0;
3322 void GLES2Implementation::DeleteFramebuffersStub(
3323 GLsizei n
, const GLuint
* framebuffers
) {
3324 helper_
->DeleteFramebuffersImmediate(n
, framebuffers
);
3327 void GLES2Implementation::DeleteRenderbuffersHelper(
3328 GLsizei n
, const GLuint
* renderbuffers
) {
3329 if (!GetIdHandler(id_namespaces::kRenderbuffers
)->FreeIds(
3330 this, n
, renderbuffers
, &GLES2Implementation::DeleteRenderbuffersStub
)) {
3333 "glDeleteRenderbuffers", "id not created by this context.");
3336 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
3337 if (renderbuffers
[ii
] == bound_renderbuffer_
) {
3338 bound_renderbuffer_
= 0;
3343 void GLES2Implementation::DeleteRenderbuffersStub(
3344 GLsizei n
, const GLuint
* renderbuffers
) {
3345 helper_
->DeleteRenderbuffersImmediate(n
, renderbuffers
);
3348 void GLES2Implementation::DeleteTexturesHelper(
3349 GLsizei n
, const GLuint
* textures
) {
3350 if (!GetIdHandler(id_namespaces::kTextures
)->FreeIds(
3351 this, n
, textures
, &GLES2Implementation::DeleteTexturesStub
)) {
3354 "glDeleteTextures", "id not created by this context.");
3357 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
3358 for (GLint tt
= 0; tt
< capabilities_
.max_combined_texture_image_units
;
3360 TextureUnit
& unit
= texture_units_
[tt
];
3361 if (textures
[ii
] == unit
.bound_texture_2d
) {
3362 unit
.bound_texture_2d
= 0;
3364 if (textures
[ii
] == unit
.bound_texture_cube_map
) {
3365 unit
.bound_texture_cube_map
= 0;
3367 if (textures
[ii
] == unit
.bound_texture_external_oes
) {
3368 unit
.bound_texture_external_oes
= 0;
3374 void GLES2Implementation::DeleteTexturesStub(GLsizei n
,
3375 const GLuint
* textures
) {
3376 helper_
->DeleteTexturesImmediate(n
, textures
);
3379 void GLES2Implementation::DeleteVertexArraysOESHelper(
3380 GLsizei n
, const GLuint
* arrays
) {
3381 vertex_array_object_manager_
->DeleteVertexArrays(n
, arrays
);
3382 if (!GetIdHandler(id_namespaces::kVertexArrays
)->FreeIds(
3383 this, n
, arrays
, &GLES2Implementation::DeleteVertexArraysOESStub
)) {
3386 "glDeleteVertexArraysOES", "id not created by this context.");
3391 void GLES2Implementation::DeleteVertexArraysOESStub(
3392 GLsizei n
, const GLuint
* arrays
) {
3393 helper_
->DeleteVertexArraysOESImmediate(n
, arrays
);
3396 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
3398 const GLuint
* valuebuffers
) {
3399 if (!GetIdHandler(id_namespaces::kValuebuffers
)
3400 ->FreeIds(this, n
, valuebuffers
,
3401 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub
)) {
3402 SetGLError(GL_INVALID_VALUE
, "glDeleteValuebuffersCHROMIUM",
3403 "id not created by this context.");
3406 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
3407 if (valuebuffers
[ii
] == bound_valuebuffer_
) {
3408 bound_valuebuffer_
= 0;
3413 void GLES2Implementation::DeleteSamplersStub(
3414 GLsizei n
, const GLuint
* samplers
) {
3415 helper_
->DeleteSamplersImmediate(n
, samplers
);
3418 void GLES2Implementation::DeleteSamplersHelper(
3419 GLsizei n
, const GLuint
* samplers
) {
3420 if (!GetIdHandler(id_namespaces::kSamplers
)->FreeIds(
3421 this, n
, samplers
, &GLES2Implementation::DeleteSamplersStub
)) {
3424 "glDeleteSamplers", "id not created by this context.");
3429 void GLES2Implementation::DeleteTransformFeedbacksStub(
3430 GLsizei n
, const GLuint
* transformfeedbacks
) {
3431 helper_
->DeleteTransformFeedbacksImmediate(n
, transformfeedbacks
);
3434 void GLES2Implementation::DeleteTransformFeedbacksHelper(
3435 GLsizei n
, const GLuint
* transformfeedbacks
) {
3436 if (!GetIdHandler(id_namespaces::kTransformFeedbacks
)->FreeIds(
3437 this, n
, transformfeedbacks
,
3438 &GLES2Implementation::DeleteTransformFeedbacksStub
)) {
3441 "glDeleteTransformFeedbacks", "id not created by this context.");
3446 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
3448 const GLuint
* valuebuffers
) {
3449 helper_
->DeleteValuebuffersCHROMIUMImmediate(n
, valuebuffers
);
3452 void GLES2Implementation::DisableVertexAttribArray(GLuint index
) {
3453 GPU_CLIENT_SINGLE_THREAD_CHECK();
3455 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index
<< ")");
3456 vertex_array_object_manager_
->SetAttribEnable(index
, false);
3457 helper_
->DisableVertexAttribArray(index
);
3461 void GLES2Implementation::EnableVertexAttribArray(GLuint index
) {
3462 GPU_CLIENT_SINGLE_THREAD_CHECK();
3463 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
3465 vertex_array_object_manager_
->SetAttribEnable(index
, true);
3466 helper_
->EnableVertexAttribArray(index
);
3470 void GLES2Implementation::DrawArrays(GLenum mode
, GLint first
, GLsizei count
) {
3471 GPU_CLIENT_SINGLE_THREAD_CHECK();
3472 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
3473 << GLES2Util::GetStringDrawMode(mode
) << ", "
3474 << first
<< ", " << count
<< ")");
3476 SetGLError(GL_INVALID_VALUE
, "glDrawArrays", "count < 0");
3479 bool simulated
= false;
3480 if (!vertex_array_object_manager_
->SetupSimulatedClientSideBuffers(
3481 "glDrawArrays", this, helper_
, first
+ count
, 0, &simulated
)) {
3484 helper_
->DrawArrays(mode
, first
, count
);
3485 RestoreArrayBuffer(simulated
);
3489 void GLES2Implementation::GetVertexAttribfv(
3490 GLuint index
, GLenum pname
, GLfloat
* params
) {
3491 GPU_CLIENT_SINGLE_THREAD_CHECK();
3492 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
3494 << GLES2Util::GetStringVertexAttribute(pname
) << ", "
3495 << static_cast<const void*>(params
) << ")");
3497 if (vertex_array_object_manager_
->GetVertexAttrib(index
, pname
, &value
)) {
3498 *params
= static_cast<float>(value
);
3501 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
3502 typedef cmds::GetVertexAttribfv::Result Result
;
3503 Result
* result
= GetResultAs
<Result
*>();
3507 result
->SetNumResults(0);
3508 helper_
->GetVertexAttribfv(
3509 index
, pname
, GetResultShmId(), GetResultShmOffset());
3511 result
->CopyResult(params
);
3512 GPU_CLIENT_LOG_CODE_BLOCK({
3513 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
3514 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
3520 void GLES2Implementation::GetVertexAttribiv(
3521 GLuint index
, GLenum pname
, GLint
* params
) {
3522 GPU_CLIENT_SINGLE_THREAD_CHECK();
3523 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
3525 << GLES2Util::GetStringVertexAttribute(pname
) << ", "
3526 << static_cast<const void*>(params
) << ")");
3528 if (vertex_array_object_manager_
->GetVertexAttrib(index
, pname
, &value
)) {
3532 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
3533 typedef cmds::GetVertexAttribiv::Result Result
;
3534 Result
* result
= GetResultAs
<Result
*>();
3538 result
->SetNumResults(0);
3539 helper_
->GetVertexAttribiv(
3540 index
, pname
, GetResultShmId(), GetResultShmOffset());
3542 result
->CopyResult(params
);
3543 GPU_CLIENT_LOG_CODE_BLOCK({
3544 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
3545 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
3551 void GLES2Implementation::Swap() {
3555 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect
& sub_buffer
) {
3556 PostSubBufferCHROMIUM(
3557 sub_buffer
.x(), sub_buffer
.y(), sub_buffer
.width(), sub_buffer
.height());
3560 static GLenum
GetGLESOverlayTransform(gfx::OverlayTransform plane_transform
) {
3561 switch (plane_transform
) {
3562 case gfx::OVERLAY_TRANSFORM_INVALID
:
3564 case gfx::OVERLAY_TRANSFORM_NONE
:
3565 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM
;
3566 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL
:
3567 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM
;
3568 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL
:
3569 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM
;
3570 case gfx::OVERLAY_TRANSFORM_ROTATE_90
:
3571 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM
;
3572 case gfx::OVERLAY_TRANSFORM_ROTATE_180
:
3573 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM
;
3574 case gfx::OVERLAY_TRANSFORM_ROTATE_270
:
3575 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM
;
3578 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM
;
3581 void GLES2Implementation::ScheduleOverlayPlane(
3583 gfx::OverlayTransform plane_transform
,
3584 unsigned overlay_texture_id
,
3585 const gfx::Rect
& display_bounds
,
3586 const gfx::RectF
& uv_rect
) {
3587 ScheduleOverlayPlaneCHROMIUM(plane_z_order
,
3588 GetGLESOverlayTransform(plane_transform
),
3592 display_bounds
.width(),
3593 display_bounds
.height(),
3600 GLboolean
GLES2Implementation::EnableFeatureCHROMIUM(
3601 const char* feature
) {
3602 GPU_CLIENT_SINGLE_THREAD_CHECK();
3603 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
3605 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
3606 typedef cmds::EnableFeatureCHROMIUM::Result Result
;
3607 Result
* result
= GetResultAs
<Result
*>();
3612 SetBucketAsCString(kResultBucketId
, feature
);
3613 helper_
->EnableFeatureCHROMIUM(
3614 kResultBucketId
, GetResultShmId(), GetResultShmOffset());
3616 helper_
->SetBucketSize(kResultBucketId
, 0);
3617 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result
));
3618 return *result
!= 0;
3621 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
3622 GLuint target
, GLintptr offset
, GLsizeiptr size
, GLenum access
) {
3623 GPU_CLIENT_SINGLE_THREAD_CHECK();
3624 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
3625 << target
<< ", " << offset
<< ", " << size
<< ", "
3626 << GLES2Util::GetStringEnum(access
) << ")");
3627 // NOTE: target is NOT checked because the service will check it
3628 // and we don't know what targets are valid.
3629 if (access
!= GL_WRITE_ONLY
) {
3630 SetGLErrorInvalidEnum(
3631 "glMapBufferSubDataCHROMIUM", access
, "access");
3634 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size
) ||
3635 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset
)) {
3640 unsigned int shm_offset
;
3641 void* mem
= mapped_memory_
->Alloc(size
, &shm_id
, &shm_offset
);
3643 SetGLError(GL_OUT_OF_MEMORY
, "glMapBufferSubDataCHROMIUM", "out of memory");
3647 std::pair
<MappedBufferMap::iterator
, bool> result
=
3648 mapped_buffers_
.insert(std::make_pair(
3651 access
, shm_id
, mem
, shm_offset
, target
, offset
, size
)));
3652 DCHECK(result
.second
);
3653 GPU_CLIENT_LOG(" returned " << mem
);
3657 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem
) {
3658 GPU_CLIENT_SINGLE_THREAD_CHECK();
3660 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem
<< ")");
3661 MappedBufferMap::iterator it
= mapped_buffers_
.find(mem
);
3662 if (it
== mapped_buffers_
.end()) {
3664 GL_INVALID_VALUE
, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
3667 const MappedBuffer
& mb
= it
->second
;
3668 helper_
->BufferSubData(
3669 mb
.target
, mb
.offset
, mb
.size
, mb
.shm_id
, mb
.shm_offset
);
3670 mapped_memory_
->FreePendingToken(mb
.shm_memory
, helper_
->InsertToken());
3671 mapped_buffers_
.erase(it
);
3675 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
3685 GPU_CLIENT_SINGLE_THREAD_CHECK();
3686 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
3687 << target
<< ", " << level
<< ", "
3688 << xoffset
<< ", " << yoffset
<< ", "
3689 << width
<< ", " << height
<< ", "
3690 << GLES2Util::GetStringTextureFormat(format
) << ", "
3691 << GLES2Util::GetStringPixelType(type
) << ", "
3692 << GLES2Util::GetStringEnum(access
) << ")");
3693 if (access
!= GL_WRITE_ONLY
) {
3694 SetGLErrorInvalidEnum(
3695 "glMapTexSubImage2DCHROMIUM", access
, "access");
3698 // NOTE: target is NOT checked because the service will check it
3699 // and we don't know what targets are valid.
3700 if (level
< 0 || xoffset
< 0 || yoffset
< 0 || width
< 0 || height
< 0) {
3702 GL_INVALID_VALUE
, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
3706 if (!GLES2Util::ComputeImageDataSizes(
3707 width
, height
, 1, format
, type
, unpack_alignment_
, &size
, NULL
, NULL
)) {
3709 GL_INVALID_VALUE
, "glMapTexSubImage2DCHROMIUM", "image size too large");
3713 unsigned int shm_offset
;
3714 void* mem
= mapped_memory_
->Alloc(size
, &shm_id
, &shm_offset
);
3716 SetGLError(GL_OUT_OF_MEMORY
, "glMapTexSubImage2DCHROMIUM", "out of memory");
3720 std::pair
<MappedTextureMap::iterator
, bool> result
=
3721 mapped_textures_
.insert(std::make_pair(
3724 access
, shm_id
, mem
, shm_offset
,
3725 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
)));
3726 DCHECK(result
.second
);
3727 GPU_CLIENT_LOG(" returned " << mem
);
3731 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem
) {
3732 GPU_CLIENT_SINGLE_THREAD_CHECK();
3734 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem
<< ")");
3735 MappedTextureMap::iterator it
= mapped_textures_
.find(mem
);
3736 if (it
== mapped_textures_
.end()) {
3738 GL_INVALID_VALUE
, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
3741 const MappedTexture
& mt
= it
->second
;
3742 helper_
->TexSubImage2D(
3743 mt
.target
, mt
.level
, mt
.xoffset
, mt
.yoffset
, mt
.width
, mt
.height
,
3744 mt
.format
, mt
.type
, mt
.shm_id
, mt
.shm_offset
, GL_FALSE
);
3745 mapped_memory_
->FreePendingToken(mt
.shm_memory
, helper_
->InsertToken());
3746 mapped_textures_
.erase(it
);
3750 void GLES2Implementation::ResizeCHROMIUM(GLuint width
, GLuint height
,
3751 float scale_factor
) {
3752 GPU_CLIENT_SINGLE_THREAD_CHECK();
3753 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
3754 << width
<< ", " << height
<< ", " << scale_factor
<< ")");
3755 helper_
->ResizeCHROMIUM(width
, height
, scale_factor
);
3759 const GLchar
* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
3760 GPU_CLIENT_SINGLE_THREAD_CHECK();
3761 GPU_CLIENT_LOG("[" << GetLogPrefix()
3762 << "] glGetRequestableExtensionsCHROMIUM()");
3764 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
3765 const char* result
= NULL
;
3766 // Clear the bucket so if the command fails nothing will be in it.
3767 helper_
->SetBucketSize(kResultBucketId
, 0);
3768 helper_
->GetRequestableExtensionsCHROMIUM(kResultBucketId
);
3770 if (GetBucketAsString(kResultBucketId
, &str
)) {
3771 // The set of requestable extensions shrinks as we enable
3772 // them. Because we don't know when the client will stop referring
3773 // to a previous one it queries (see GetString) we need to cache
3774 // the unique results.
3775 std::set
<std::string
>::const_iterator sit
=
3776 requestable_extensions_set_
.find(str
);
3777 if (sit
!= requestable_extensions_set_
.end()) {
3778 result
= sit
->c_str();
3780 std::pair
<std::set
<std::string
>::const_iterator
, bool> insert_result
=
3781 requestable_extensions_set_
.insert(str
);
3782 DCHECK(insert_result
.second
);
3783 result
= insert_result
.first
->c_str();
3786 GPU_CLIENT_LOG(" returned " << result
);
3787 return reinterpret_cast<const GLchar
*>(result
);
3790 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
3791 // with VirtualGL contexts.
3792 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension
) {
3793 GPU_CLIENT_SINGLE_THREAD_CHECK();
3794 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
3795 << extension
<< ")");
3796 SetBucketAsCString(kResultBucketId
, extension
);
3797 helper_
->RequestExtensionCHROMIUM(kResultBucketId
);
3798 helper_
->SetBucketSize(kResultBucketId
, 0);
3800 struct ExtensionCheck
{
3801 const char* extension
;
3802 ExtensionStatus
* status
;
3804 const ExtensionCheck checks
[] = {
3806 "GL_ANGLE_pack_reverse_row_order",
3807 &angle_pack_reverse_row_order_status_
,
3810 "GL_CHROMIUM_framebuffer_multisample",
3811 &chromium_framebuffer_multisample_
,
3814 const size_t kNumChecks
= sizeof(checks
)/sizeof(checks
[0]);
3815 for (size_t ii
= 0; ii
< kNumChecks
; ++ii
) {
3816 const ExtensionCheck
& check
= checks
[ii
];
3817 if (*check
.status
== kUnavailableExtensionStatus
&&
3818 !strcmp(extension
, check
.extension
)) {
3819 *check
.status
= kUnknownExtensionStatus
;
3824 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
3825 GPU_CLIENT_SINGLE_THREAD_CHECK();
3826 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
3827 // Wait if this would add too many rate limit tokens.
3828 if (rate_limit_tokens_
.size() == kMaxSwapBuffers
) {
3829 helper_
->WaitForToken(rate_limit_tokens_
.front());
3830 rate_limit_tokens_
.pop();
3832 rate_limit_tokens_
.push(helper_
->InsertToken());
3835 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3836 GLuint program
, std::vector
<int8
>* result
) {
3838 // Clear the bucket so if the command fails nothing will be in it.
3839 helper_
->SetBucketSize(kResultBucketId
, 0);
3840 helper_
->GetProgramInfoCHROMIUM(program
, kResultBucketId
);
3841 GetBucketContents(kResultBucketId
, result
);
3844 void GLES2Implementation::GetProgramInfoCHROMIUM(
3845 GLuint program
, GLsizei bufsize
, GLsizei
* size
, void* info
) {
3846 GPU_CLIENT_SINGLE_THREAD_CHECK();
3849 GL_INVALID_VALUE
, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3853 SetGLError(GL_INVALID_VALUE
, "glProgramInfoCHROMIUM", "size is null.");
3856 // Make sure they've set size to 0 else the value will be undefined on
3858 DCHECK_EQ(0, *size
);
3859 std::vector
<int8
> result
;
3860 GetProgramInfoCHROMIUMHelper(program
, &result
);
3861 if (result
.empty()) {
3864 *size
= result
.size();
3868 if (static_cast<size_t>(bufsize
) < result
.size()) {
3869 SetGLError(GL_INVALID_OPERATION
,
3870 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3873 memcpy(info
, &result
[0], result
.size());
3876 void GLES2Implementation::GetUniformBlocksCHROMIUMHelper(
3877 GLuint program
, std::vector
<int8
>* result
) {
3879 // Clear the bucket so if the command fails nothing will be in it.
3880 helper_
->SetBucketSize(kResultBucketId
, 0);
3881 helper_
->GetUniformBlocksCHROMIUM(program
, kResultBucketId
);
3882 GetBucketContents(kResultBucketId
, result
);
3885 void GLES2Implementation::GetUniformBlocksCHROMIUM(
3886 GLuint program
, GLsizei bufsize
, GLsizei
* size
, void* info
) {
3887 GPU_CLIENT_SINGLE_THREAD_CHECK();
3890 GL_INVALID_VALUE
, "glGetUniformBlocksCHROMIUM", "bufsize less than 0.");
3894 SetGLError(GL_INVALID_VALUE
, "glGetUniformBlocksCHROMIUM", "size is null.");
3897 // Make sure they've set size to 0 else the value will be undefined on
3899 DCHECK_EQ(0, *size
);
3900 std::vector
<int8
> result
;
3901 GetUniformBlocksCHROMIUMHelper(program
, &result
);
3902 if (result
.empty()) {
3905 *size
= result
.size();
3909 if (static_cast<size_t>(bufsize
) < result
.size()) {
3910 SetGLError(GL_INVALID_OPERATION
, "glGetUniformBlocksCHROMIUM",
3911 "bufsize is too small for result.");
3914 memcpy(info
, &result
[0], result
.size());
3917 void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
3918 GLuint program
, std::vector
<int8
>* result
) {
3920 // Clear the bucket so if the command fails nothing will be in it.
3921 helper_
->SetBucketSize(kResultBucketId
, 0);
3922 helper_
->GetUniformsES3CHROMIUM(program
, kResultBucketId
);
3923 GetBucketContents(kResultBucketId
, result
);
3926 void GLES2Implementation::GetUniformsES3CHROMIUM(
3927 GLuint program
, GLsizei bufsize
, GLsizei
* size
, void* info
) {
3928 GPU_CLIENT_SINGLE_THREAD_CHECK();
3931 GL_INVALID_VALUE
, "glGetUniformsES3CHROMIUM", "bufsize less than 0.");
3935 SetGLError(GL_INVALID_VALUE
, "glGetUniformsES3CHROMIUM", "size is null.");
3938 // Make sure they've set size to 0 else the value will be undefined on
3940 DCHECK_EQ(0, *size
);
3941 std::vector
<int8
> result
;
3942 GetUniformsES3CHROMIUMHelper(program
, &result
);
3943 if (result
.empty()) {
3946 *size
= result
.size();
3950 if (static_cast<size_t>(bufsize
) < result
.size()) {
3951 SetGLError(GL_INVALID_OPERATION
,
3952 "glGetUniformsES3CHROMIUM", "bufsize is too small for result.");
3955 memcpy(info
, &result
[0], result
.size());
3958 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
3959 GLuint program
, std::vector
<int8
>* result
) {
3961 // Clear the bucket so if the command fails nothing will be in it.
3962 helper_
->SetBucketSize(kResultBucketId
, 0);
3963 helper_
->GetTransformFeedbackVaryingsCHROMIUM(program
, kResultBucketId
);
3964 GetBucketContents(kResultBucketId
, result
);
3967 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(
3968 GLuint program
, GLsizei bufsize
, GLsizei
* size
, void* info
) {
3969 GPU_CLIENT_SINGLE_THREAD_CHECK();
3971 SetGLError(GL_INVALID_VALUE
, "glGetTransformFeedbackVaryingsCHROMIUM",
3972 "bufsize less than 0.");
3976 SetGLError(GL_INVALID_VALUE
, "glGetTransformFeedbackVaryingsCHROMIUM",
3980 // Make sure they've set size to 0 else the value will be undefined on
3982 DCHECK_EQ(0, *size
);
3983 std::vector
<int8
> result
;
3984 GetTransformFeedbackVaryingsCHROMIUMHelper(program
, &result
);
3985 if (result
.empty()) {
3988 *size
= result
.size();
3992 if (static_cast<size_t>(bufsize
) < result
.size()) {
3993 SetGLError(GL_INVALID_OPERATION
, "glGetTransformFeedbackVaryingsCHROMIUM",
3994 "bufsize is too small for result.");
3997 memcpy(info
, &result
[0], result
.size());
4000 GLuint
GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture
) {
4001 GPU_CLIENT_SINGLE_THREAD_CHECK();
4002 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
4004 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
4005 helper_
->CommandBufferHelper::Flush();
4006 return gpu_control_
->CreateStreamTexture(texture
);
4009 void GLES2Implementation::PostSubBufferCHROMIUM(
4010 GLint x
, GLint y
, GLint width
, GLint height
) {
4011 GPU_CLIENT_SINGLE_THREAD_CHECK();
4012 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
4013 << x
<< ", " << y
<< ", " << width
<< ", " << height
<< ")");
4014 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
4015 "width", width
, "height", height
);
4017 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
4018 swap_buffers_tokens_
.push(helper_
->InsertToken());
4019 helper_
->PostSubBufferCHROMIUM(x
, y
, width
, height
);
4020 helper_
->CommandBufferHelper::Flush();
4021 if (swap_buffers_tokens_
.size() > kMaxSwapBuffers
+ 1) {
4022 helper_
->WaitForToken(swap_buffers_tokens_
.front());
4023 swap_buffers_tokens_
.pop();
4027 void GLES2Implementation::DeleteQueriesEXTHelper(
4028 GLsizei n
, const GLuint
* queries
) {
4029 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
4030 query_tracker_
->RemoveQuery(queries
[ii
]);
4031 query_id_allocator_
->FreeID(queries
[ii
]);
4034 helper_
->DeleteQueriesEXTImmediate(n
, queries
);
4037 GLboolean
GLES2Implementation::IsQueryEXT(GLuint id
) {
4038 GPU_CLIENT_SINGLE_THREAD_CHECK();
4039 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id
<< ")");
4041 // TODO(gman): To be spec compliant IDs from other contexts sharing
4042 // resources need to return true here even though you can't share
4043 // queries across contexts?
4044 return query_tracker_
->GetQuery(id
) != NULL
;
4047 void GLES2Implementation::BeginQueryEXT(GLenum target
, GLuint id
) {
4048 GPU_CLIENT_SINGLE_THREAD_CHECK();
4049 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
4050 << GLES2Util::GetStringQueryTarget(target
)
4051 << ", " << id
<< ")");
4053 // if any outstanding queries INV_OP
4054 QueryMap::iterator it
= current_queries_
.find(target
);
4055 if (it
!= current_queries_
.end()) {
4057 GL_INVALID_OPERATION
, "glBeginQueryEXT", "query already in progress");
4063 SetGLError(GL_INVALID_OPERATION
, "glBeginQueryEXT", "id is 0");
4067 // if not GENned INV_OPERATION
4068 if (!query_id_allocator_
->InUse(id
)) {
4069 SetGLError(GL_INVALID_OPERATION
, "glBeginQueryEXT", "invalid id");
4073 // if id does not have an object
4074 QueryTracker::Query
* query
= query_tracker_
->GetQuery(id
);
4076 query
= query_tracker_
->CreateQuery(id
, target
);
4078 SetGLError(GL_OUT_OF_MEMORY
,
4080 "transfer buffer allocation failed");
4083 } else if (query
->target() != target
) {
4085 GL_INVALID_OPERATION
, "glBeginQueryEXT", "target does not match");
4089 current_queries_
[target
] = query
;
4095 void GLES2Implementation::EndQueryEXT(GLenum target
) {
4096 GPU_CLIENT_SINGLE_THREAD_CHECK();
4097 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
4098 << GLES2Util::GetStringQueryTarget(target
) << ")");
4099 // Don't do anything if the context is lost.
4100 if (helper_
->IsContextLost()) {
4104 QueryMap::iterator it
= current_queries_
.find(target
);
4105 if (it
== current_queries_
.end()) {
4106 SetGLError(GL_INVALID_OPERATION
, "glEndQueryEXT", "no active query");
4110 QueryTracker::Query
* query
= it
->second
;
4112 current_queries_
.erase(it
);
4116 void GLES2Implementation::GetQueryivEXT(
4117 GLenum target
, GLenum pname
, GLint
* params
) {
4118 GPU_CLIENT_SINGLE_THREAD_CHECK();
4119 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
4120 << GLES2Util::GetStringQueryTarget(target
) << ", "
4121 << GLES2Util::GetStringQueryParameter(pname
) << ", "
4122 << static_cast<const void*>(params
) << ")");
4124 if (pname
!= GL_CURRENT_QUERY_EXT
) {
4125 SetGLErrorInvalidEnum("glGetQueryivEXT", pname
, "pname");
4128 QueryMap::iterator it
= current_queries_
.find(target
);
4129 if (it
!= current_queries_
.end()) {
4130 QueryTracker::Query
* query
= it
->second
;
4131 *params
= query
->id();
4135 GPU_CLIENT_LOG(" " << *params
);
4139 void GLES2Implementation::GetQueryObjectuivEXT(
4140 GLuint id
, GLenum pname
, GLuint
* params
) {
4141 GPU_CLIENT_SINGLE_THREAD_CHECK();
4142 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id
<< ", "
4143 << GLES2Util::GetStringQueryObjectParameter(pname
) << ", "
4144 << static_cast<const void*>(params
) << ")");
4146 QueryTracker::Query
* query
= query_tracker_
->GetQuery(id
);
4148 SetGLError(GL_INVALID_OPERATION
, "glQueryObjectuivEXT", "unknown query id");
4152 QueryMap::iterator it
= current_queries_
.find(query
->target());
4153 if (it
!= current_queries_
.end()) {
4155 GL_INVALID_OPERATION
,
4156 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
4160 if (query
->NeverUsed()) {
4162 GL_INVALID_OPERATION
,
4163 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
4168 case GL_QUERY_RESULT_EXT
:
4169 if (!query
->CheckResultsAvailable(helper_
)) {
4170 helper_
->WaitForToken(query
->token());
4171 if (!query
->CheckResultsAvailable(helper_
)) {
4173 CHECK(query
->CheckResultsAvailable(helper_
));
4176 *params
= query
->GetResult();
4178 case GL_QUERY_RESULT_AVAILABLE_EXT
:
4179 *params
= query
->CheckResultsAvailable(helper_
);
4182 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname
, "pname");
4185 GPU_CLIENT_LOG(" " << *params
);
4189 void GLES2Implementation::DrawArraysInstancedANGLE(
4190 GLenum mode
, GLint first
, GLsizei count
, GLsizei primcount
) {
4191 GPU_CLIENT_SINGLE_THREAD_CHECK();
4192 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
4193 << GLES2Util::GetStringDrawMode(mode
) << ", "
4194 << first
<< ", " << count
<< ", " << primcount
<< ")");
4196 SetGLError(GL_INVALID_VALUE
, "glDrawArraysInstancedANGLE", "count < 0");
4199 if (primcount
< 0) {
4200 SetGLError(GL_INVALID_VALUE
, "glDrawArraysInstancedANGLE", "primcount < 0");
4203 if (primcount
== 0) {
4206 bool simulated
= false;
4207 if (!vertex_array_object_manager_
->SetupSimulatedClientSideBuffers(
4208 "glDrawArraysInstancedANGLE", this, helper_
, first
+ count
, primcount
,
4212 helper_
->DrawArraysInstancedANGLE(mode
, first
, count
, primcount
);
4213 RestoreArrayBuffer(simulated
);
4217 void GLES2Implementation::DrawElementsInstancedANGLE(
4218 GLenum mode
, GLsizei count
, GLenum type
, const void* indices
,
4219 GLsizei primcount
) {
4220 GPU_CLIENT_SINGLE_THREAD_CHECK();
4221 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
4222 << GLES2Util::GetStringDrawMode(mode
) << ", "
4224 << GLES2Util::GetStringIndexType(type
) << ", "
4225 << static_cast<const void*>(indices
) << ", "
4226 << primcount
<< ")");
4228 SetGLError(GL_INVALID_VALUE
,
4229 "glDrawElementsInstancedANGLE", "count less than 0.");
4235 if (primcount
< 0) {
4236 SetGLError(GL_INVALID_VALUE
,
4237 "glDrawElementsInstancedANGLE", "primcount < 0");
4240 if (primcount
== 0) {
4243 if (vertex_array_object_manager_
->bound_element_array_buffer() != 0 &&
4244 !ValidateOffset("glDrawElementsInstancedANGLE",
4245 reinterpret_cast<GLintptr
>(indices
))) {
4249 bool simulated
= false;
4250 if (!vertex_array_object_manager_
->SetupSimulatedIndexAndClientSideBuffers(
4251 "glDrawElementsInstancedANGLE", this, helper_
, count
, type
, primcount
,
4252 indices
, &offset
, &simulated
)) {
4255 helper_
->DrawElementsInstancedANGLE(mode
, count
, type
, offset
, primcount
);
4256 RestoreElementAndArrayBuffers(simulated
);
4260 void GLES2Implementation::GenMailboxCHROMIUM(
4262 GPU_CLIENT_SINGLE_THREAD_CHECK();
4263 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
4264 << static_cast<const void*>(mailbox
) << ")");
4265 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
4267 gpu::Mailbox result
= gpu::Mailbox::Generate();
4268 memcpy(mailbox
, result
.name
, sizeof(result
.name
));
4271 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target
,
4272 const GLbyte
* data
) {
4273 GPU_CLIENT_SINGLE_THREAD_CHECK();
4274 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
4275 << static_cast<const void*>(data
) << ")");
4276 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
4277 DCHECK(mailbox
.Verify()) << "ProduceTextureCHROMIUM was passed a "
4278 "mailbox that was not generated by "
4279 "GenMailboxCHROMIUM.";
4280 helper_
->ProduceTextureCHROMIUMImmediate(target
, data
);
4284 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
4285 GLuint texture
, GLenum target
, const GLbyte
* data
) {
4286 GPU_CLIENT_SINGLE_THREAD_CHECK();
4287 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
4288 << static_cast<const void*>(data
) << ")");
4289 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
4290 DCHECK(mailbox
.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
4291 "mailbox that was not generated by "
4292 "GenMailboxCHROMIUM.";
4293 helper_
->ProduceTextureDirectCHROMIUMImmediate(texture
, target
, data
);
4297 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target
,
4298 const GLbyte
* data
) {
4299 GPU_CLIENT_SINGLE_THREAD_CHECK();
4300 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
4301 << static_cast<const void*>(data
) << ")");
4302 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
4303 DCHECK(mailbox
.Verify()) << "ConsumeTextureCHROMIUM was passed a "
4304 "mailbox that was not generated by "
4305 "GenMailboxCHROMIUM.";
4306 helper_
->ConsumeTextureCHROMIUMImmediate(target
, data
);
4310 GLuint
GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
4311 GLenum target
, const GLbyte
* data
) {
4312 GPU_CLIENT_SINGLE_THREAD_CHECK();
4313 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
4314 << static_cast<const void*>(data
) << ")");
4315 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
4316 DCHECK(mailbox
.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
4317 "mailbox that was not generated by "
4318 "GenMailboxCHROMIUM.";
4320 GetIdHandler(id_namespaces::kTextures
)->MakeIds(this, 0, 1, &client_id
);
4321 helper_
->CreateAndConsumeTextureCHROMIUMImmediate(target
,
4323 if (share_group_
->bind_generates_resource())
4324 helper_
->CommandBufferHelper::Flush();
4329 void GLES2Implementation::PushGroupMarkerEXT(
4330 GLsizei length
, const GLchar
* marker
) {
4331 GPU_CLIENT_SINGLE_THREAD_CHECK();
4332 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
4333 << length
<< ", " << marker
<< ")");
4339 (length
? std::string(marker
, length
) : std::string(marker
)));
4340 helper_
->PushGroupMarkerEXT(kResultBucketId
);
4341 helper_
->SetBucketSize(kResultBucketId
, 0);
4342 debug_marker_manager_
.PushGroup(
4343 length
? std::string(marker
, length
) : std::string(marker
));
4346 void GLES2Implementation::InsertEventMarkerEXT(
4347 GLsizei length
, const GLchar
* marker
) {
4348 GPU_CLIENT_SINGLE_THREAD_CHECK();
4349 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
4350 << length
<< ", " << marker
<< ")");
4356 (length
? std::string(marker
, length
) : std::string(marker
)));
4357 helper_
->InsertEventMarkerEXT(kResultBucketId
);
4358 helper_
->SetBucketSize(kResultBucketId
, 0);
4359 debug_marker_manager_
.SetMarker(
4360 length
? std::string(marker
, length
) : std::string(marker
));
4363 void GLES2Implementation::PopGroupMarkerEXT() {
4364 GPU_CLIENT_SINGLE_THREAD_CHECK();
4365 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
4366 helper_
->PopGroupMarkerEXT();
4367 debug_marker_manager_
.PopGroup();
4370 void GLES2Implementation::TraceBeginCHROMIUM(
4371 const char* category_name
, const char* trace_name
) {
4372 GPU_CLIENT_SINGLE_THREAD_CHECK();
4373 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
4374 << category_name
<< ", " << trace_name
<< ")");
4375 SetBucketAsCString(kResultBucketId
, category_name
);
4376 SetBucketAsCString(kResultBucketId
+ 1, trace_name
);
4377 helper_
->TraceBeginCHROMIUM(kResultBucketId
, kResultBucketId
+ 1);
4378 helper_
->SetBucketSize(kResultBucketId
, 0);
4379 helper_
->SetBucketSize(kResultBucketId
+ 1, 0);
4380 current_trace_stack_
++;
4383 void GLES2Implementation::TraceEndCHROMIUM() {
4384 GPU_CLIENT_SINGLE_THREAD_CHECK();
4385 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
4386 if (current_trace_stack_
== 0) {
4387 SetGLError(GL_INVALID_OPERATION
, "glTraceEndCHROMIUM",
4388 "missing begin trace");
4391 helper_
->TraceEndCHROMIUM();
4392 current_trace_stack_
--;
4395 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target
, GLenum access
) {
4396 GPU_CLIENT_SINGLE_THREAD_CHECK();
4397 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
4398 << target
<< ", " << GLES2Util::GetStringEnum(access
) << ")");
4400 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
:
4401 if (access
!= GL_READ_ONLY
) {
4402 SetGLError(GL_INVALID_ENUM
, "glMapBufferCHROMIUM", "bad access mode");
4406 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
:
4407 if (access
!= GL_WRITE_ONLY
) {
4408 SetGLError(GL_INVALID_ENUM
, "glMapBufferCHROMIUM", "bad access mode");
4414 GL_INVALID_ENUM
, "glMapBufferCHROMIUM", "invalid target");
4418 GetBoundPixelTransferBuffer(target
, "glMapBufferCHROMIUM", &buffer_id
);
4422 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
4424 SetGLError(GL_INVALID_OPERATION
, "glMapBufferCHROMIUM", "invalid buffer");
4427 if (buffer
->mapped()) {
4428 SetGLError(GL_INVALID_OPERATION
, "glMapBufferCHROMIUM", "already mapped");
4431 // Here we wait for previous transfer operations to be finished.
4432 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
4433 // with this method of synchronization. Until this is fixed,
4434 // MapBufferCHROMIUM will not block even if the transfer is not ready
4436 if (buffer
->last_usage_token()) {
4437 helper_
->WaitForToken(buffer
->last_usage_token());
4438 buffer
->set_last_usage_token(0);
4440 buffer
->set_mapped(true);
4442 GPU_CLIENT_LOG(" returned " << buffer
->address());
4444 return buffer
->address();
4447 GLboolean
GLES2Implementation::UnmapBufferCHROMIUM(GLuint target
) {
4448 GPU_CLIENT_SINGLE_THREAD_CHECK();
4450 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target
<< ")");
4452 if (!GetBoundPixelTransferBuffer(target
, "glMapBufferCHROMIUM", &buffer_id
)) {
4453 SetGLError(GL_INVALID_ENUM
, "glUnmapBufferCHROMIUM", "invalid target");
4458 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
4460 SetGLError(GL_INVALID_OPERATION
, "glUnmapBufferCHROMIUM", "invalid buffer");
4463 if (!buffer
->mapped()) {
4464 SetGLError(GL_INVALID_OPERATION
, "glUnmapBufferCHROMIUM", "not mapped");
4467 buffer
->set_mapped(false);
4472 bool GLES2Implementation::EnsureAsyncUploadSync() {
4473 if (async_upload_sync_
)
4477 unsigned int shm_offset
;
4478 void* mem
= mapped_memory_
->Alloc(sizeof(AsyncUploadSync
),
4484 async_upload_sync_shm_id_
= shm_id
;
4485 async_upload_sync_shm_offset_
= shm_offset
;
4486 async_upload_sync_
= static_cast<AsyncUploadSync
*>(mem
);
4487 async_upload_sync_
->Reset();
4492 uint32
GLES2Implementation::NextAsyncUploadToken() {
4493 async_upload_token_
++;
4494 if (async_upload_token_
== 0)
4495 async_upload_token_
++;
4496 return async_upload_token_
;
4499 void GLES2Implementation::PollAsyncUploads() {
4500 if (!async_upload_sync_
)
4503 if (helper_
->IsContextLost()) {
4504 DetachedAsyncUploadMemoryList::iterator it
=
4505 detached_async_upload_memory_
.begin();
4506 while (it
!= detached_async_upload_memory_
.end()) {
4507 mapped_memory_
->Free(it
->first
);
4508 it
= detached_async_upload_memory_
.erase(it
);
4513 DetachedAsyncUploadMemoryList::iterator it
=
4514 detached_async_upload_memory_
.begin();
4515 while (it
!= detached_async_upload_memory_
.end()) {
4516 if (HasAsyncUploadTokenPassed(it
->second
)) {
4517 mapped_memory_
->Free(it
->first
);
4518 it
= detached_async_upload_memory_
.erase(it
);
4525 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
4526 // Free all completed unmanaged async uploads buffers.
4529 // Synchronously free rest of the unmanaged async upload buffers.
4530 if (!detached_async_upload_memory_
.empty()) {
4531 WaitAllAsyncTexImage2DCHROMIUM();
4537 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
4538 GLenum target
, GLint level
, GLenum internalformat
, GLsizei width
,
4539 GLsizei height
, GLint border
, GLenum format
, GLenum type
,
4540 const void* pixels
) {
4541 GPU_CLIENT_SINGLE_THREAD_CHECK();
4542 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
4543 << GLES2Util::GetStringTextureTarget(target
) << ", "
4545 << GLES2Util::GetStringTextureInternalFormat(internalformat
) << ", "
4546 << width
<< ", " << height
<< ", " << border
<< ", "
4547 << GLES2Util::GetStringTextureFormat(format
) << ", "
4548 << GLES2Util::GetStringPixelType(type
) << ", "
4549 << static_cast<const void*>(pixels
) << ")");
4550 if (level
< 0 || height
< 0 || width
< 0) {
4551 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "dimension < 0");
4555 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "border != 0");
4559 uint32 unpadded_row_size
;
4560 uint32 padded_row_size
;
4561 if (!GLES2Util::ComputeImageDataSizes(
4562 width
, height
, 1, format
, type
, unpack_alignment_
, &size
,
4563 &unpadded_row_size
, &padded_row_size
)) {
4564 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "image size too large");
4568 // If there's no data/buffer just issue the AsyncTexImage2D
4569 if (!pixels
&& !bound_pixel_unpack_transfer_buffer_id_
) {
4570 helper_
->AsyncTexImage2DCHROMIUM(
4571 target
, level
, internalformat
, width
, height
, format
, type
,
4576 if (!EnsureAsyncUploadSync()) {
4577 SetGLError(GL_OUT_OF_MEMORY
, "glTexImage2D", "out of memory");
4581 // Otherwise, async uploads require a transfer buffer to be bound.
4582 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
4583 // the buffer before the transfer is finished. (Currently such
4584 // synchronization has to be handled manually.)
4585 GLuint offset
= ToGLuint(pixels
);
4586 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
4587 bound_pixel_unpack_transfer_buffer_id_
,
4588 "glAsyncTexImage2DCHROMIUM", offset
, size
);
4589 if (buffer
&& buffer
->shm_id() != -1) {
4590 uint32 async_token
= NextAsyncUploadToken();
4591 buffer
->set_last_async_upload_token(async_token
);
4592 helper_
->AsyncTexImage2DCHROMIUM(
4593 target
, level
, internalformat
, width
, height
, format
, type
,
4594 buffer
->shm_id(), buffer
->shm_offset() + offset
,
4596 async_upload_sync_shm_id_
, async_upload_sync_shm_offset_
);
4600 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
4601 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
4602 GLsizei height
, GLenum format
, GLenum type
, const void* pixels
) {
4603 GPU_CLIENT_SINGLE_THREAD_CHECK();
4604 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
4605 << GLES2Util::GetStringTextureTarget(target
) << ", "
4607 << xoffset
<< ", " << yoffset
<< ", "
4608 << width
<< ", " << height
<< ", "
4609 << GLES2Util::GetStringTextureFormat(format
) << ", "
4610 << GLES2Util::GetStringPixelType(type
) << ", "
4611 << static_cast<const void*>(pixels
) << ")");
4612 if (level
< 0 || height
< 0 || width
< 0) {
4614 GL_INVALID_VALUE
, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
4619 uint32 unpadded_row_size
;
4620 uint32 padded_row_size
;
4621 if (!GLES2Util::ComputeImageDataSizes(
4622 width
, height
, 1, format
, type
, unpack_alignment_
, &size
,
4623 &unpadded_row_size
, &padded_row_size
)) {
4625 GL_INVALID_VALUE
, "glAsyncTexSubImage2DCHROMIUM", "size to large");
4629 if (!EnsureAsyncUploadSync()) {
4630 SetGLError(GL_OUT_OF_MEMORY
, "glTexImage2D", "out of memory");
4634 // Async uploads require a transfer buffer to be bound.
4635 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
4636 // the buffer before the transfer is finished. (Currently such
4637 // synchronization has to be handled manually.)
4638 GLuint offset
= ToGLuint(pixels
);
4639 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
4640 bound_pixel_unpack_transfer_buffer_id_
,
4641 "glAsyncTexSubImage2DCHROMIUM", offset
, size
);
4642 if (buffer
&& buffer
->shm_id() != -1) {
4643 uint32 async_token
= NextAsyncUploadToken();
4644 buffer
->set_last_async_upload_token(async_token
);
4645 helper_
->AsyncTexSubImage2DCHROMIUM(
4646 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
,
4647 buffer
->shm_id(), buffer
->shm_offset() + offset
,
4649 async_upload_sync_shm_id_
, async_upload_sync_shm_offset_
);
4653 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target
) {
4654 GPU_CLIENT_SINGLE_THREAD_CHECK();
4655 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
4656 << GLES2Util::GetStringTextureTarget(target
) << ")");
4657 helper_
->WaitAsyncTexImage2DCHROMIUM(target
);
4661 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
4662 GPU_CLIENT_SINGLE_THREAD_CHECK();
4663 GPU_CLIENT_LOG("[" << GetLogPrefix()
4664 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
4665 helper_
->WaitAllAsyncTexImage2DCHROMIUM();
4669 GLuint
GLES2Implementation::InsertSyncPointCHROMIUM() {
4670 GPU_CLIENT_SINGLE_THREAD_CHECK();
4671 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
4672 helper_
->CommandBufferHelper::Flush();
4673 return gpu_control_
->InsertSyncPoint();
4676 GLuint
GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
4677 GPU_CLIENT_SINGLE_THREAD_CHECK();
4678 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
4679 DCHECK(capabilities_
.future_sync_points
);
4680 return gpu_control_
->InsertFutureSyncPoint();
4683 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point
) {
4684 GPU_CLIENT_SINGLE_THREAD_CHECK();
4685 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
4686 << sync_point
<< ")");
4687 DCHECK(capabilities_
.future_sync_points
);
4688 helper_
->CommandBufferHelper::Flush();
4689 gpu_control_
->RetireSyncPoint(sync_point
);
4694 bool ValidImageFormat(GLenum internalformat
) {
4695 switch (internalformat
) {
4704 bool ValidImageUsage(GLenum usage
) {
4706 case GL_MAP_CHROMIUM
:
4707 case GL_SCANOUT_CHROMIUM
:
4716 GLuint
GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer
,
4719 GLenum internalformat
) {
4721 SetGLError(GL_INVALID_VALUE
, "glCreateImageCHROMIUM", "width <= 0");
4726 SetGLError(GL_INVALID_VALUE
, "glCreateImageCHROMIUM", "height <= 0");
4730 if (!ValidImageFormat(internalformat
)) {
4731 SetGLError(GL_INVALID_VALUE
, "glCreateImageCHROMIUM", "invalid format");
4736 gpu_control_
->CreateImage(buffer
, width
, height
, internalformat
);
4738 SetGLError(GL_OUT_OF_MEMORY
, "glCreateImageCHROMIUM", "image_id < 0");
4744 GLuint
GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer
,
4747 GLenum internalformat
) {
4748 GPU_CLIENT_SINGLE_THREAD_CHECK();
4749 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
4750 << ", " << height
<< ", "
4751 << GLES2Util::GetStringImageInternalFormat(internalformat
)
4754 CreateImageCHROMIUMHelper(buffer
, width
, height
, internalformat
);
4759 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id
) {
4760 // Flush the command stream to make sure all pending commands
4761 // that may refer to the image_id are executed on the service side.
4762 helper_
->CommandBufferHelper::Flush();
4763 gpu_control_
->DestroyImage(image_id
);
4766 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id
) {
4767 GPU_CLIENT_SINGLE_THREAD_CHECK();
4768 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
4769 << image_id
<< ")");
4770 DestroyImageCHROMIUMHelper(image_id
);
4774 GLuint
GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
4777 GLenum internalformat
,
4781 GL_INVALID_VALUE
, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
4786 SetGLError(GL_INVALID_VALUE
,
4787 "glCreateGpuMemoryBufferImageCHROMIUM",
4792 if (!ValidImageFormat(internalformat
)) {
4793 SetGLError(GL_INVALID_VALUE
,
4794 "glCreateGpuMemoryBufferImageCHROMIUM",
4799 if (!ValidImageUsage(usage
)) {
4800 SetGLError(GL_INVALID_VALUE
,
4801 "glCreateGpuMemoryBufferImageCHROMIUM",
4806 // Flush the command stream to ensure ordering in case the newly
4807 // returned image_id has recently been in use with a different buffer.
4808 helper_
->CommandBufferHelper::Flush();
4809 int32_t image_id
= gpu_control_
->CreateGpuMemoryBufferImage(
4810 width
, height
, internalformat
, usage
);
4812 SetGLError(GL_OUT_OF_MEMORY
,
4813 "glCreateGpuMemoryBufferImageCHROMIUM",
4820 GLuint
GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
4823 GLenum internalformat
,
4825 GPU_CLIENT_SINGLE_THREAD_CHECK();
4826 GPU_CLIENT_LOG("[" << GetLogPrefix()
4827 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
4828 << ", " << height
<< ", "
4829 << GLES2Util::GetStringImageInternalFormat(internalformat
)
4830 << ", " << GLES2Util::GetStringImageUsage(usage
) << ")");
4831 GLuint image_id
= CreateGpuMemoryBufferImageCHROMIUMHelper(
4832 width
, height
, internalformat
, usage
);
4837 bool GLES2Implementation::ValidateSize(const char* func
, GLsizeiptr size
) {
4839 SetGLError(GL_INVALID_VALUE
, func
, "size < 0");
4842 if (!FitInt32NonNegative
<GLsizeiptr
>(size
)) {
4843 SetGLError(GL_INVALID_OPERATION
, func
, "size more than 32-bit");
4849 bool GLES2Implementation::ValidateOffset(const char* func
, GLintptr offset
) {
4851 SetGLError(GL_INVALID_VALUE
, func
, "offset < 0");
4854 if (!FitInt32NonNegative
<GLintptr
>(offset
)) {
4855 SetGLError(GL_INVALID_OPERATION
, func
, "offset more than 32-bit");
4861 bool GLES2Implementation::GetSamplerParameterfvHelper(
4862 GLuint
/* sampler */, GLenum
/* pname */, GLfloat
* /* params */) {
4863 // TODO(zmo): Implement client side caching.
4867 bool GLES2Implementation::GetSamplerParameterivHelper(
4868 GLuint
/* sampler */, GLenum
/* pname */, GLint
* /* params */) {
4869 // TODO(zmo): Implement client side caching.
4873 bool GLES2Implementation::PackStringsToBucket(GLsizei count
,
4874 const char* const* str
,
4875 const GLint
* length
,
4876 const char* func_name
) {
4877 DCHECK_LE(0, count
);
4878 // Compute the total size.
4879 base::CheckedNumeric
<size_t> total_size
= count
;
4881 total_size
*= sizeof(GLint
);
4882 if (!total_size
.IsValid()) {
4883 SetGLError(GL_INVALID_VALUE
, func_name
, "overflow");
4886 size_t header_size
= total_size
.ValueOrDefault(0);
4887 std::vector
<GLint
> header(count
+ 1);
4888 header
[0] = static_cast<GLint
>(count
);
4889 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
4892 len
= (length
&& length
[ii
] >= 0)
4894 : base::checked_cast
<GLint
>(strlen(str
[ii
]));
4897 total_size
+= 1; // NULL at the end of each char array.
4898 if (!total_size
.IsValid()) {
4899 SetGLError(GL_INVALID_VALUE
, func_name
, "overflow");
4902 header
[ii
+ 1] = len
;
4904 // Pack data into a bucket on the service.
4905 helper_
->SetBucketSize(kResultBucketId
, total_size
.ValueOrDefault(0));
4907 for (GLsizei ii
= 0; ii
<= count
; ++ii
) {
4909 (ii
== 0) ? reinterpret_cast<const char*>(&header
[0]) : str
[ii
- 1];
4910 base::CheckedNumeric
<size_t> checked_size
=
4911 (ii
== 0) ? header_size
: static_cast<size_t>(header
[ii
]);
4913 checked_size
+= 1; // NULL in the end.
4915 if (!checked_size
.IsValid()) {
4916 SetGLError(GL_INVALID_VALUE
, func_name
, "overflow");
4919 size_t size
= checked_size
.ValueOrDefault(0);
4921 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
4922 if (!buffer
.valid() || buffer
.size() == 0) {
4923 SetGLError(GL_OUT_OF_MEMORY
, func_name
, "too large");
4926 size_t copy_size
= buffer
.size();
4927 if (ii
> 0 && buffer
.size() == size
)
4930 memcpy(buffer
.address(), src
, copy_size
);
4931 if (copy_size
< buffer
.size()) {
4932 // Append NULL in the end.
4933 DCHECK(copy_size
+ 1 == buffer
.size());
4934 char* str
= reinterpret_cast<char*>(buffer
.address());
4937 helper_
->SetBucketData(kResultBucketId
, offset
, buffer
.size(),
4938 buffer
.shm_id(), buffer
.offset());
4939 offset
+= buffer
.size();
4940 src
+= buffer
.size();
4941 size
-= buffer
.size();
4944 DCHECK_EQ(total_size
.ValueOrDefault(0), offset
);
4948 void GLES2Implementation::UniformBlockBinding(GLuint program
,
4951 GPU_CLIENT_SINGLE_THREAD_CHECK();
4952 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
4953 << ", " << index
<< ", " << binding
<< ")");
4954 share_group_
->program_info_manager()->UniformBlockBinding(
4955 this, program
, index
, binding
);
4956 helper_
->UniformBlockBinding(program
, index
, binding
);
4960 GLenum
GLES2Implementation::ClientWaitSync(
4961 GLsync sync
, GLbitfield flags
, GLuint64 timeout
) {
4962 GPU_CLIENT_SINGLE_THREAD_CHECK();
4963 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync
4964 << ", " << flags
<< ", " << timeout
<< ")");
4965 typedef cmds::ClientWaitSync::Result Result
;
4966 Result
* result
= GetResultAs
<Result
*>();
4968 SetGLError(GL_OUT_OF_MEMORY
, "ClientWaitSync", "");
4969 return GL_WAIT_FAILED
;
4971 *result
= GL_WAIT_FAILED
;
4972 uint32_t v32_0
= 0, v32_1
= 0;
4973 GLES2Util::MapUint64ToTwoUint32(timeout
, &v32_0
, &v32_1
);
4974 helper_
->ClientWaitSync(
4975 ToGLuint(sync
), flags
, v32_0
, v32_1
,
4976 GetResultShmId(), GetResultShmOffset());
4978 GPU_CLIENT_LOG("returned " << *result
);
4983 void GLES2Implementation::WaitSync(
4984 GLsync sync
, GLbitfield flags
, GLuint64 timeout
) {
4985 GPU_CLIENT_SINGLE_THREAD_CHECK();
4986 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync
<< ", "
4987 << flags
<< ", " << timeout
<< ")");
4988 uint32_t v32_0
= 0, v32_1
= 0;
4989 GLES2Util::MapUint64ToTwoUint32(timeout
, &v32_0
, &v32_1
);
4990 helper_
->WaitSync(ToGLuint(sync
), flags
, v32_0
, v32_1
);
4994 // Include the auto-generated part of this file. We split this because it means
4995 // we can easily edit the non-auto generated parts right here in this file
4996 // instead of having to edit some template or the code generator.
4997 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
4999 } // namespace gles2