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 GLuint
GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
751 GLuint buffer_id
, GLsizei count
, GLenum type
, GLuint offset
) {
752 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result
;
753 Result
* result
= GetResultAs
<Result
*>();
758 helper_
->GetMaxValueInBufferCHROMIUM(
759 buffer_id
, count
, type
, offset
, GetResultShmId(), GetResultShmOffset());
764 GLuint
GLES2Implementation::GetMaxValueInBufferCHROMIUM(
765 GLuint buffer_id
, GLsizei count
, GLenum type
, GLuint offset
) {
766 GPU_CLIENT_SINGLE_THREAD_CHECK();
767 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
768 << buffer_id
<< ", " << count
<< ", "
769 << GLES2Util::GetStringGetMaxIndexType(type
)
770 << ", " << offset
<< ")");
771 GLuint result
= GetMaxValueInBufferCHROMIUMHelper(
772 buffer_id
, count
, type
, offset
);
773 GPU_CLIENT_LOG("returned " << result
);
778 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore
) {
780 RestoreArrayBuffer(restore
);
781 // Restore the element array binding.
782 // We only need to restore it if it wasn't a client side array.
783 if (vertex_array_object_manager_
->bound_element_array_buffer() == 0) {
784 helper_
->BindBuffer(GL_ELEMENT_ARRAY_BUFFER
, 0);
789 void GLES2Implementation::RestoreArrayBuffer(bool restore
) {
791 // Restore the user's current binding.
792 helper_
->BindBuffer(GL_ARRAY_BUFFER
, bound_array_buffer_id_
);
796 void GLES2Implementation::DrawElements(
797 GLenum mode
, GLsizei count
, GLenum type
, const void* indices
) {
798 GPU_CLIENT_SINGLE_THREAD_CHECK();
799 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
800 << GLES2Util::GetStringDrawMode(mode
) << ", "
802 << GLES2Util::GetStringIndexType(type
) << ", "
803 << static_cast<const void*>(indices
) << ")");
805 SetGLError(GL_INVALID_VALUE
, "glDrawElements", "count less than 0.");
811 if (vertex_array_object_manager_
->bound_element_array_buffer() != 0 &&
812 !ValidateOffset("glDrawElements", reinterpret_cast<GLintptr
>(indices
))) {
816 bool simulated
= false;
817 if (!vertex_array_object_manager_
->SetupSimulatedIndexAndClientSideBuffers(
818 "glDrawElements", this, helper_
, count
, type
, 0, indices
,
819 &offset
, &simulated
)) {
822 helper_
->DrawElements(mode
, count
, type
, offset
);
823 RestoreElementAndArrayBuffers(simulated
);
827 void GLES2Implementation::Flush() {
828 GPU_CLIENT_SINGLE_THREAD_CHECK();
829 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
830 // Insert the cmd to call glFlush
832 // Flush our command buffer
833 // (tell the service to execute up to the flush cmd.)
834 helper_
->CommandBufferHelper::Flush();
837 void GLES2Implementation::ShallowFlushCHROMIUM() {
838 GPU_CLIENT_SINGLE_THREAD_CHECK();
839 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
840 // Flush our command buffer
841 // (tell the service to execute up to the flush cmd.)
842 helper_
->CommandBufferHelper::Flush();
843 // TODO(piman): Add the FreeEverything() logic here.
846 void GLES2Implementation::OrderingBarrierCHROMIUM() {
847 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOrderingBarrierCHROMIUM");
848 // Flush command buffer at the GPU channel level. May be implemented as
850 helper_
->CommandBufferHelper::OrderingBarrier();
853 void GLES2Implementation::Finish() {
854 GPU_CLIENT_SINGLE_THREAD_CHECK();
858 void GLES2Implementation::ShallowFinishCHROMIUM() {
859 GPU_CLIENT_SINGLE_THREAD_CHECK();
860 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
861 // Flush our command buffer (tell the service to execute up to the flush cmd
862 // and don't return until it completes).
863 helper_
->CommandBufferHelper::Finish();
866 void GLES2Implementation::FinishHelper() {
867 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
868 TRACE_EVENT0("gpu", "GLES2::Finish");
869 // Insert the cmd to call glFinish
871 // Finish our command buffer
872 // (tell the service to execute up to the Finish cmd and wait for it to
874 helper_
->CommandBufferHelper::Finish();
877 void GLES2Implementation::SwapBuffers() {
878 GPU_CLIENT_SINGLE_THREAD_CHECK();
879 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
880 // TODO(piman): Strictly speaking we'd want to insert the token after the
881 // swap, but the state update with the updated token might not have happened
882 // by the time the SwapBuffer callback gets called, forcing us to synchronize
883 // with the GPU process more than needed. So instead, make it happen before.
884 // All it means is that we could be slightly looser on the kMaxSwapBuffers
885 // semantics if the client doesn't use the callback mechanism, and by chance
886 // the scheduler yields between the InsertToken and the SwapBuffers.
887 swap_buffers_tokens_
.push(helper_
->InsertToken());
888 helper_
->SwapBuffers();
889 helper_
->CommandBufferHelper::Flush();
890 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
891 // compensate for TODO above.
892 if (swap_buffers_tokens_
.size() > kMaxSwapBuffers
+ 1) {
893 helper_
->WaitForToken(swap_buffers_tokens_
.front());
894 swap_buffers_tokens_
.pop();
898 void GLES2Implementation::SwapInterval(int interval
) {
899 GPU_CLIENT_SINGLE_THREAD_CHECK();
900 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapInterval("
902 helper_
->SwapInterval(interval
);
905 void GLES2Implementation::BindAttribLocation(
906 GLuint program
, GLuint index
, const char* name
) {
907 GPU_CLIENT_SINGLE_THREAD_CHECK();
908 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
909 << program
<< ", " << index
<< ", " << name
<< ")");
910 SetBucketAsString(kResultBucketId
, name
);
911 helper_
->BindAttribLocationBucket(program
, index
, kResultBucketId
);
912 helper_
->SetBucketSize(kResultBucketId
, 0);
916 void GLES2Implementation::BindUniformLocationCHROMIUM(
917 GLuint program
, GLint location
, const char* name
) {
918 GPU_CLIENT_SINGLE_THREAD_CHECK();
919 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
920 << program
<< ", " << location
<< ", " << name
<< ")");
921 SetBucketAsString(kResultBucketId
, name
);
922 helper_
->BindUniformLocationCHROMIUMBucket(
923 program
, location
, kResultBucketId
);
924 helper_
->SetBucketSize(kResultBucketId
, 0);
928 void GLES2Implementation::GetVertexAttribPointerv(
929 GLuint index
, GLenum pname
, void** ptr
) {
930 GPU_CLIENT_SINGLE_THREAD_CHECK();
931 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
932 << index
<< ", " << GLES2Util::GetStringVertexPointer(pname
) << ", "
933 << static_cast<void*>(ptr
) << ")");
934 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results
= 1);
935 if (!vertex_array_object_manager_
->GetAttribPointer(index
, pname
, ptr
)) {
936 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
937 typedef cmds::GetVertexAttribPointerv::Result Result
;
938 Result
* result
= GetResultAs
<Result
*>();
942 result
->SetNumResults(0);
943 helper_
->GetVertexAttribPointerv(
944 index
, pname
, GetResultShmId(), GetResultShmOffset());
946 result
->CopyResult(ptr
);
947 GPU_CLIENT_LOG_CODE_BLOCK(num_results
= result
->GetNumResults());
949 GPU_CLIENT_LOG_CODE_BLOCK({
950 for (int32 i
= 0; i
< num_results
; ++i
) {
951 GPU_CLIENT_LOG(" " << i
<< ": " << ptr
[i
]);
957 bool GLES2Implementation::DeleteProgramHelper(GLuint program
) {
958 if (!GetIdHandler(id_namespaces::kProgramsAndShaders
)->FreeIds(
959 this, 1, &program
, &GLES2Implementation::DeleteProgramStub
)) {
962 "glDeleteProgram", "id not created by this context.");
965 if (program
== current_program_
) {
966 current_program_
= 0;
971 void GLES2Implementation::DeleteProgramStub(
972 GLsizei n
, const GLuint
* programs
) {
974 share_group_
->program_info_manager()->DeleteInfo(programs
[0]);
975 helper_
->DeleteProgram(programs
[0]);
978 bool GLES2Implementation::DeleteShaderHelper(GLuint shader
) {
979 if (!GetIdHandler(id_namespaces::kProgramsAndShaders
)->FreeIds(
980 this, 1, &shader
, &GLES2Implementation::DeleteShaderStub
)) {
983 "glDeleteShader", "id not created by this context.");
989 void GLES2Implementation::DeleteShaderStub(
990 GLsizei n
, const GLuint
* shaders
) {
992 share_group_
->program_info_manager()->DeleteInfo(shaders
[0]);
993 helper_
->DeleteShader(shaders
[0]);
996 void GLES2Implementation::DeleteSyncHelper(GLsync sync
) {
997 GLuint sync_uint
= ToGLuint(sync
);
998 if (!GetIdHandler(id_namespaces::kSyncs
)->FreeIds(
999 this, 1, &sync_uint
, &GLES2Implementation::DeleteSyncStub
)) {
1002 "glDeleteSync", "id not created by this context.");
1006 void GLES2Implementation::DeleteSyncStub(GLsizei n
, const GLuint
* syncs
) {
1008 helper_
->DeleteSync(syncs
[0]);
1011 GLint
GLES2Implementation::GetAttribLocationHelper(
1012 GLuint program
, const char* name
) {
1013 typedef cmds::GetAttribLocation::Result Result
;
1014 Result
* result
= GetResultAs
<Result
*>();
1019 SetBucketAsCString(kResultBucketId
, name
);
1020 helper_
->GetAttribLocation(
1021 program
, kResultBucketId
, GetResultShmId(), GetResultShmOffset());
1023 helper_
->SetBucketSize(kResultBucketId
, 0);
1027 GLint
GLES2Implementation::GetAttribLocation(
1028 GLuint program
, const char* name
) {
1029 GPU_CLIENT_SINGLE_THREAD_CHECK();
1030 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1031 << ", " << name
<< ")");
1032 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1033 GLint loc
= share_group_
->program_info_manager()->GetAttribLocation(
1034 this, program
, name
);
1035 GPU_CLIENT_LOG("returned " << loc
);
1040 GLint
GLES2Implementation::GetUniformLocationHelper(
1041 GLuint program
, const char* name
) {
1042 typedef cmds::GetUniformLocation::Result Result
;
1043 Result
* result
= GetResultAs
<Result
*>();
1048 SetBucketAsCString(kResultBucketId
, name
);
1049 helper_
->GetUniformLocation(program
, kResultBucketId
,
1050 GetResultShmId(), GetResultShmOffset());
1052 helper_
->SetBucketSize(kResultBucketId
, 0);
1056 GLint
GLES2Implementation::GetUniformLocation(
1057 GLuint program
, const char* name
) {
1058 GPU_CLIENT_SINGLE_THREAD_CHECK();
1059 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1060 << ", " << name
<< ")");
1061 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1062 GLint loc
= share_group_
->program_info_manager()->GetUniformLocation(
1063 this, program
, name
);
1064 GPU_CLIENT_LOG("returned " << loc
);
1069 bool GLES2Implementation::GetUniformIndicesHelper(
1070 GLuint program
, GLsizei count
, const char* const* names
, GLuint
* indices
) {
1071 typedef cmds::GetUniformIndices::Result Result
;
1072 Result
* result
= GetResultAs
<Result
*>();
1076 result
->SetNumResults(0);
1077 if (!PackStringsToBucket(count
, names
, NULL
, "glGetUniformIndices")) {
1080 helper_
->GetUniformIndices(program
, kResultBucketId
,
1081 GetResultShmId(), GetResultShmOffset());
1083 if (result
->GetNumResults() != count
) {
1086 result
->CopyResult(indices
);
1090 void GLES2Implementation::GetUniformIndices(
1091 GLuint program
, GLsizei count
, const char* const* names
, GLuint
* indices
) {
1092 GPU_CLIENT_SINGLE_THREAD_CHECK();
1093 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
1094 << ", " << count
<< ", " << names
<< ", " << indices
<< ")");
1095 TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
1097 SetGLError(GL_INVALID_VALUE
, "glGetUniformIndices", "count < 0");
1103 bool success
= share_group_
->program_info_manager()->GetUniformIndices(
1104 this, program
, count
, names
, indices
);
1106 GPU_CLIENT_LOG_CODE_BLOCK({
1107 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1108 GPU_CLIENT_LOG(" " << ii
<< ": " << indices
[ii
]);
1115 bool GLES2Implementation::GetProgramivHelper(
1116 GLuint program
, GLenum pname
, GLint
* params
) {
1117 bool got_value
= share_group_
->program_info_manager()->GetProgramiv(
1118 this, program
, pname
, params
);
1119 GPU_CLIENT_LOG_CODE_BLOCK({
1121 GPU_CLIENT_LOG(" 0: " << *params
);
1127 GLint
GLES2Implementation::GetFragDataLocationHelper(
1128 GLuint program
, const char* name
) {
1129 typedef cmds::GetFragDataLocation::Result Result
;
1130 Result
* result
= GetResultAs
<Result
*>();
1135 SetBucketAsCString(kResultBucketId
, name
);
1136 helper_
->GetFragDataLocation(
1137 program
, kResultBucketId
, GetResultShmId(), GetResultShmOffset());
1139 helper_
->SetBucketSize(kResultBucketId
, 0);
1143 GLint
GLES2Implementation::GetFragDataLocation(
1144 GLuint program
, const char* name
) {
1145 GPU_CLIENT_SINGLE_THREAD_CHECK();
1146 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataLocation("
1147 << program
<< ", " << name
<< ")");
1148 TRACE_EVENT0("gpu", "GLES2::GetFragDataLocation");
1149 GLint loc
= share_group_
->program_info_manager()->GetFragDataLocation(
1150 this, program
, name
);
1151 GPU_CLIENT_LOG("returned " << loc
);
1156 GLuint
GLES2Implementation::GetUniformBlockIndexHelper(
1157 GLuint program
, const char* name
) {
1158 typedef cmds::GetUniformBlockIndex::Result Result
;
1159 Result
* result
= GetResultAs
<Result
*>();
1161 return GL_INVALID_INDEX
;
1163 *result
= GL_INVALID_INDEX
;
1164 SetBucketAsCString(kResultBucketId
, name
);
1165 helper_
->GetUniformBlockIndex(
1166 program
, kResultBucketId
, GetResultShmId(), GetResultShmOffset());
1168 helper_
->SetBucketSize(kResultBucketId
, 0);
1172 GLuint
GLES2Implementation::GetUniformBlockIndex(
1173 GLuint program
, const char* name
) {
1174 GPU_CLIENT_SINGLE_THREAD_CHECK();
1175 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformBlockIndex("
1176 << program
<< ", " << name
<< ")");
1177 TRACE_EVENT0("gpu", "GLES2::GetUniformBlockIndex");
1178 GLuint index
= share_group_
->program_info_manager()->GetUniformBlockIndex(
1179 this, program
, name
);
1180 GPU_CLIENT_LOG("returned " << index
);
1185 void GLES2Implementation::LinkProgram(GLuint program
) {
1186 GPU_CLIENT_SINGLE_THREAD_CHECK();
1187 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program
<< ")");
1188 helper_
->LinkProgram(program
);
1189 share_group_
->program_info_manager()->CreateInfo(program
);
1193 void GLES2Implementation::ShaderBinary(
1194 GLsizei n
, const GLuint
* shaders
, GLenum binaryformat
, const void* binary
,
1196 GPU_CLIENT_SINGLE_THREAD_CHECK();
1197 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n
<< ", "
1198 << static_cast<const void*>(shaders
) << ", "
1199 << GLES2Util::GetStringEnum(binaryformat
) << ", "
1200 << static_cast<const void*>(binary
) << ", "
1203 SetGLError(GL_INVALID_VALUE
, "glShaderBinary", "n < 0.");
1207 SetGLError(GL_INVALID_VALUE
, "glShaderBinary", "length < 0.");
1210 // TODO(gman): ShaderBinary should use buckets.
1211 unsigned int shader_id_size
= n
* sizeof(*shaders
);
1212 ScopedTransferBufferArray
<GLint
> buffer(
1213 shader_id_size
+ length
, helper_
, transfer_buffer_
);
1214 if (!buffer
.valid() || buffer
.num_elements() != shader_id_size
+ length
) {
1215 SetGLError(GL_OUT_OF_MEMORY
, "glShaderBinary", "out of memory.");
1218 void* shader_ids
= buffer
.elements();
1219 void* shader_data
= buffer
.elements() + shader_id_size
;
1220 memcpy(shader_ids
, shaders
, shader_id_size
);
1221 memcpy(shader_data
, binary
, length
);
1222 helper_
->ShaderBinary(
1228 buffer
.offset() + shader_id_size
,
1233 void GLES2Implementation::PixelStorei(GLenum pname
, GLint param
) {
1234 GPU_CLIENT_SINGLE_THREAD_CHECK();
1235 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1236 << GLES2Util::GetStringPixelStore(pname
) << ", "
1239 case GL_PACK_ALIGNMENT
:
1240 pack_alignment_
= param
;
1242 case GL_UNPACK_ALIGNMENT
:
1243 unpack_alignment_
= param
;
1245 case GL_UNPACK_ROW_LENGTH_EXT
:
1246 unpack_row_length_
= param
;
1248 case GL_UNPACK_IMAGE_HEIGHT
:
1249 unpack_image_height_
= param
;
1251 case GL_UNPACK_SKIP_ROWS_EXT
:
1252 unpack_skip_rows_
= param
;
1254 case GL_UNPACK_SKIP_PIXELS_EXT
:
1255 unpack_skip_pixels_
= param
;
1257 case GL_UNPACK_SKIP_IMAGES
:
1258 unpack_skip_images_
= param
;
1260 case GL_UNPACK_FLIP_Y_CHROMIUM
:
1261 unpack_flip_y_
= (param
!= 0);
1263 case GL_PACK_REVERSE_ROW_ORDER_ANGLE
:
1264 pack_reverse_row_order_
=
1265 IsAnglePackReverseRowOrderAvailable() ? (param
!= 0) : false;
1270 helper_
->PixelStorei(pname
, param
);
1274 void GLES2Implementation::VertexAttribIPointer(
1275 GLuint index
, GLint size
, GLenum type
, GLsizei stride
, const void* ptr
) {
1276 GPU_CLIENT_SINGLE_THREAD_CHECK();
1277 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1280 << GLES2Util::GetStringVertexAttribType(type
) << ", "
1283 helper_
->VertexAttribIPointer(index
, size
, type
, stride
, ToGLuint(ptr
));
1287 void GLES2Implementation::VertexAttribPointer(
1288 GLuint index
, GLint size
, GLenum type
, GLboolean normalized
, GLsizei stride
,
1290 GPU_CLIENT_SINGLE_THREAD_CHECK();
1291 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1294 << GLES2Util::GetStringVertexAttribType(type
) << ", "
1295 << GLES2Util::GetStringBool(normalized
) << ", "
1298 // Record the info on the client side.
1299 if (!vertex_array_object_manager_
->SetAttribPointer(
1300 bound_array_buffer_id_
, index
, size
, type
, normalized
, stride
, ptr
)) {
1301 SetGLError(GL_INVALID_OPERATION
, "glVertexAttribPointer",
1302 "client side arrays are not allowed in vertex array objects.");
1305 if (!support_client_side_arrays_
|| bound_array_buffer_id_
!= 0) {
1306 // Only report NON client side buffers to the service.
1307 if (!ValidateOffset("glVertexAttribPointer",
1308 reinterpret_cast<GLintptr
>(ptr
))) {
1311 helper_
->VertexAttribPointer(index
, size
, type
, normalized
, stride
,
1317 void GLES2Implementation::VertexAttribDivisorANGLE(
1318 GLuint index
, GLuint divisor
) {
1319 GPU_CLIENT_SINGLE_THREAD_CHECK();
1320 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1322 << divisor
<< ") ");
1323 // Record the info on the client side.
1324 vertex_array_object_manager_
->SetAttribDivisor(index
, divisor
);
1325 helper_
->VertexAttribDivisorANGLE(index
, divisor
);
1329 void GLES2Implementation::BufferDataHelper(
1330 GLenum target
, GLsizeiptr size
, const void* data
, GLenum usage
) {
1331 if (!ValidateSize("glBufferData", size
))
1334 #if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
1335 // Do not upload uninitialized data. Even if it's not a bug, it can cause a
1336 // bogus MSan report during a readback later. This is because MSan doesn't
1337 // understand shared memory and would assume we were reading back the same
1338 // unintialized data.
1339 if (data
) __msan_check_mem_is_initialized(data
, size
);
1343 if (GetBoundPixelTransferBuffer(target
, "glBufferData", &buffer_id
)) {
1348 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
1350 RemoveTransferBuffer(buffer
);
1352 // Create new buffer.
1353 buffer
= buffer_tracker_
->CreateBuffer(buffer_id
, size
);
1355 if (buffer
->address() && data
)
1356 memcpy(buffer
->address(), data
, size
);
1364 // If there is no data just send BufferData
1366 helper_
->BufferData(target
, size
, 0, 0, usage
);
1370 // See if we can send all at once.
1371 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1372 if (!buffer
.valid()) {
1376 if (buffer
.size() >= static_cast<unsigned int>(size
)) {
1377 memcpy(buffer
.address(), data
, size
);
1378 helper_
->BufferData(
1387 // Make the buffer with BufferData then send via BufferSubData
1388 helper_
->BufferData(target
, size
, 0, 0, usage
);
1389 BufferSubDataHelperImpl(target
, 0, size
, data
, &buffer
);
1393 void GLES2Implementation::BufferData(
1394 GLenum target
, GLsizeiptr size
, const void* data
, GLenum usage
) {
1395 GPU_CLIENT_SINGLE_THREAD_CHECK();
1396 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1397 << GLES2Util::GetStringBufferTarget(target
) << ", "
1399 << static_cast<const void*>(data
) << ", "
1400 << GLES2Util::GetStringBufferUsage(usage
) << ")");
1401 BufferDataHelper(target
, size
, data
, usage
);
1405 void GLES2Implementation::BufferSubDataHelper(
1406 GLenum target
, GLintptr offset
, GLsizeiptr size
, const void* data
) {
1411 if (!ValidateSize("glBufferSubData", size
) ||
1412 !ValidateOffset("glBufferSubData", offset
)) {
1417 if (GetBoundPixelTransferBuffer(target
, "glBufferSubData", &buffer_id
)) {
1421 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
1423 SetGLError(GL_INVALID_VALUE
, "glBufferSubData", "unknown buffer");
1428 int32 buffer_size
= buffer
->size();
1429 if (!SafeAddInt32(offset
, size
, &end
) || end
> buffer_size
) {
1430 SetGLError(GL_INVALID_VALUE
, "glBufferSubData", "out of range");
1434 if (buffer
->address() && data
)
1435 memcpy(static_cast<uint8
*>(buffer
->address()) + offset
, data
, size
);
1439 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1440 BufferSubDataHelperImpl(target
, offset
, size
, data
, &buffer
);
1443 void GLES2Implementation::BufferSubDataHelperImpl(
1444 GLenum target
, GLintptr offset
, GLsizeiptr size
, const void* data
,
1445 ScopedTransferBufferPtr
* buffer
) {
1449 const int8
* source
= static_cast<const int8
*>(data
);
1451 if (!buffer
->valid() || buffer
->size() == 0) {
1452 buffer
->Reset(size
);
1453 if (!buffer
->valid()) {
1457 memcpy(buffer
->address(), source
, buffer
->size());
1458 helper_
->BufferSubData(
1459 target
, offset
, buffer
->size(), buffer
->shm_id(), buffer
->offset());
1460 offset
+= buffer
->size();
1461 source
+= buffer
->size();
1462 size
-= buffer
->size();
1467 void GLES2Implementation::BufferSubData(
1468 GLenum target
, GLintptr offset
, GLsizeiptr size
, const void* data
) {
1469 GPU_CLIENT_SINGLE_THREAD_CHECK();
1470 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1471 << GLES2Util::GetStringBufferTarget(target
) << ", "
1472 << offset
<< ", " << size
<< ", "
1473 << static_cast<const void*>(data
) << ")");
1474 BufferSubDataHelper(target
, offset
, size
, data
);
1478 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer
* buffer
) {
1479 int32 token
= buffer
->last_usage_token();
1480 uint32 async_token
= buffer
->last_async_upload_token();
1483 if (HasAsyncUploadTokenPassed(async_token
)) {
1484 buffer_tracker_
->Free(buffer
);
1486 detached_async_upload_memory_
.push_back(
1487 std::make_pair(buffer
->address(), async_token
));
1488 buffer_tracker_
->Unmanage(buffer
);
1491 if (helper_
->HasTokenPassed(token
))
1492 buffer_tracker_
->Free(buffer
);
1494 buffer_tracker_
->FreePendingToken(buffer
, token
);
1496 buffer_tracker_
->Free(buffer
);
1499 buffer_tracker_
->RemoveBuffer(buffer
->id());
1502 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1504 const char* function_name
,
1505 GLuint
* buffer_id
) {
1509 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
:
1510 *buffer_id
= bound_pixel_pack_transfer_buffer_id_
;
1512 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
:
1513 *buffer_id
= bound_pixel_unpack_transfer_buffer_id_
;
1520 SetGLError(GL_INVALID_OPERATION
, function_name
, "no buffer bound");
1525 BufferTracker::Buffer
*
1526 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1528 const char* function_name
,
1529 GLuint offset
, GLsizei size
) {
1531 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
1533 SetGLError(GL_INVALID_OPERATION
, function_name
, "invalid buffer");
1536 if (buffer
->mapped()) {
1537 SetGLError(GL_INVALID_OPERATION
, function_name
, "buffer mapped");
1540 if ((buffer
->size() - offset
) < static_cast<GLuint
>(size
)) {
1541 SetGLError(GL_INVALID_VALUE
, function_name
, "unpack size to large");
1547 void GLES2Implementation::CompressedTexImage2D(
1548 GLenum target
, GLint level
, GLenum internalformat
, GLsizei width
,
1549 GLsizei height
, GLint border
, GLsizei image_size
, const void* data
) {
1550 GPU_CLIENT_SINGLE_THREAD_CHECK();
1551 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1552 << GLES2Util::GetStringTextureTarget(target
) << ", "
1554 << GLES2Util::GetStringCompressedTextureFormat(internalformat
) << ", "
1555 << width
<< ", " << height
<< ", " << border
<< ", "
1556 << image_size
<< ", "
1557 << static_cast<const void*>(data
) << ")");
1558 if (width
< 0 || height
< 0 || level
< 0) {
1559 SetGLError(GL_INVALID_VALUE
, "glCompressedTexImage2D", "dimension < 0");
1563 SetGLError(GL_INVALID_VALUE
, "glCompressedTexImage2D", "border != 0");
1566 if (height
== 0 || width
== 0) {
1569 // If there's a pixel unpack buffer bound use it when issuing
1570 // CompressedTexImage2D.
1571 if (bound_pixel_unpack_transfer_buffer_id_
) {
1572 GLuint offset
= ToGLuint(data
);
1573 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1574 bound_pixel_unpack_transfer_buffer_id_
,
1575 "glCompressedTexImage2D", offset
, image_size
);
1576 if (buffer
&& buffer
->shm_id() != -1) {
1577 helper_
->CompressedTexImage2D(
1578 target
, level
, internalformat
, width
, height
, image_size
,
1579 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1580 buffer
->set_last_usage_token(helper_
->InsertToken());
1584 SetBucketContents(kResultBucketId
, data
, image_size
);
1585 helper_
->CompressedTexImage2DBucket(
1586 target
, level
, internalformat
, width
, height
, kResultBucketId
);
1587 // Free the bucket. This is not required but it does free up the memory.
1588 // and we don't have to wait for the result so from the client's perspective
1590 helper_
->SetBucketSize(kResultBucketId
, 0);
1594 void GLES2Implementation::CompressedTexSubImage2D(
1595 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
1596 GLsizei height
, GLenum format
, GLsizei image_size
, const void* data
) {
1597 GPU_CLIENT_SINGLE_THREAD_CHECK();
1598 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1599 << GLES2Util::GetStringTextureTarget(target
) << ", "
1601 << xoffset
<< ", " << yoffset
<< ", "
1602 << width
<< ", " << height
<< ", "
1603 << GLES2Util::GetStringCompressedTextureFormat(format
) << ", "
1604 << image_size
<< ", "
1605 << static_cast<const void*>(data
) << ")");
1606 if (width
< 0 || height
< 0 || level
< 0) {
1607 SetGLError(GL_INVALID_VALUE
, "glCompressedTexSubImage2D", "dimension < 0");
1610 // If there's a pixel unpack buffer bound use it when issuing
1611 // CompressedTexSubImage2D.
1612 if (bound_pixel_unpack_transfer_buffer_id_
) {
1613 GLuint offset
= ToGLuint(data
);
1614 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1615 bound_pixel_unpack_transfer_buffer_id_
,
1616 "glCompressedTexSubImage2D", offset
, image_size
);
1617 if (buffer
&& buffer
->shm_id() != -1) {
1618 helper_
->CompressedTexSubImage2D(
1619 target
, level
, xoffset
, yoffset
, width
, height
, format
, image_size
,
1620 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1621 buffer
->set_last_usage_token(helper_
->InsertToken());
1626 SetBucketContents(kResultBucketId
, data
, image_size
);
1627 helper_
->CompressedTexSubImage2DBucket(
1628 target
, level
, xoffset
, yoffset
, width
, height
, format
, kResultBucketId
);
1629 // Free the bucket. This is not required but it does free up the memory.
1630 // and we don't have to wait for the result so from the client's perspective
1632 helper_
->SetBucketSize(kResultBucketId
, 0);
1638 void CopyRectToBuffer(
1641 uint32 unpadded_row_size
,
1642 uint32 pixels_padded_row_size
,
1645 uint32 buffer_padded_row_size
) {
1646 const int8
* source
= static_cast<const int8
*>(pixels
);
1647 int8
* dest
= static_cast<int8
*>(buffer
);
1648 if (flip_y
|| pixels_padded_row_size
!= buffer_padded_row_size
) {
1650 dest
+= buffer_padded_row_size
* (height
- 1);
1652 // the last row is copied unpadded at the end
1653 for (; height
> 1; --height
) {
1654 memcpy(dest
, source
, buffer_padded_row_size
);
1656 dest
-= buffer_padded_row_size
;
1658 dest
+= buffer_padded_row_size
;
1660 source
+= pixels_padded_row_size
;
1662 memcpy(dest
, source
, unpadded_row_size
);
1664 uint32 size
= (height
- 1) * pixels_padded_row_size
+ unpadded_row_size
;
1665 memcpy(dest
, source
, size
);
1669 } // anonymous namespace
1671 void GLES2Implementation::TexImage2D(
1672 GLenum target
, GLint level
, GLint internalformat
, GLsizei width
,
1673 GLsizei height
, GLint border
, GLenum format
, GLenum type
,
1674 const void* pixels
) {
1675 GPU_CLIENT_SINGLE_THREAD_CHECK();
1676 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1677 << GLES2Util::GetStringTextureTarget(target
) << ", "
1679 << GLES2Util::GetStringTextureInternalFormat(internalformat
) << ", "
1680 << width
<< ", " << height
<< ", " << border
<< ", "
1681 << GLES2Util::GetStringTextureFormat(format
) << ", "
1682 << GLES2Util::GetStringPixelType(type
) << ", "
1683 << static_cast<const void*>(pixels
) << ")");
1684 if (level
< 0 || height
< 0 || width
< 0) {
1685 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "dimension < 0");
1689 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "border != 0");
1693 uint32 unpadded_row_size
;
1694 uint32 padded_row_size
;
1695 if (!GLES2Util::ComputeImageDataSizes(
1696 width
, height
, 1, format
, type
, unpack_alignment_
, &size
,
1697 &unpadded_row_size
, &padded_row_size
)) {
1698 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "image size too large");
1702 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1703 if (bound_pixel_unpack_transfer_buffer_id_
) {
1704 GLuint offset
= ToGLuint(pixels
);
1705 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1706 bound_pixel_unpack_transfer_buffer_id_
,
1707 "glTexImage2D", offset
, size
);
1708 if (buffer
&& buffer
->shm_id() != -1) {
1709 helper_
->TexImage2D(
1710 target
, level
, internalformat
, width
, height
, format
, type
,
1711 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1712 buffer
->set_last_usage_token(helper_
->InsertToken());
1718 // If there's no data just issue TexImage2D
1720 helper_
->TexImage2D(
1721 target
, level
, internalformat
, width
, height
, format
, type
,
1727 // compute the advance bytes per row for the src pixels
1728 uint32 src_padded_row_size
;
1729 if (unpack_row_length_
> 0) {
1730 if (!GLES2Util::ComputeImagePaddedRowSize(
1731 unpack_row_length_
, format
, type
, unpack_alignment_
,
1732 &src_padded_row_size
)) {
1734 GL_INVALID_VALUE
, "glTexImage2D", "unpack row length too large");
1738 src_padded_row_size
= padded_row_size
;
1741 // advance pixels pointer past the skip rows and skip pixels
1742 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1743 unpack_skip_rows_
* src_padded_row_size
;
1744 if (unpack_skip_pixels_
) {
1745 uint32 group_size
= GLES2Util::ComputeImageGroupSize(format
, type
);
1746 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1747 unpack_skip_pixels_
* group_size
;
1750 // Check if we can send it all at once.
1751 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1752 if (!buffer
.valid()) {
1756 if (buffer
.size() >= size
) {
1758 pixels
, height
, unpadded_row_size
, src_padded_row_size
, unpack_flip_y_
,
1759 buffer
.address(), padded_row_size
);
1760 helper_
->TexImage2D(
1761 target
, level
, internalformat
, width
, height
, format
, type
,
1762 buffer
.shm_id(), buffer
.offset());
1767 // No, so send it using TexSubImage2D.
1768 helper_
->TexImage2D(
1769 target
, level
, internalformat
, width
, height
, format
, type
,
1772 target
, level
, 0, 0, width
, height
, format
, type
, unpadded_row_size
,
1773 pixels
, src_padded_row_size
, GL_TRUE
, &buffer
, padded_row_size
);
1777 void GLES2Implementation::TexImage3D(
1778 GLenum target
, GLint level
, GLint internalformat
, GLsizei width
,
1779 GLsizei height
, GLsizei depth
, GLint border
, GLenum format
, GLenum type
,
1780 const void* pixels
) {
1781 GPU_CLIENT_SINGLE_THREAD_CHECK();
1782 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D("
1783 << GLES2Util::GetStringTextureTarget(target
) << ", "
1785 << GLES2Util::GetStringTextureInternalFormat(internalformat
) << ", "
1786 << width
<< ", " << height
<< ", " << depth
<< ", " << border
<< ", "
1787 << GLES2Util::GetStringTextureFormat(format
) << ", "
1788 << GLES2Util::GetStringPixelType(type
) << ", "
1789 << static_cast<const void*>(pixels
) << ")");
1790 if (level
< 0 || height
< 0 || width
< 0 || depth
< 0) {
1791 SetGLError(GL_INVALID_VALUE
, "glTexImage3D", "dimension < 0");
1795 SetGLError(GL_INVALID_VALUE
, "glTexImage3D", "border != 0");
1799 uint32 unpadded_row_size
;
1800 uint32 padded_row_size
;
1801 if (!GLES2Util::ComputeImageDataSizes(
1802 width
, height
, depth
, format
, type
, unpack_alignment_
, &size
,
1803 &unpadded_row_size
, &padded_row_size
)) {
1804 SetGLError(GL_INVALID_VALUE
, "glTexImage3D", "image size too large");
1808 // If there's a pixel unpack buffer bound use it when issuing TexImage3D.
1809 if (bound_pixel_unpack_transfer_buffer_id_
) {
1810 GLuint offset
= ToGLuint(pixels
);
1811 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1812 bound_pixel_unpack_transfer_buffer_id_
,
1813 "glTexImage3D", offset
, size
);
1814 if (buffer
&& buffer
->shm_id() != -1) {
1815 helper_
->TexImage3D(
1816 target
, level
, internalformat
, width
, height
, depth
, format
, type
,
1817 buffer
->shm_id(), buffer
->shm_offset() + offset
);
1818 buffer
->set_last_usage_token(helper_
->InsertToken());
1824 // If there's no data just issue TexImage3D
1826 helper_
->TexImage3D(
1827 target
, level
, internalformat
, width
, height
, depth
, format
, type
,
1833 // compute the advance bytes per row for the src pixels
1834 uint32 src_padded_row_size
;
1835 if (unpack_row_length_
> 0) {
1836 if (!GLES2Util::ComputeImagePaddedRowSize(
1837 unpack_row_length_
, format
, type
, unpack_alignment_
,
1838 &src_padded_row_size
)) {
1840 GL_INVALID_VALUE
, "glTexImage3D", "unpack row length too large");
1844 src_padded_row_size
= padded_row_size
;
1846 uint32 src_height
= unpack_image_height_
> 0 ? unpack_image_height_
: height
;
1848 // advance pixels pointer past the skip images/rows/pixels
1849 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1850 unpack_skip_images_
* src_padded_row_size
* src_height
+
1851 unpack_skip_rows_
* src_padded_row_size
;
1852 if (unpack_skip_pixels_
) {
1853 uint32 group_size
= GLES2Util::ComputeImageGroupSize(format
, type
);
1854 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1855 unpack_skip_pixels_
* group_size
;
1858 // Check if we can send it all at once.
1859 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
1860 if (!buffer
.valid()) {
1864 if (buffer
.size() >= size
) {
1865 void* buffer_pointer
= buffer
.address();
1866 for (GLsizei z
= 0; z
< depth
; ++z
) {
1867 // Only the last row of the last image is unpadded.
1868 uint32 src_unpadded_row_size
=
1869 (z
== depth
- 1) ? unpadded_row_size
: src_padded_row_size
;
1870 // TODO(zmo): Ignore flip_y flag for now.
1872 pixels
, height
, src_unpadded_row_size
, src_padded_row_size
, false,
1873 buffer_pointer
, padded_row_size
);
1874 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1875 src_padded_row_size
* src_height
;
1876 buffer_pointer
= reinterpret_cast<int8
*>(buffer_pointer
) +
1877 padded_row_size
* height
;
1879 helper_
->TexImage3D(
1880 target
, level
, internalformat
, width
, height
, depth
, format
, type
,
1881 buffer
.shm_id(), buffer
.offset());
1886 // No, so send it using TexSubImage3D.
1887 helper_
->TexImage3D(
1888 target
, level
, internalformat
, width
, height
, depth
, format
, type
,
1891 target
, level
, 0, 0, 0, width
, height
, depth
, format
, type
,
1892 unpadded_row_size
, pixels
, src_padded_row_size
, GL_TRUE
, &buffer
,
1897 void GLES2Implementation::TexSubImage2D(
1898 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
1899 GLsizei height
, GLenum format
, GLenum type
, const void* pixels
) {
1900 GPU_CLIENT_SINGLE_THREAD_CHECK();
1901 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1902 << GLES2Util::GetStringTextureTarget(target
) << ", "
1904 << xoffset
<< ", " << yoffset
<< ", "
1905 << width
<< ", " << height
<< ", "
1906 << GLES2Util::GetStringTextureFormat(format
) << ", "
1907 << GLES2Util::GetStringPixelType(type
) << ", "
1908 << static_cast<const void*>(pixels
) << ")");
1910 if (level
< 0 || height
< 0 || width
< 0) {
1911 SetGLError(GL_INVALID_VALUE
, "glTexSubImage2D", "dimension < 0");
1914 if (height
== 0 || width
== 0) {
1919 uint32 unpadded_row_size
;
1920 uint32 padded_row_size
;
1921 if (!GLES2Util::ComputeImageDataSizes(
1922 width
, height
, 1, format
, type
, unpack_alignment_
, &temp_size
,
1923 &unpadded_row_size
, &padded_row_size
)) {
1924 SetGLError(GL_INVALID_VALUE
, "glTexSubImage2D", "size to large");
1928 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1929 if (bound_pixel_unpack_transfer_buffer_id_
) {
1930 GLuint offset
= ToGLuint(pixels
);
1931 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
1932 bound_pixel_unpack_transfer_buffer_id_
,
1933 "glTexSubImage2D", offset
, temp_size
);
1934 if (buffer
&& buffer
->shm_id() != -1) {
1935 helper_
->TexSubImage2D(
1936 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
,
1937 buffer
->shm_id(), buffer
->shm_offset() + offset
, false);
1938 buffer
->set_last_usage_token(helper_
->InsertToken());
1944 // compute the advance bytes per row for the src pixels
1945 uint32 src_padded_row_size
;
1946 if (unpack_row_length_
> 0) {
1947 if (!GLES2Util::ComputeImagePaddedRowSize(
1948 unpack_row_length_
, format
, type
, unpack_alignment_
,
1949 &src_padded_row_size
)) {
1951 GL_INVALID_VALUE
, "glTexImage2D", "unpack row length too large");
1955 src_padded_row_size
= padded_row_size
;
1958 // advance pixels pointer past the skip rows and skip pixels
1959 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1960 unpack_skip_rows_
* src_padded_row_size
;
1961 if (unpack_skip_pixels_
) {
1962 uint32 group_size
= GLES2Util::ComputeImageGroupSize(format
, type
);
1963 pixels
= reinterpret_cast<const int8
*>(pixels
) +
1964 unpack_skip_pixels_
* group_size
;
1967 ScopedTransferBufferPtr
buffer(temp_size
, helper_
, transfer_buffer_
);
1969 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
,
1970 unpadded_row_size
, pixels
, src_padded_row_size
, GL_FALSE
, &buffer
,
1975 void GLES2Implementation::TexSubImage3D(
1976 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLint zoffset
,
1977 GLsizei width
, GLsizei height
, GLsizei depth
, GLenum format
, GLenum type
,
1978 const void* pixels
) {
1979 GPU_CLIENT_SINGLE_THREAD_CHECK();
1980 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D("
1981 << GLES2Util::GetStringTextureTarget(target
) << ", "
1983 << xoffset
<< ", " << yoffset
<< ", " << zoffset
<< ", "
1984 << width
<< ", " << height
<< ", " << depth
<< ", "
1985 << GLES2Util::GetStringTextureFormat(format
) << ", "
1986 << GLES2Util::GetStringPixelType(type
) << ", "
1987 << static_cast<const void*>(pixels
) << ")");
1989 if (level
< 0 || height
< 0 || width
< 0 || depth
< 0) {
1990 SetGLError(GL_INVALID_VALUE
, "glTexSubImage3D", "dimension < 0");
1993 if (height
== 0 || width
== 0 || depth
== 0) {
1998 uint32 unpadded_row_size
;
1999 uint32 padded_row_size
;
2000 if (!GLES2Util::ComputeImageDataSizes(
2001 width
, height
, depth
, format
, type
, unpack_alignment_
, &temp_size
,
2002 &unpadded_row_size
, &padded_row_size
)) {
2003 SetGLError(GL_INVALID_VALUE
, "glTexSubImage3D", "size to large");
2007 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2008 if (bound_pixel_unpack_transfer_buffer_id_
) {
2009 GLuint offset
= ToGLuint(pixels
);
2010 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
2011 bound_pixel_unpack_transfer_buffer_id_
,
2012 "glTexSubImage3D", offset
, temp_size
);
2013 if (buffer
&& buffer
->shm_id() != -1) {
2014 helper_
->TexSubImage3D(
2015 target
, level
, xoffset
, yoffset
, zoffset
, width
, height
, depth
,
2016 format
, type
, buffer
->shm_id(), buffer
->shm_offset() + offset
, false);
2017 buffer
->set_last_usage_token(helper_
->InsertToken());
2023 // compute the advance bytes per row for the src pixels
2024 uint32 src_padded_row_size
;
2025 if (unpack_row_length_
> 0) {
2026 if (!GLES2Util::ComputeImagePaddedRowSize(
2027 unpack_row_length_
, format
, type
, unpack_alignment_
,
2028 &src_padded_row_size
)) {
2030 GL_INVALID_VALUE
, "glTexImage3D", "unpack row length too large");
2034 src_padded_row_size
= padded_row_size
;
2036 uint32 src_height
= unpack_image_height_
> 0 ? unpack_image_height_
: height
;
2038 // advance pixels pointer past the skip images/rows/pixels
2039 pixels
= reinterpret_cast<const int8
*>(pixels
) +
2040 unpack_skip_images_
* src_padded_row_size
* src_height
+
2041 unpack_skip_rows_
* src_padded_row_size
;
2042 if (unpack_skip_pixels_
) {
2043 uint32 group_size
= GLES2Util::ComputeImageGroupSize(format
, type
);
2044 pixels
= reinterpret_cast<const int8
*>(pixels
) +
2045 unpack_skip_pixels_
* group_size
;
2048 ScopedTransferBufferPtr
buffer(temp_size
, helper_
, transfer_buffer_
);
2050 target
, level
, xoffset
, yoffset
, zoffset
, width
, height
, depth
,
2051 format
, type
, unpadded_row_size
, pixels
, src_padded_row_size
, GL_FALSE
,
2052 &buffer
, padded_row_size
);
2056 static GLint
ComputeNumRowsThatFitInBuffer(
2057 uint32 padded_row_size
, uint32 unpadded_row_size
,
2058 unsigned int size
, GLsizei remaining_rows
) {
2059 DCHECK_GE(unpadded_row_size
, 0u);
2060 if (padded_row_size
== 0) {
2063 GLint num_rows
= size
/ padded_row_size
;
2064 if (num_rows
+ 1 == remaining_rows
&&
2065 size
- num_rows
* padded_row_size
>= unpadded_row_size
) {
2071 void GLES2Implementation::TexSubImage2DImpl(
2072 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
2073 GLsizei height
, GLenum format
, GLenum type
, uint32 unpadded_row_size
,
2074 const void* pixels
, uint32 pixels_padded_row_size
, GLboolean internal
,
2075 ScopedTransferBufferPtr
* buffer
, uint32 buffer_padded_row_size
) {
2077 DCHECK_GE(level
, 0);
2078 DCHECK_GT(height
, 0);
2079 DCHECK_GT(width
, 0);
2081 const int8
* source
= reinterpret_cast<const int8
*>(pixels
);
2082 GLint original_yoffset
= yoffset
;
2083 // Transfer by rows.
2085 unsigned int desired_size
=
2086 buffer_padded_row_size
* (height
- 1) + unpadded_row_size
;
2087 if (!buffer
->valid() || buffer
->size() == 0) {
2088 buffer
->Reset(desired_size
);
2089 if (!buffer
->valid()) {
2094 GLint num_rows
= ComputeNumRowsThatFitInBuffer(
2095 buffer_padded_row_size
, unpadded_row_size
, buffer
->size(), height
);
2096 num_rows
= std::min(num_rows
, height
);
2098 source
, num_rows
, unpadded_row_size
, pixels_padded_row_size
,
2099 unpack_flip_y_
, buffer
->address(), buffer_padded_row_size
);
2100 GLint y
= unpack_flip_y_
? original_yoffset
+ height
- num_rows
: yoffset
;
2101 helper_
->TexSubImage2D(
2102 target
, level
, xoffset
, y
, width
, num_rows
, format
, type
,
2103 buffer
->shm_id(), buffer
->offset(), internal
);
2105 yoffset
+= num_rows
;
2106 source
+= num_rows
* pixels_padded_row_size
;
2111 void GLES2Implementation::TexSubImage3DImpl(
2112 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei zoffset
,
2113 GLsizei width
, GLsizei height
, GLsizei depth
, GLenum format
, GLenum type
,
2114 uint32 unpadded_row_size
, const void* pixels
, uint32 pixels_padded_row_size
,
2115 GLboolean internal
, ScopedTransferBufferPtr
* buffer
,
2116 uint32 buffer_padded_row_size
) {
2118 DCHECK_GE(level
, 0);
2119 DCHECK_GT(height
, 0);
2120 DCHECK_GT(width
, 0);
2121 DCHECK_GT(depth
, 0);
2122 const int8
* source
= reinterpret_cast<const int8
*>(pixels
);
2123 GLsizei total_rows
= height
* depth
;
2124 GLint row_index
= 0, depth_index
= 0;
2125 while (total_rows
) {
2126 // Each time, we either copy one or more images, or copy one or more rows
2127 // within a single image, depending on the buffer size limit.
2129 unsigned int desired_size
;
2130 if (row_index
> 0) {
2131 // We are in the middle of an image. Send the remaining of the image.
2132 max_rows
= height
- row_index
;
2133 if (total_rows
<= height
) {
2134 // Last image, so last row is unpadded.
2135 desired_size
= buffer_padded_row_size
* (max_rows
- 1) +
2138 desired_size
= buffer_padded_row_size
* max_rows
;
2141 // Send all the remaining data if possible.
2142 max_rows
= total_rows
;
2144 buffer_padded_row_size
* (max_rows
- 1) + unpadded_row_size
;
2146 if (!buffer
->valid() || buffer
->size() == 0) {
2147 buffer
->Reset(desired_size
);
2148 if (!buffer
->valid()) {
2152 GLint num_rows
= ComputeNumRowsThatFitInBuffer(
2153 buffer_padded_row_size
, unpadded_row_size
, buffer
->size(), total_rows
);
2154 num_rows
= std::min(num_rows
, max_rows
);
2155 GLint num_images
= num_rows
/ height
;
2156 GLsizei my_height
, my_depth
;
2157 if (num_images
> 0) {
2158 num_rows
= num_images
* height
;
2160 my_depth
= num_images
;
2162 my_height
= num_rows
;
2166 // TODO(zmo): Ignore flip_y flag for now.
2167 if (num_images
> 0) {
2168 int8
* buffer_pointer
= reinterpret_cast<int8
*>(buffer
->address());
2170 unpack_image_height_
> 0 ? unpack_image_height_
: height
;
2171 uint32 image_size_dst
= buffer_padded_row_size
* height
;
2172 uint32 image_size_src
= pixels_padded_row_size
* src_height
;
2173 for (GLint ii
= 0; ii
< num_images
; ++ii
) {
2174 uint32 my_unpadded_row_size
;
2175 if (total_rows
== num_rows
&& ii
+ 1 == num_images
)
2176 my_unpadded_row_size
= unpadded_row_size
;
2178 my_unpadded_row_size
= pixels_padded_row_size
;
2180 source
+ ii
* image_size_src
, my_height
, my_unpadded_row_size
,
2181 pixels_padded_row_size
, false, buffer_pointer
+ ii
* image_size_dst
,
2182 buffer_padded_row_size
);
2185 uint32 my_unpadded_row_size
;
2186 if (total_rows
== num_rows
)
2187 my_unpadded_row_size
= unpadded_row_size
;
2189 my_unpadded_row_size
= pixels_padded_row_size
;
2191 source
, my_height
, my_unpadded_row_size
, pixels_padded_row_size
,
2192 false, buffer
->address(), buffer_padded_row_size
);
2194 helper_
->TexSubImage3D(
2195 target
, level
, xoffset
, yoffset
+ row_index
, zoffset
+ depth_index
,
2196 width
, my_height
, my_depth
,
2197 format
, type
, buffer
->shm_id(), buffer
->offset(), internal
);
2200 total_rows
-= num_rows
;
2201 if (total_rows
> 0) {
2202 GLint num_image_paddings
;
2203 if (num_images
> 0) {
2204 DCHECK_EQ(row_index
, 0);
2205 depth_index
+= num_images
;
2206 num_image_paddings
= num_images
;
2208 row_index
= (row_index
+ my_height
) % height
;
2209 num_image_paddings
= 0;
2210 if (my_height
> 0 && row_index
== 0) {
2212 num_image_paddings
++;
2215 source
+= num_rows
* pixels_padded_row_size
;
2216 if (unpack_image_height_
> height
&& num_image_paddings
> 0) {
2217 source
+= num_image_paddings
* (unpack_image_height_
- height
) *
2218 pixels_padded_row_size
;
2224 bool GLES2Implementation::GetActiveAttribHelper(
2225 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2226 GLenum
* type
, char* name
) {
2227 // Clear the bucket so if the command fails nothing will be in it.
2228 helper_
->SetBucketSize(kResultBucketId
, 0);
2229 typedef cmds::GetActiveAttrib::Result Result
;
2230 Result
* result
= GetResultAs
<Result
*>();
2234 // Set as failed so if the command fails we'll recover.
2235 result
->success
= false;
2236 helper_
->GetActiveAttrib(program
, index
, kResultBucketId
,
2237 GetResultShmId(), GetResultShmOffset());
2239 if (result
->success
) {
2241 *size
= result
->size
;
2244 *type
= result
->type
;
2246 if (length
|| name
) {
2247 std::vector
<int8
> str
;
2248 GetBucketContents(kResultBucketId
, &str
);
2249 GLsizei max_size
= std::min(static_cast<size_t>(bufsize
) - 1,
2250 std::max(static_cast<size_t>(0),
2255 if (name
&& bufsize
> 0) {
2256 memcpy(name
, &str
[0], max_size
);
2257 name
[max_size
] = '\0';
2261 return result
->success
!= 0;
2264 void GLES2Implementation::GetActiveAttrib(
2265 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2266 GLenum
* type
, char* name
) {
2267 GPU_CLIENT_SINGLE_THREAD_CHECK();
2268 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2269 << program
<< ", " << index
<< ", " << bufsize
<< ", "
2270 << static_cast<const void*>(length
) << ", "
2271 << static_cast<const void*>(size
) << ", "
2272 << static_cast<const void*>(type
) << ", "
2273 << static_cast<const void*>(name
) << ", ");
2275 SetGLError(GL_INVALID_VALUE
, "glGetActiveAttrib", "bufsize < 0");
2278 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2279 bool success
= share_group_
->program_info_manager()->GetActiveAttrib(
2280 this, program
, index
, bufsize
, length
, size
, type
, name
);
2283 GPU_CLIENT_LOG(" size: " << *size
);
2286 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type
));
2289 GPU_CLIENT_LOG(" name: " << name
);
2295 bool GLES2Implementation::GetActiveUniformHelper(
2296 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2297 GLenum
* type
, char* name
) {
2298 // Clear the bucket so if the command fails nothing will be in it.
2299 helper_
->SetBucketSize(kResultBucketId
, 0);
2300 typedef cmds::GetActiveUniform::Result Result
;
2301 Result
* result
= GetResultAs
<Result
*>();
2305 // Set as failed so if the command fails we'll recover.
2306 result
->success
= false;
2307 helper_
->GetActiveUniform(program
, index
, kResultBucketId
,
2308 GetResultShmId(), GetResultShmOffset());
2310 if (result
->success
) {
2312 *size
= result
->size
;
2315 *type
= result
->type
;
2317 if (length
|| name
) {
2318 std::vector
<int8
> str
;
2319 GetBucketContents(kResultBucketId
, &str
);
2320 GLsizei max_size
= std::min(static_cast<size_t>(bufsize
) - 1,
2321 std::max(static_cast<size_t>(0),
2326 if (name
&& bufsize
> 0) {
2327 memcpy(name
, &str
[0], max_size
);
2328 name
[max_size
] = '\0';
2332 return result
->success
!= 0;
2335 void GLES2Implementation::GetActiveUniform(
2336 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2337 GLenum
* type
, char* name
) {
2338 GPU_CLIENT_SINGLE_THREAD_CHECK();
2339 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2340 << program
<< ", " << index
<< ", " << bufsize
<< ", "
2341 << static_cast<const void*>(length
) << ", "
2342 << static_cast<const void*>(size
) << ", "
2343 << static_cast<const void*>(type
) << ", "
2344 << static_cast<const void*>(name
) << ", ");
2346 SetGLError(GL_INVALID_VALUE
, "glGetActiveUniform", "bufsize < 0");
2349 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2350 bool success
= share_group_
->program_info_manager()->GetActiveUniform(
2351 this, program
, index
, bufsize
, length
, size
, type
, name
);
2354 GPU_CLIENT_LOG(" size: " << *size
);
2357 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type
));
2360 GPU_CLIENT_LOG(" name: " << name
);
2366 bool GLES2Implementation::GetActiveUniformBlockNameHelper(
2367 GLuint program
, GLuint index
, GLsizei bufsize
,
2368 GLsizei
* length
, char* name
) {
2369 DCHECK_LE(0, bufsize
);
2370 // Clear the bucket so if the command fails nothing will be in it.
2371 helper_
->SetBucketSize(kResultBucketId
, 0);
2372 typedef cmds::GetActiveUniformBlockName::Result Result
;
2373 Result
* result
= GetResultAs
<Result
*>();
2377 // Set as failed so if the command fails we'll recover.
2379 helper_
->GetActiveUniformBlockName(program
, index
, kResultBucketId
,
2380 GetResultShmId(), GetResultShmOffset());
2387 } else if (length
|| name
) {
2388 std::vector
<int8
> str
;
2389 GetBucketContents(kResultBucketId
, &str
);
2390 DCHECK(str
.size() > 0);
2392 std::min(bufsize
, static_cast<GLsizei
>(str
.size())) - 1;
2397 memcpy(name
, &str
[0], max_size
);
2398 name
[max_size
] = '\0';
2402 return *result
!= 0;
2405 void GLES2Implementation::GetActiveUniformBlockName(
2406 GLuint program
, GLuint index
, GLsizei bufsize
,
2407 GLsizei
* length
, char* name
) {
2408 GPU_CLIENT_SINGLE_THREAD_CHECK();
2409 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
2410 << program
<< ", " << index
<< ", " << bufsize
<< ", "
2411 << static_cast<const void*>(length
) << ", "
2412 << static_cast<const void*>(name
) << ")");
2414 SetGLError(GL_INVALID_VALUE
, "glGetActiveUniformBlockName", "bufsize < 0");
2417 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockName");
2419 share_group_
->program_info_manager()->GetActiveUniformBlockName(
2420 this, program
, index
, bufsize
, length
, name
);
2423 GPU_CLIENT_LOG(" name: " << name
);
2429 bool GLES2Implementation::GetActiveUniformBlockivHelper(
2430 GLuint program
, GLuint index
, GLenum pname
, GLint
* params
) {
2431 typedef cmds::GetActiveUniformBlockiv::Result Result
;
2432 Result
* result
= GetResultAs
<Result
*>();
2436 result
->SetNumResults(0);
2437 helper_
->GetActiveUniformBlockiv(
2438 program
, index
, pname
, GetResultShmId(), GetResultShmOffset());
2440 if (result
->GetNumResults() > 0) {
2442 result
->CopyResult(params
);
2444 GPU_CLIENT_LOG_CODE_BLOCK({
2445 for (int32_t i
= 0; i
< result
->GetNumResults(); ++i
) {
2446 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2454 void GLES2Implementation::GetActiveUniformBlockiv(
2455 GLuint program
, GLuint index
, GLenum pname
, GLint
* params
) {
2456 GPU_CLIENT_SINGLE_THREAD_CHECK();
2457 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
2458 << program
<< ", " << index
<< ", "
2459 << GLES2Util::GetStringUniformBlockParameter(pname
) << ", "
2460 << static_cast<const void*>(params
) << ")");
2461 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
2463 share_group_
->program_info_manager()->GetActiveUniformBlockiv(
2464 this, program
, index
, pname
, params
);
2467 // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
2468 // be more than one value returned in params.
2469 GPU_CLIENT_LOG(" params: " << params
[0]);
2475 bool GLES2Implementation::GetActiveUniformsivHelper(
2476 GLuint program
, GLsizei count
, const GLuint
* indices
,
2477 GLenum pname
, GLint
* params
) {
2478 typedef cmds::GetActiveUniformsiv::Result Result
;
2479 Result
* result
= GetResultAs
<Result
*>();
2483 result
->SetNumResults(0);
2484 base::CheckedNumeric
<size_t> bytes
= static_cast<size_t>(count
);
2485 bytes
*= sizeof(GLuint
);
2486 if (!bytes
.IsValid()) {
2487 SetGLError(GL_INVALID_VALUE
, "glGetActiveUniformsiv", "count overflow");
2490 SetBucketContents(kResultBucketId
, indices
, bytes
.ValueOrDefault(0));
2491 helper_
->GetActiveUniformsiv(
2492 program
, kResultBucketId
, pname
, GetResultShmId(), GetResultShmOffset());
2494 bool success
= result
->GetNumResults() == count
;
2497 result
->CopyResult(params
);
2499 GPU_CLIENT_LOG_CODE_BLOCK({
2500 for (int32_t i
= 0; i
< result
->GetNumResults(); ++i
) {
2501 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2505 helper_
->SetBucketSize(kResultBucketId
, 0);
2509 void GLES2Implementation::GetActiveUniformsiv(
2510 GLuint program
, GLsizei count
, const GLuint
* indices
,
2511 GLenum pname
, GLint
* params
) {
2512 GPU_CLIENT_SINGLE_THREAD_CHECK();
2513 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv("
2514 << program
<< ", " << count
<< ", "
2515 << static_cast<const void*>(indices
) << ", "
2516 << GLES2Util::GetStringUniformParameter(pname
) << ", "
2517 << static_cast<const void*>(params
) << ")");
2518 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
2520 SetGLError(GL_INVALID_VALUE
, "glGetActiveUniformsiv", "count < 0");
2523 bool success
= share_group_
->program_info_manager()->GetActiveUniformsiv(
2524 this, program
, count
, indices
, pname
, params
);
2527 GPU_CLIENT_LOG_CODE_BLOCK({
2528 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
2529 GPU_CLIENT_LOG(" " << ii
<< ": " << params
[ii
]);
2537 void GLES2Implementation::GetAttachedShaders(
2538 GLuint program
, GLsizei maxcount
, GLsizei
* count
, GLuint
* shaders
) {
2539 GPU_CLIENT_SINGLE_THREAD_CHECK();
2540 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2541 << program
<< ", " << maxcount
<< ", "
2542 << static_cast<const void*>(count
) << ", "
2543 << static_cast<const void*>(shaders
) << ", ");
2545 SetGLError(GL_INVALID_VALUE
, "glGetAttachedShaders", "maxcount < 0");
2548 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2549 typedef cmds::GetAttachedShaders::Result Result
;
2550 uint32 size
= Result::ComputeSize(maxcount
);
2551 Result
* result
= static_cast<Result
*>(transfer_buffer_
->Alloc(size
));
2555 result
->SetNumResults(0);
2556 helper_
->GetAttachedShaders(
2558 transfer_buffer_
->GetShmId(),
2559 transfer_buffer_
->GetOffset(result
),
2561 int32 token
= helper_
->InsertToken();
2564 *count
= result
->GetNumResults();
2566 result
->CopyResult(shaders
);
2567 GPU_CLIENT_LOG_CODE_BLOCK({
2568 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2569 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2572 transfer_buffer_
->FreePendingToken(result
, token
);
2576 void GLES2Implementation::GetShaderPrecisionFormat(
2577 GLenum shadertype
, GLenum precisiontype
, GLint
* range
, GLint
* precision
) {
2578 GPU_CLIENT_SINGLE_THREAD_CHECK();
2579 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2580 << GLES2Util::GetStringShaderType(shadertype
) << ", "
2581 << GLES2Util::GetStringShaderPrecision(precisiontype
) << ", "
2582 << static_cast<const void*>(range
) << ", "
2583 << static_cast<const void*>(precision
) << ", ");
2584 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2585 typedef cmds::GetShaderPrecisionFormat::Result Result
;
2586 Result
* result
= GetResultAs
<Result
*>();
2591 GLStaticState::ShaderPrecisionKey
key(shadertype
, precisiontype
);
2592 GLStaticState::ShaderPrecisionMap::iterator i
=
2593 static_state_
.shader_precisions
.find(key
);
2594 if (i
!= static_state_
.shader_precisions
.end()) {
2595 *result
= i
->second
;
2597 result
->success
= false;
2598 helper_
->GetShaderPrecisionFormat(
2599 shadertype
, precisiontype
, GetResultShmId(), GetResultShmOffset());
2601 if (result
->success
)
2602 static_state_
.shader_precisions
[key
] = *result
;
2605 if (result
->success
) {
2607 range
[0] = result
->min_range
;
2608 range
[1] = result
->max_range
;
2609 GPU_CLIENT_LOG(" min_range: " << range
[0]);
2610 GPU_CLIENT_LOG(" min_range: " << range
[1]);
2613 precision
[0] = result
->precision
;
2614 GPU_CLIENT_LOG(" min_range: " << precision
[0]);
2620 const GLubyte
* GLES2Implementation::GetStringHelper(GLenum name
) {
2621 const char* result
= NULL
;
2622 // Clears the bucket so if the command fails nothing will be in it.
2623 helper_
->SetBucketSize(kResultBucketId
, 0);
2624 helper_
->GetString(name
, kResultBucketId
);
2626 if (GetBucketAsString(kResultBucketId
, &str
)) {
2627 // Adds extensions implemented on client side only.
2630 str
+= std::string(str
.empty() ? "" : " ") +
2631 "GL_CHROMIUM_flipy "
2632 "GL_EXT_unpack_subimage "
2633 "GL_CHROMIUM_map_sub";
2634 if (capabilities_
.image
)
2635 str
+= " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
2636 if (capabilities_
.future_sync_points
)
2637 str
+= " GL_CHROMIUM_future_sync_point";
2643 // Because of WebGL the extensions can change. We have to cache each unique
2644 // result since we don't know when the client will stop referring to a
2645 // previous one it queries.
2646 GLStringMap::iterator it
= gl_strings_
.find(name
);
2647 if (it
== gl_strings_
.end()) {
2648 std::set
<std::string
> strings
;
2649 std::pair
<GLStringMap::iterator
, bool> insert_result
=
2650 gl_strings_
.insert(std::make_pair(name
, strings
));
2651 DCHECK(insert_result
.second
);
2652 it
= insert_result
.first
;
2654 std::set
<std::string
>& string_set
= it
->second
;
2655 std::set
<std::string
>::const_iterator sit
= string_set
.find(str
);
2656 if (sit
!= string_set
.end()) {
2657 result
= sit
->c_str();
2659 std::pair
<std::set
<std::string
>::const_iterator
, bool> insert_result
=
2660 string_set
.insert(str
);
2661 DCHECK(insert_result
.second
);
2662 result
= insert_result
.first
->c_str();
2665 return reinterpret_cast<const GLubyte
*>(result
);
2668 const GLubyte
* GLES2Implementation::GetString(GLenum name
) {
2669 GPU_CLIENT_SINGLE_THREAD_CHECK();
2670 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2671 << GLES2Util::GetStringStringType(name
) << ")");
2672 TRACE_EVENT0("gpu", "GLES2::GetString");
2673 const GLubyte
* result
= GetStringHelper(name
);
2674 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result
));
2679 bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
2680 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2681 GLenum
* type
, char* name
) {
2682 // Clear the bucket so if the command fails nothing will be in it.
2683 helper_
->SetBucketSize(kResultBucketId
, 0);
2684 typedef cmds::GetTransformFeedbackVarying::Result Result
;
2685 Result
* result
= GetResultAs
<Result
*>();
2689 // Set as failed so if the command fails we'll recover.
2690 result
->success
= false;
2691 helper_
->GetTransformFeedbackVarying(
2692 program
, index
, kResultBucketId
, GetResultShmId(), GetResultShmOffset());
2694 if (result
->success
) {
2696 *size
= result
->size
;
2699 *type
= result
->type
;
2701 if (length
|| name
) {
2702 std::vector
<int8
> str
;
2703 GetBucketContents(kResultBucketId
, &str
);
2704 GLsizei max_size
= std::min(bufsize
, static_cast<GLsizei
>(str
.size()));
2713 memcpy(name
, &str
[0], max_size
);
2714 name
[max_size
] = '\0';
2715 } else if (bufsize
> 0) {
2721 return result
->success
!= 0;
2724 void GLES2Implementation::GetTransformFeedbackVarying(
2725 GLuint program
, GLuint index
, GLsizei bufsize
, GLsizei
* length
, GLint
* size
,
2726 GLenum
* type
, char* name
) {
2727 GPU_CLIENT_SINGLE_THREAD_CHECK();
2728 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
2729 << program
<< ", " << index
<< ", " << bufsize
<< ", "
2730 << static_cast<const void*>(length
) << ", "
2731 << static_cast<const void*>(size
) << ", "
2732 << static_cast<const void*>(type
) << ", "
2733 << static_cast<const void*>(name
) << ", ");
2735 SetGLError(GL_INVALID_VALUE
, "glGetTransformFeedbackVarying",
2739 TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
2741 share_group_
->program_info_manager()->GetTransformFeedbackVarying(
2742 this, program
, index
, bufsize
, length
, size
, type
, name
);
2745 GPU_CLIENT_LOG(" size: " << *size
);
2748 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type
));
2751 GPU_CLIENT_LOG(" name: " << name
);
2757 void GLES2Implementation::GetUniformfv(
2758 GLuint program
, GLint location
, GLfloat
* params
) {
2759 GPU_CLIENT_SINGLE_THREAD_CHECK();
2760 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2761 << program
<< ", " << location
<< ", "
2762 << static_cast<const void*>(params
) << ")");
2763 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2764 typedef cmds::GetUniformfv::Result Result
;
2765 Result
* result
= GetResultAs
<Result
*>();
2769 result
->SetNumResults(0);
2770 helper_
->GetUniformfv(
2771 program
, location
, GetResultShmId(), GetResultShmOffset());
2773 result
->CopyResult(params
);
2774 GPU_CLIENT_LOG_CODE_BLOCK({
2775 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2776 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2782 void GLES2Implementation::GetUniformiv(
2783 GLuint program
, GLint location
, GLint
* params
) {
2784 GPU_CLIENT_SINGLE_THREAD_CHECK();
2785 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2786 << program
<< ", " << location
<< ", "
2787 << static_cast<const void*>(params
) << ")");
2788 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2789 typedef cmds::GetUniformiv::Result Result
;
2790 Result
* result
= GetResultAs
<Result
*>();
2794 result
->SetNumResults(0);
2795 helper_
->GetUniformiv(
2796 program
, location
, GetResultShmId(), GetResultShmOffset());
2798 GetResultAs
<cmds::GetUniformfv::Result
*>()->CopyResult(params
);
2799 GPU_CLIENT_LOG_CODE_BLOCK({
2800 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
2801 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
2807 void GLES2Implementation::ReadPixels(
2808 GLint xoffset
, GLint yoffset
, GLsizei width
, GLsizei height
, GLenum format
,
2809 GLenum type
, void* pixels
) {
2810 GPU_CLIENT_SINGLE_THREAD_CHECK();
2811 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2812 << xoffset
<< ", " << yoffset
<< ", "
2813 << width
<< ", " << height
<< ", "
2814 << GLES2Util::GetStringReadPixelFormat(format
) << ", "
2815 << GLES2Util::GetStringPixelType(type
) << ", "
2816 << static_cast<const void*>(pixels
) << ")");
2817 if (width
< 0 || height
< 0) {
2818 SetGLError(GL_INVALID_VALUE
, "glReadPixels", "dimensions < 0");
2821 if (width
== 0 || height
== 0) {
2825 // glReadPixel pads the size of each row of pixels by an amount specified by
2826 // glPixelStorei. So, we have to take that into account both in the fact that
2827 // the pixels returned from the ReadPixel command will include that padding
2828 // and that when we copy the results to the user's buffer we need to not
2829 // write those padding bytes but leave them as they are.
2831 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2832 typedef cmds::ReadPixels::Result Result
;
2834 int8
* dest
= reinterpret_cast<int8
*>(pixels
);
2836 uint32 unpadded_row_size
;
2837 uint32 padded_row_size
;
2838 if (!GLES2Util::ComputeImageDataSizes(
2839 width
, 2, 1, format
, type
, pack_alignment_
, &temp_size
,
2840 &unpadded_row_size
, &padded_row_size
)) {
2841 SetGLError(GL_INVALID_VALUE
, "glReadPixels", "size too large.");
2845 if (bound_pixel_pack_transfer_buffer_id_
) {
2846 GLuint offset
= ToGLuint(pixels
);
2847 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
2848 bound_pixel_pack_transfer_buffer_id_
,
2849 "glReadPixels", offset
, padded_row_size
* height
);
2850 if (buffer
&& buffer
->shm_id() != -1) {
2851 helper_
->ReadPixels(xoffset
, yoffset
, width
, height
, format
, type
,
2852 buffer
->shm_id(), buffer
->shm_offset(),
2860 SetGLError(GL_INVALID_OPERATION
, "glReadPixels", "pixels = NULL");
2864 // Transfer by rows.
2865 // The max rows we can transfer.
2867 GLsizei desired_size
= padded_row_size
* (height
- 1) + unpadded_row_size
;
2868 ScopedTransferBufferPtr
buffer(desired_size
, helper_
, transfer_buffer_
);
2869 if (!buffer
.valid()) {
2872 GLint num_rows
= ComputeNumRowsThatFitInBuffer(
2873 padded_row_size
, unpadded_row_size
, buffer
.size(), height
);
2874 num_rows
= std::min(num_rows
, height
);
2875 // NOTE: We must look up the address of the result area AFTER allocation
2876 // of the transfer buffer since the transfer buffer may be reallocated.
2877 Result
* result
= GetResultAs
<Result
*>();
2881 *result
= 0; // mark as failed.
2882 helper_
->ReadPixels(
2883 xoffset
, yoffset
, width
, num_rows
, format
, type
,
2884 buffer
.shm_id(), buffer
.offset(),
2885 GetResultShmId(), GetResultShmOffset(),
2889 // when doing a y-flip we have to iterate through top-to-bottom chunks
2890 // of the dst. The service side handles reversing the rows within a
2893 if (pack_reverse_row_order_
) {
2894 rows_dst
= dest
+ (height
- num_rows
) * padded_row_size
;
2898 // We have to copy 1 row at a time to avoid writing pad bytes.
2899 const int8
* src
= static_cast<const int8
*>(buffer
.address());
2900 for (GLint yy
= 0; yy
< num_rows
; ++yy
) {
2901 memcpy(rows_dst
, src
, unpadded_row_size
);
2902 rows_dst
+= padded_row_size
;
2903 src
+= padded_row_size
;
2905 if (!pack_reverse_row_order_
) {
2909 // If it was not marked as successful exit.
2913 yoffset
+= num_rows
;
2919 void GLES2Implementation::ActiveTexture(GLenum texture
) {
2920 GPU_CLIENT_SINGLE_THREAD_CHECK();
2921 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2922 << GLES2Util::GetStringEnum(texture
) << ")");
2923 GLuint texture_index
= texture
- GL_TEXTURE0
;
2924 if (texture_index
>=
2925 static_cast<GLuint
>(capabilities_
.max_combined_texture_image_units
)) {
2926 SetGLErrorInvalidEnum(
2927 "glActiveTexture", texture
, "texture");
2931 active_texture_unit_
= texture_index
;
2932 helper_
->ActiveTexture(texture
);
2936 void GLES2Implementation::GenBuffersHelper(
2937 GLsizei
/* n */, const GLuint
* /* buffers */) {
2940 void GLES2Implementation::GenFramebuffersHelper(
2941 GLsizei
/* n */, const GLuint
* /* framebuffers */) {
2944 void GLES2Implementation::GenRenderbuffersHelper(
2945 GLsizei
/* n */, const GLuint
* /* renderbuffers */) {
2948 void GLES2Implementation::GenTexturesHelper(
2949 GLsizei
/* n */, const GLuint
* /* textures */) {
2952 void GLES2Implementation::GenVertexArraysOESHelper(
2953 GLsizei n
, const GLuint
* arrays
) {
2954 vertex_array_object_manager_
->GenVertexArrays(n
, arrays
);
2957 void GLES2Implementation::GenQueriesEXTHelper(
2958 GLsizei
/* n */, const GLuint
* /* queries */) {
2961 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
2963 const GLuint
* /* valuebuffers */) {
2966 void GLES2Implementation::GenSamplersHelper(
2967 GLsizei
/* n */, const GLuint
* /* samplers */) {
2970 void GLES2Implementation::GenTransformFeedbacksHelper(
2971 GLsizei
/* n */, const GLuint
* /* transformfeedbacks */) {
2974 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
2975 // generates a new resource. On newer versions of OpenGL they don't. The code
2976 // related to binding below will need to change if we switch to the new OpenGL
2977 // model. Specifically it assumes a bind will succeed which is always true in
2978 // the old model but possibly not true in the new model if another context has
2979 // deleted the resource.
2981 // NOTE #2: There is a bug in some BindXXXHelpers, that IDs might be marked as
2982 // used even when Bind has failed. However, the bug is minor compared to the
2983 // overhead & duplicated checking in client side.
2985 void GLES2Implementation::BindBufferHelper(
2986 GLenum target
, GLuint buffer_id
) {
2987 // TODO(gman): See note #1 above.
2988 bool changed
= false;
2990 case GL_ARRAY_BUFFER
:
2991 if (bound_array_buffer_id_
!= buffer_id
) {
2992 bound_array_buffer_id_
= buffer_id
;
2996 case GL_ELEMENT_ARRAY_BUFFER
:
2997 changed
= vertex_array_object_manager_
->BindElementArray(buffer_id
);
2999 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
:
3000 bound_pixel_pack_transfer_buffer_id_
= buffer_id
;
3002 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
:
3003 bound_pixel_unpack_transfer_buffer_id_
= buffer_id
;
3009 // TODO(gman): See note #2 above.
3011 GetIdHandler(id_namespaces::kBuffers
)->MarkAsUsedForBind(
3012 this, target
, buffer_id
, &GLES2Implementation::BindBufferStub
);
3016 void GLES2Implementation::BindBufferStub(GLenum target
, GLuint buffer
) {
3017 helper_
->BindBuffer(target
, buffer
);
3018 if (share_group_
->bind_generates_resource())
3019 helper_
->CommandBufferHelper::Flush();
3022 void GLES2Implementation::BindBufferBaseHelper(
3023 GLenum target
, GLuint index
, GLuint buffer_id
) {
3024 // TODO(zmo): See note #1 above.
3025 // TODO(zmo): See note #2 above.
3026 GetIdHandler(id_namespaces::kBuffers
)->MarkAsUsedForBind(
3027 this, target
, index
, buffer_id
, &GLES2Implementation::BindBufferBaseStub
);
3030 void GLES2Implementation::BindBufferBaseStub(
3031 GLenum target
, GLuint index
, GLuint buffer
) {
3032 helper_
->BindBufferBase(target
, index
, buffer
);
3033 if (share_group_
->bind_generates_resource())
3034 helper_
->CommandBufferHelper::Flush();
3037 void GLES2Implementation::BindBufferRangeHelper(
3038 GLenum target
, GLuint index
, GLuint buffer_id
,
3039 GLintptr offset
, GLsizeiptr size
) {
3040 // TODO(zmo): See note #1 above.
3041 // TODO(zmo): See note #2 above.
3042 GetIdHandler(id_namespaces::kBuffers
)->MarkAsUsedForBind(
3043 this, target
, index
, buffer_id
, offset
, size
,
3044 &GLES2Implementation::BindBufferRangeStub
);
3047 void GLES2Implementation::BindBufferRangeStub(
3048 GLenum target
, GLuint index
, GLuint buffer
,
3049 GLintptr offset
, GLsizeiptr size
) {
3050 helper_
->BindBufferRange(target
, index
, buffer
, offset
, size
);
3051 if (share_group_
->bind_generates_resource())
3052 helper_
->CommandBufferHelper::Flush();
3055 void GLES2Implementation::BindFramebufferHelper(
3056 GLenum target
, GLuint framebuffer
) {
3057 // TODO(gman): See note #1 above.
3058 bool changed
= false;
3060 case GL_FRAMEBUFFER
:
3061 if (bound_framebuffer_
!= framebuffer
||
3062 bound_read_framebuffer_
!= framebuffer
) {
3063 bound_framebuffer_
= framebuffer
;
3064 bound_read_framebuffer_
= framebuffer
;
3068 case GL_READ_FRAMEBUFFER
:
3069 if (!IsChromiumFramebufferMultisampleAvailable()) {
3070 SetGLErrorInvalidEnum("glBindFramebuffer", target
, "target");
3073 if (bound_read_framebuffer_
!= framebuffer
) {
3074 bound_read_framebuffer_
= framebuffer
;
3078 case GL_DRAW_FRAMEBUFFER
:
3079 if (!IsChromiumFramebufferMultisampleAvailable()) {
3080 SetGLErrorInvalidEnum("glBindFramebuffer", target
, "target");
3083 if (bound_framebuffer_
!= framebuffer
) {
3084 bound_framebuffer_
= framebuffer
;
3089 SetGLErrorInvalidEnum("glBindFramebuffer", target
, "target");
3094 GetIdHandler(id_namespaces::kFramebuffers
)->MarkAsUsedForBind(
3095 this, target
, framebuffer
, &GLES2Implementation::BindFramebufferStub
);
3099 void GLES2Implementation::BindFramebufferStub(GLenum target
,
3100 GLuint framebuffer
) {
3101 helper_
->BindFramebuffer(target
, framebuffer
);
3102 if (share_group_
->bind_generates_resource())
3103 helper_
->CommandBufferHelper::Flush();
3106 void GLES2Implementation::BindRenderbufferHelper(
3107 GLenum target
, GLuint renderbuffer
) {
3108 // TODO(gman): See note #1 above.
3109 bool changed
= false;
3111 case GL_RENDERBUFFER
:
3112 if (bound_renderbuffer_
!= renderbuffer
) {
3113 bound_renderbuffer_
= renderbuffer
;
3121 // TODO(zmo): See note #2 above.
3123 GetIdHandler(id_namespaces::kRenderbuffers
)->MarkAsUsedForBind(
3124 this, target
, renderbuffer
,
3125 &GLES2Implementation::BindRenderbufferStub
);
3129 void GLES2Implementation::BindRenderbufferStub(GLenum target
,
3130 GLuint renderbuffer
) {
3131 helper_
->BindRenderbuffer(target
, renderbuffer
);
3132 if (share_group_
->bind_generates_resource())
3133 helper_
->CommandBufferHelper::Flush();
3136 void GLES2Implementation::BindSamplerHelper(GLuint unit
,
3138 helper_
->BindSampler(unit
, sampler
);
3141 void GLES2Implementation::BindTextureHelper(GLenum target
, GLuint texture
) {
3142 // TODO(gman): See note #1 above.
3143 // TODO(gman): Change this to false once we figure out why it's failing
3145 bool changed
= true;
3146 TextureUnit
& unit
= texture_units_
[active_texture_unit_
];
3149 if (unit
.bound_texture_2d
!= texture
) {
3150 unit
.bound_texture_2d
= texture
;
3154 case GL_TEXTURE_CUBE_MAP
:
3155 if (unit
.bound_texture_cube_map
!= texture
) {
3156 unit
.bound_texture_cube_map
= texture
;
3160 case GL_TEXTURE_EXTERNAL_OES
:
3161 if (unit
.bound_texture_external_oes
!= texture
) {
3162 unit
.bound_texture_external_oes
= texture
;
3170 // TODO(gman): See note #2 above.
3172 GetIdHandler(id_namespaces::kTextures
)->MarkAsUsedForBind(
3173 this, target
, texture
, &GLES2Implementation::BindTextureStub
);
3177 void GLES2Implementation::BindTextureStub(GLenum target
, GLuint texture
) {
3178 helper_
->BindTexture(target
, texture
);
3179 if (share_group_
->bind_generates_resource())
3180 helper_
->CommandBufferHelper::Flush();
3183 void GLES2Implementation::BindTransformFeedbackHelper(
3184 GLenum target
, GLuint transformfeedback
) {
3185 helper_
->BindTransformFeedback(target
, transformfeedback
);
3188 void GLES2Implementation::BindVertexArrayOESHelper(GLuint array
) {
3189 bool changed
= false;
3190 if (vertex_array_object_manager_
->BindVertexArray(array
, &changed
)) {
3192 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
3193 // because unlike other resources VertexArrayObject ids must
3194 // be generated by GenVertexArrays. A random id to Bind will not
3195 // generate a new object.
3196 helper_
->BindVertexArrayOES(array
);
3200 GL_INVALID_OPERATION
, "glBindVertexArrayOES",
3201 "id was not generated with glGenVertexArrayOES");
3205 void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target
,
3206 GLuint valuebuffer
) {
3207 bool changed
= false;
3209 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM
:
3210 if (bound_valuebuffer_
!= valuebuffer
) {
3211 bound_valuebuffer_
= valuebuffer
;
3219 // TODO(gman): See note #2 above.
3221 GetIdHandler(id_namespaces::kValuebuffers
)->MarkAsUsedForBind(
3222 this, target
, valuebuffer
,
3223 &GLES2Implementation::BindValuebufferCHROMIUMStub
);
3227 void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target
,
3228 GLuint valuebuffer
) {
3229 helper_
->BindValuebufferCHROMIUM(target
, valuebuffer
);
3230 if (share_group_
->bind_generates_resource())
3231 helper_
->CommandBufferHelper::Flush();
3234 void GLES2Implementation::UseProgramHelper(GLuint program
) {
3235 if (current_program_
!= program
) {
3236 current_program_
= program
;
3237 helper_
->UseProgram(program
);
3241 bool GLES2Implementation::IsBufferReservedId(GLuint id
) {
3242 return vertex_array_object_manager_
->IsReservedId(id
);
3245 void GLES2Implementation::DeleteBuffersHelper(
3246 GLsizei n
, const GLuint
* buffers
) {
3247 if (!GetIdHandler(id_namespaces::kBuffers
)->FreeIds(
3248 this, n
, buffers
, &GLES2Implementation::DeleteBuffersStub
)) {
3251 "glDeleteBuffers", "id not created by this context.");
3254 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
3255 if (buffers
[ii
] == bound_array_buffer_id_
) {
3256 bound_array_buffer_id_
= 0;
3258 vertex_array_object_manager_
->UnbindBuffer(buffers
[ii
]);
3260 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffers
[ii
]);
3262 RemoveTransferBuffer(buffer
);
3264 if (buffers
[ii
] == bound_pixel_unpack_transfer_buffer_id_
) {
3265 bound_pixel_unpack_transfer_buffer_id_
= 0;
3270 void GLES2Implementation::DeleteBuffersStub(
3271 GLsizei n
, const GLuint
* buffers
) {
3272 helper_
->DeleteBuffersImmediate(n
, buffers
);
3276 void GLES2Implementation::DeleteFramebuffersHelper(
3277 GLsizei n
, const GLuint
* framebuffers
) {
3278 if (!GetIdHandler(id_namespaces::kFramebuffers
)->FreeIds(
3279 this, n
, framebuffers
, &GLES2Implementation::DeleteFramebuffersStub
)) {
3282 "glDeleteFramebuffers", "id not created by this context.");
3285 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
3286 if (framebuffers
[ii
] == bound_framebuffer_
) {
3287 bound_framebuffer_
= 0;
3289 if (framebuffers
[ii
] == bound_read_framebuffer_
) {
3290 bound_read_framebuffer_
= 0;
3295 void GLES2Implementation::DeleteFramebuffersStub(
3296 GLsizei n
, const GLuint
* framebuffers
) {
3297 helper_
->DeleteFramebuffersImmediate(n
, framebuffers
);
3300 void GLES2Implementation::DeleteRenderbuffersHelper(
3301 GLsizei n
, const GLuint
* renderbuffers
) {
3302 if (!GetIdHandler(id_namespaces::kRenderbuffers
)->FreeIds(
3303 this, n
, renderbuffers
, &GLES2Implementation::DeleteRenderbuffersStub
)) {
3306 "glDeleteRenderbuffers", "id not created by this context.");
3309 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
3310 if (renderbuffers
[ii
] == bound_renderbuffer_
) {
3311 bound_renderbuffer_
= 0;
3316 void GLES2Implementation::DeleteRenderbuffersStub(
3317 GLsizei n
, const GLuint
* renderbuffers
) {
3318 helper_
->DeleteRenderbuffersImmediate(n
, renderbuffers
);
3321 void GLES2Implementation::DeleteTexturesHelper(
3322 GLsizei n
, const GLuint
* textures
) {
3323 if (!GetIdHandler(id_namespaces::kTextures
)->FreeIds(
3324 this, n
, textures
, &GLES2Implementation::DeleteTexturesStub
)) {
3327 "glDeleteTextures", "id not created by this context.");
3330 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
3331 for (GLint tt
= 0; tt
< capabilities_
.max_combined_texture_image_units
;
3333 TextureUnit
& unit
= texture_units_
[tt
];
3334 if (textures
[ii
] == unit
.bound_texture_2d
) {
3335 unit
.bound_texture_2d
= 0;
3337 if (textures
[ii
] == unit
.bound_texture_cube_map
) {
3338 unit
.bound_texture_cube_map
= 0;
3340 if (textures
[ii
] == unit
.bound_texture_external_oes
) {
3341 unit
.bound_texture_external_oes
= 0;
3347 void GLES2Implementation::DeleteTexturesStub(GLsizei n
,
3348 const GLuint
* textures
) {
3349 helper_
->DeleteTexturesImmediate(n
, textures
);
3352 void GLES2Implementation::DeleteVertexArraysOESHelper(
3353 GLsizei n
, const GLuint
* arrays
) {
3354 vertex_array_object_manager_
->DeleteVertexArrays(n
, arrays
);
3355 if (!GetIdHandler(id_namespaces::kVertexArrays
)->FreeIds(
3356 this, n
, arrays
, &GLES2Implementation::DeleteVertexArraysOESStub
)) {
3359 "glDeleteVertexArraysOES", "id not created by this context.");
3364 void GLES2Implementation::DeleteVertexArraysOESStub(
3365 GLsizei n
, const GLuint
* arrays
) {
3366 helper_
->DeleteVertexArraysOESImmediate(n
, arrays
);
3369 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
3371 const GLuint
* valuebuffers
) {
3372 if (!GetIdHandler(id_namespaces::kValuebuffers
)
3373 ->FreeIds(this, n
, valuebuffers
,
3374 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub
)) {
3375 SetGLError(GL_INVALID_VALUE
, "glDeleteValuebuffersCHROMIUM",
3376 "id not created by this context.");
3379 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
3380 if (valuebuffers
[ii
] == bound_valuebuffer_
) {
3381 bound_valuebuffer_
= 0;
3386 void GLES2Implementation::DeleteSamplersStub(
3387 GLsizei n
, const GLuint
* samplers
) {
3388 helper_
->DeleteSamplersImmediate(n
, samplers
);
3391 void GLES2Implementation::DeleteSamplersHelper(
3392 GLsizei n
, const GLuint
* samplers
) {
3393 if (!GetIdHandler(id_namespaces::kSamplers
)->FreeIds(
3394 this, n
, samplers
, &GLES2Implementation::DeleteSamplersStub
)) {
3397 "glDeleteSamplers", "id not created by this context.");
3402 void GLES2Implementation::DeleteTransformFeedbacksStub(
3403 GLsizei n
, const GLuint
* transformfeedbacks
) {
3404 helper_
->DeleteTransformFeedbacksImmediate(n
, transformfeedbacks
);
3407 void GLES2Implementation::DeleteTransformFeedbacksHelper(
3408 GLsizei n
, const GLuint
* transformfeedbacks
) {
3409 if (!GetIdHandler(id_namespaces::kTransformFeedbacks
)->FreeIds(
3410 this, n
, transformfeedbacks
,
3411 &GLES2Implementation::DeleteTransformFeedbacksStub
)) {
3414 "glDeleteTransformFeedbacks", "id not created by this context.");
3419 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
3421 const GLuint
* valuebuffers
) {
3422 helper_
->DeleteValuebuffersCHROMIUMImmediate(n
, valuebuffers
);
3425 void GLES2Implementation::DisableVertexAttribArray(GLuint index
) {
3426 GPU_CLIENT_SINGLE_THREAD_CHECK();
3428 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index
<< ")");
3429 vertex_array_object_manager_
->SetAttribEnable(index
, false);
3430 helper_
->DisableVertexAttribArray(index
);
3434 void GLES2Implementation::EnableVertexAttribArray(GLuint index
) {
3435 GPU_CLIENT_SINGLE_THREAD_CHECK();
3436 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
3438 vertex_array_object_manager_
->SetAttribEnable(index
, true);
3439 helper_
->EnableVertexAttribArray(index
);
3443 void GLES2Implementation::DrawArrays(GLenum mode
, GLint first
, GLsizei count
) {
3444 GPU_CLIENT_SINGLE_THREAD_CHECK();
3445 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
3446 << GLES2Util::GetStringDrawMode(mode
) << ", "
3447 << first
<< ", " << count
<< ")");
3449 SetGLError(GL_INVALID_VALUE
, "glDrawArrays", "count < 0");
3452 bool simulated
= false;
3453 if (!vertex_array_object_manager_
->SetupSimulatedClientSideBuffers(
3454 "glDrawArrays", this, helper_
, first
+ count
, 0, &simulated
)) {
3457 helper_
->DrawArrays(mode
, first
, count
);
3458 RestoreArrayBuffer(simulated
);
3462 void GLES2Implementation::GetVertexAttribfv(
3463 GLuint index
, GLenum pname
, GLfloat
* params
) {
3464 GPU_CLIENT_SINGLE_THREAD_CHECK();
3465 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
3467 << GLES2Util::GetStringVertexAttribute(pname
) << ", "
3468 << static_cast<const void*>(params
) << ")");
3470 if (vertex_array_object_manager_
->GetVertexAttrib(index
, pname
, &value
)) {
3471 *params
= static_cast<float>(value
);
3474 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
3475 typedef cmds::GetVertexAttribfv::Result Result
;
3476 Result
* result
= GetResultAs
<Result
*>();
3480 result
->SetNumResults(0);
3481 helper_
->GetVertexAttribfv(
3482 index
, pname
, GetResultShmId(), GetResultShmOffset());
3484 result
->CopyResult(params
);
3485 GPU_CLIENT_LOG_CODE_BLOCK({
3486 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
3487 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
3493 void GLES2Implementation::GetVertexAttribiv(
3494 GLuint index
, GLenum pname
, GLint
* params
) {
3495 GPU_CLIENT_SINGLE_THREAD_CHECK();
3496 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
3498 << GLES2Util::GetStringVertexAttribute(pname
) << ", "
3499 << static_cast<const void*>(params
) << ")");
3501 if (vertex_array_object_manager_
->GetVertexAttrib(index
, pname
, &value
)) {
3505 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
3506 typedef cmds::GetVertexAttribiv::Result Result
;
3507 Result
* result
= GetResultAs
<Result
*>();
3511 result
->SetNumResults(0);
3512 helper_
->GetVertexAttribiv(
3513 index
, pname
, GetResultShmId(), GetResultShmOffset());
3515 result
->CopyResult(params
);
3516 GPU_CLIENT_LOG_CODE_BLOCK({
3517 for (int32 i
= 0; i
< result
->GetNumResults(); ++i
) {
3518 GPU_CLIENT_LOG(" " << i
<< ": " << result
->GetData()[i
]);
3524 void GLES2Implementation::Swap() {
3528 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect
& sub_buffer
) {
3529 PostSubBufferCHROMIUM(
3530 sub_buffer
.x(), sub_buffer
.y(), sub_buffer
.width(), sub_buffer
.height());
3533 static GLenum
GetGLESOverlayTransform(gfx::OverlayTransform plane_transform
) {
3534 switch (plane_transform
) {
3535 case gfx::OVERLAY_TRANSFORM_INVALID
:
3537 case gfx::OVERLAY_TRANSFORM_NONE
:
3538 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM
;
3539 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL
:
3540 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM
;
3541 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL
:
3542 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM
;
3543 case gfx::OVERLAY_TRANSFORM_ROTATE_90
:
3544 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM
;
3545 case gfx::OVERLAY_TRANSFORM_ROTATE_180
:
3546 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM
;
3547 case gfx::OVERLAY_TRANSFORM_ROTATE_270
:
3548 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM
;
3551 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM
;
3554 void GLES2Implementation::ScheduleOverlayPlane(
3556 gfx::OverlayTransform plane_transform
,
3557 unsigned overlay_texture_id
,
3558 const gfx::Rect
& display_bounds
,
3559 const gfx::RectF
& uv_rect
) {
3560 ScheduleOverlayPlaneCHROMIUM(plane_z_order
,
3561 GetGLESOverlayTransform(plane_transform
),
3565 display_bounds
.width(),
3566 display_bounds
.height(),
3573 GLboolean
GLES2Implementation::EnableFeatureCHROMIUM(
3574 const char* feature
) {
3575 GPU_CLIENT_SINGLE_THREAD_CHECK();
3576 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
3578 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
3579 typedef cmds::EnableFeatureCHROMIUM::Result Result
;
3580 Result
* result
= GetResultAs
<Result
*>();
3585 SetBucketAsCString(kResultBucketId
, feature
);
3586 helper_
->EnableFeatureCHROMIUM(
3587 kResultBucketId
, GetResultShmId(), GetResultShmOffset());
3589 helper_
->SetBucketSize(kResultBucketId
, 0);
3590 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result
));
3591 return *result
!= 0;
3594 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
3595 GLuint target
, GLintptr offset
, GLsizeiptr size
, GLenum access
) {
3596 GPU_CLIENT_SINGLE_THREAD_CHECK();
3597 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
3598 << target
<< ", " << offset
<< ", " << size
<< ", "
3599 << GLES2Util::GetStringEnum(access
) << ")");
3600 // NOTE: target is NOT checked because the service will check it
3601 // and we don't know what targets are valid.
3602 if (access
!= GL_WRITE_ONLY
) {
3603 SetGLErrorInvalidEnum(
3604 "glMapBufferSubDataCHROMIUM", access
, "access");
3607 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size
) ||
3608 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset
)) {
3613 unsigned int shm_offset
;
3614 void* mem
= mapped_memory_
->Alloc(size
, &shm_id
, &shm_offset
);
3616 SetGLError(GL_OUT_OF_MEMORY
, "glMapBufferSubDataCHROMIUM", "out of memory");
3620 std::pair
<MappedBufferMap::iterator
, bool> result
=
3621 mapped_buffers_
.insert(std::make_pair(
3624 access
, shm_id
, mem
, shm_offset
, target
, offset
, size
)));
3625 DCHECK(result
.second
);
3626 GPU_CLIENT_LOG(" returned " << mem
);
3630 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem
) {
3631 GPU_CLIENT_SINGLE_THREAD_CHECK();
3633 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem
<< ")");
3634 MappedBufferMap::iterator it
= mapped_buffers_
.find(mem
);
3635 if (it
== mapped_buffers_
.end()) {
3637 GL_INVALID_VALUE
, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
3640 const MappedBuffer
& mb
= it
->second
;
3641 helper_
->BufferSubData(
3642 mb
.target
, mb
.offset
, mb
.size
, mb
.shm_id
, mb
.shm_offset
);
3643 mapped_memory_
->FreePendingToken(mb
.shm_memory
, helper_
->InsertToken());
3644 mapped_buffers_
.erase(it
);
3648 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
3658 GPU_CLIENT_SINGLE_THREAD_CHECK();
3659 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
3660 << target
<< ", " << level
<< ", "
3661 << xoffset
<< ", " << yoffset
<< ", "
3662 << width
<< ", " << height
<< ", "
3663 << GLES2Util::GetStringTextureFormat(format
) << ", "
3664 << GLES2Util::GetStringPixelType(type
) << ", "
3665 << GLES2Util::GetStringEnum(access
) << ")");
3666 if (access
!= GL_WRITE_ONLY
) {
3667 SetGLErrorInvalidEnum(
3668 "glMapTexSubImage2DCHROMIUM", access
, "access");
3671 // NOTE: target is NOT checked because the service will check it
3672 // and we don't know what targets are valid.
3673 if (level
< 0 || xoffset
< 0 || yoffset
< 0 || width
< 0 || height
< 0) {
3675 GL_INVALID_VALUE
, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
3679 if (!GLES2Util::ComputeImageDataSizes(
3680 width
, height
, 1, format
, type
, unpack_alignment_
, &size
, NULL
, NULL
)) {
3682 GL_INVALID_VALUE
, "glMapTexSubImage2DCHROMIUM", "image size too large");
3686 unsigned int shm_offset
;
3687 void* mem
= mapped_memory_
->Alloc(size
, &shm_id
, &shm_offset
);
3689 SetGLError(GL_OUT_OF_MEMORY
, "glMapTexSubImage2DCHROMIUM", "out of memory");
3693 std::pair
<MappedTextureMap::iterator
, bool> result
=
3694 mapped_textures_
.insert(std::make_pair(
3697 access
, shm_id
, mem
, shm_offset
,
3698 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
)));
3699 DCHECK(result
.second
);
3700 GPU_CLIENT_LOG(" returned " << mem
);
3704 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem
) {
3705 GPU_CLIENT_SINGLE_THREAD_CHECK();
3707 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem
<< ")");
3708 MappedTextureMap::iterator it
= mapped_textures_
.find(mem
);
3709 if (it
== mapped_textures_
.end()) {
3711 GL_INVALID_VALUE
, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
3714 const MappedTexture
& mt
= it
->second
;
3715 helper_
->TexSubImage2D(
3716 mt
.target
, mt
.level
, mt
.xoffset
, mt
.yoffset
, mt
.width
, mt
.height
,
3717 mt
.format
, mt
.type
, mt
.shm_id
, mt
.shm_offset
, GL_FALSE
);
3718 mapped_memory_
->FreePendingToken(mt
.shm_memory
, helper_
->InsertToken());
3719 mapped_textures_
.erase(it
);
3723 void GLES2Implementation::ResizeCHROMIUM(GLuint width
, GLuint height
,
3724 float scale_factor
) {
3725 GPU_CLIENT_SINGLE_THREAD_CHECK();
3726 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
3727 << width
<< ", " << height
<< ", " << scale_factor
<< ")");
3728 helper_
->ResizeCHROMIUM(width
, height
, scale_factor
);
3732 const GLchar
* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
3733 GPU_CLIENT_SINGLE_THREAD_CHECK();
3734 GPU_CLIENT_LOG("[" << GetLogPrefix()
3735 << "] glGetRequestableExtensionsCHROMIUM()");
3737 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
3738 const char* result
= NULL
;
3739 // Clear the bucket so if the command fails nothing will be in it.
3740 helper_
->SetBucketSize(kResultBucketId
, 0);
3741 helper_
->GetRequestableExtensionsCHROMIUM(kResultBucketId
);
3743 if (GetBucketAsString(kResultBucketId
, &str
)) {
3744 // The set of requestable extensions shrinks as we enable
3745 // them. Because we don't know when the client will stop referring
3746 // to a previous one it queries (see GetString) we need to cache
3747 // the unique results.
3748 std::set
<std::string
>::const_iterator sit
=
3749 requestable_extensions_set_
.find(str
);
3750 if (sit
!= requestable_extensions_set_
.end()) {
3751 result
= sit
->c_str();
3753 std::pair
<std::set
<std::string
>::const_iterator
, bool> insert_result
=
3754 requestable_extensions_set_
.insert(str
);
3755 DCHECK(insert_result
.second
);
3756 result
= insert_result
.first
->c_str();
3759 GPU_CLIENT_LOG(" returned " << result
);
3760 return reinterpret_cast<const GLchar
*>(result
);
3763 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
3764 // with VirtualGL contexts.
3765 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension
) {
3766 GPU_CLIENT_SINGLE_THREAD_CHECK();
3767 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
3768 << extension
<< ")");
3769 SetBucketAsCString(kResultBucketId
, extension
);
3770 helper_
->RequestExtensionCHROMIUM(kResultBucketId
);
3771 helper_
->SetBucketSize(kResultBucketId
, 0);
3773 struct ExtensionCheck
{
3774 const char* extension
;
3775 ExtensionStatus
* status
;
3777 const ExtensionCheck checks
[] = {
3779 "GL_ANGLE_pack_reverse_row_order",
3780 &angle_pack_reverse_row_order_status_
,
3783 "GL_CHROMIUM_framebuffer_multisample",
3784 &chromium_framebuffer_multisample_
,
3787 const size_t kNumChecks
= sizeof(checks
)/sizeof(checks
[0]);
3788 for (size_t ii
= 0; ii
< kNumChecks
; ++ii
) {
3789 const ExtensionCheck
& check
= checks
[ii
];
3790 if (*check
.status
== kUnavailableExtensionStatus
&&
3791 !strcmp(extension
, check
.extension
)) {
3792 *check
.status
= kUnknownExtensionStatus
;
3797 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
3798 GPU_CLIENT_SINGLE_THREAD_CHECK();
3799 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
3800 // Wait if this would add too many rate limit tokens.
3801 if (rate_limit_tokens_
.size() == kMaxSwapBuffers
) {
3802 helper_
->WaitForToken(rate_limit_tokens_
.front());
3803 rate_limit_tokens_
.pop();
3805 rate_limit_tokens_
.push(helper_
->InsertToken());
3808 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3809 GLuint program
, std::vector
<int8
>* result
) {
3811 // Clear the bucket so if the command fails nothing will be in it.
3812 helper_
->SetBucketSize(kResultBucketId
, 0);
3813 helper_
->GetProgramInfoCHROMIUM(program
, kResultBucketId
);
3814 GetBucketContents(kResultBucketId
, result
);
3817 void GLES2Implementation::GetProgramInfoCHROMIUM(
3818 GLuint program
, GLsizei bufsize
, GLsizei
* size
, void* info
) {
3819 GPU_CLIENT_SINGLE_THREAD_CHECK();
3822 GL_INVALID_VALUE
, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3826 SetGLError(GL_INVALID_VALUE
, "glProgramInfoCHROMIUM", "size is null.");
3829 // Make sure they've set size to 0 else the value will be undefined on
3831 DCHECK_EQ(0, *size
);
3832 std::vector
<int8
> result
;
3833 GetProgramInfoCHROMIUMHelper(program
, &result
);
3834 if (result
.empty()) {
3837 *size
= result
.size();
3841 if (static_cast<size_t>(bufsize
) < result
.size()) {
3842 SetGLError(GL_INVALID_OPERATION
,
3843 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3846 memcpy(info
, &result
[0], result
.size());
3849 void GLES2Implementation::GetUniformBlocksCHROMIUMHelper(
3850 GLuint program
, std::vector
<int8
>* result
) {
3852 // Clear the bucket so if the command fails nothing will be in it.
3853 helper_
->SetBucketSize(kResultBucketId
, 0);
3854 helper_
->GetUniformBlocksCHROMIUM(program
, kResultBucketId
);
3855 GetBucketContents(kResultBucketId
, result
);
3858 void GLES2Implementation::GetUniformBlocksCHROMIUM(
3859 GLuint program
, GLsizei bufsize
, GLsizei
* size
, void* info
) {
3860 GPU_CLIENT_SINGLE_THREAD_CHECK();
3863 GL_INVALID_VALUE
, "glGetUniformBlocksCHROMIUM", "bufsize less than 0.");
3867 SetGLError(GL_INVALID_VALUE
, "glGetUniformBlocksCHROMIUM", "size is null.");
3870 // Make sure they've set size to 0 else the value will be undefined on
3872 DCHECK_EQ(0, *size
);
3873 std::vector
<int8
> result
;
3874 GetUniformBlocksCHROMIUMHelper(program
, &result
);
3875 if (result
.empty()) {
3878 *size
= result
.size();
3882 if (static_cast<size_t>(bufsize
) < result
.size()) {
3883 SetGLError(GL_INVALID_OPERATION
, "glGetUniformBlocksCHROMIUM",
3884 "bufsize is too small for result.");
3887 memcpy(info
, &result
[0], result
.size());
3890 void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
3891 GLuint program
, std::vector
<int8
>* result
) {
3893 // Clear the bucket so if the command fails nothing will be in it.
3894 helper_
->SetBucketSize(kResultBucketId
, 0);
3895 helper_
->GetUniformsES3CHROMIUM(program
, kResultBucketId
);
3896 GetBucketContents(kResultBucketId
, result
);
3899 void GLES2Implementation::GetUniformsES3CHROMIUM(
3900 GLuint program
, GLsizei bufsize
, GLsizei
* size
, void* info
) {
3901 GPU_CLIENT_SINGLE_THREAD_CHECK();
3904 GL_INVALID_VALUE
, "glGetUniformsES3CHROMIUM", "bufsize less than 0.");
3908 SetGLError(GL_INVALID_VALUE
, "glGetUniformsES3CHROMIUM", "size is null.");
3911 // Make sure they've set size to 0 else the value will be undefined on
3913 DCHECK_EQ(0, *size
);
3914 std::vector
<int8
> result
;
3915 GetUniformsES3CHROMIUMHelper(program
, &result
);
3916 if (result
.empty()) {
3919 *size
= result
.size();
3923 if (static_cast<size_t>(bufsize
) < result
.size()) {
3924 SetGLError(GL_INVALID_OPERATION
,
3925 "glGetUniformsES3CHROMIUM", "bufsize is too small for result.");
3928 memcpy(info
, &result
[0], result
.size());
3931 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
3932 GLuint program
, std::vector
<int8
>* result
) {
3934 // Clear the bucket so if the command fails nothing will be in it.
3935 helper_
->SetBucketSize(kResultBucketId
, 0);
3936 helper_
->GetTransformFeedbackVaryingsCHROMIUM(program
, kResultBucketId
);
3937 GetBucketContents(kResultBucketId
, result
);
3940 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(
3941 GLuint program
, GLsizei bufsize
, GLsizei
* size
, void* info
) {
3942 GPU_CLIENT_SINGLE_THREAD_CHECK();
3944 SetGLError(GL_INVALID_VALUE
, "glGetTransformFeedbackVaryingsCHROMIUM",
3945 "bufsize less than 0.");
3949 SetGLError(GL_INVALID_VALUE
, "glGetTransformFeedbackVaryingsCHROMIUM",
3953 // Make sure they've set size to 0 else the value will be undefined on
3955 DCHECK_EQ(0, *size
);
3956 std::vector
<int8
> result
;
3957 GetTransformFeedbackVaryingsCHROMIUMHelper(program
, &result
);
3958 if (result
.empty()) {
3961 *size
= result
.size();
3965 if (static_cast<size_t>(bufsize
) < result
.size()) {
3966 SetGLError(GL_INVALID_OPERATION
, "glGetTransformFeedbackVaryingsCHROMIUM",
3967 "bufsize is too small for result.");
3970 memcpy(info
, &result
[0], result
.size());
3973 GLuint
GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture
) {
3974 GPU_CLIENT_SINGLE_THREAD_CHECK();
3975 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
3977 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
3978 helper_
->CommandBufferHelper::Flush();
3979 return gpu_control_
->CreateStreamTexture(texture
);
3982 void GLES2Implementation::PostSubBufferCHROMIUM(
3983 GLint x
, GLint y
, GLint width
, GLint height
) {
3984 GPU_CLIENT_SINGLE_THREAD_CHECK();
3985 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
3986 << x
<< ", " << y
<< ", " << width
<< ", " << height
<< ")");
3987 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
3988 "width", width
, "height", height
);
3990 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
3991 swap_buffers_tokens_
.push(helper_
->InsertToken());
3992 helper_
->PostSubBufferCHROMIUM(x
, y
, width
, height
);
3993 helper_
->CommandBufferHelper::Flush();
3994 if (swap_buffers_tokens_
.size() > kMaxSwapBuffers
+ 1) {
3995 helper_
->WaitForToken(swap_buffers_tokens_
.front());
3996 swap_buffers_tokens_
.pop();
4000 void GLES2Implementation::DeleteQueriesEXTHelper(
4001 GLsizei n
, const GLuint
* queries
) {
4002 for (GLsizei ii
= 0; ii
< n
; ++ii
) {
4003 query_tracker_
->RemoveQuery(queries
[ii
]);
4004 query_id_allocator_
->FreeID(queries
[ii
]);
4007 helper_
->DeleteQueriesEXTImmediate(n
, queries
);
4010 GLboolean
GLES2Implementation::IsQueryEXT(GLuint id
) {
4011 GPU_CLIENT_SINGLE_THREAD_CHECK();
4012 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id
<< ")");
4014 // TODO(gman): To be spec compliant IDs from other contexts sharing
4015 // resources need to return true here even though you can't share
4016 // queries across contexts?
4017 return query_tracker_
->GetQuery(id
) != NULL
;
4020 void GLES2Implementation::BeginQueryEXT(GLenum target
, GLuint id
) {
4021 GPU_CLIENT_SINGLE_THREAD_CHECK();
4022 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
4023 << GLES2Util::GetStringQueryTarget(target
)
4024 << ", " << id
<< ")");
4026 // if any outstanding queries INV_OP
4027 QueryMap::iterator it
= current_queries_
.find(target
);
4028 if (it
!= current_queries_
.end()) {
4030 GL_INVALID_OPERATION
, "glBeginQueryEXT", "query already in progress");
4036 SetGLError(GL_INVALID_OPERATION
, "glBeginQueryEXT", "id is 0");
4040 // if not GENned INV_OPERATION
4041 if (!query_id_allocator_
->InUse(id
)) {
4042 SetGLError(GL_INVALID_OPERATION
, "glBeginQueryEXT", "invalid id");
4046 // if id does not have an object
4047 QueryTracker::Query
* query
= query_tracker_
->GetQuery(id
);
4049 query
= query_tracker_
->CreateQuery(id
, target
);
4051 SetGLError(GL_OUT_OF_MEMORY
,
4053 "transfer buffer allocation failed");
4056 } else if (query
->target() != target
) {
4058 GL_INVALID_OPERATION
, "glBeginQueryEXT", "target does not match");
4062 current_queries_
[target
] = query
;
4068 void GLES2Implementation::EndQueryEXT(GLenum target
) {
4069 GPU_CLIENT_SINGLE_THREAD_CHECK();
4070 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
4071 << GLES2Util::GetStringQueryTarget(target
) << ")");
4072 // Don't do anything if the context is lost.
4073 if (helper_
->IsContextLost()) {
4077 QueryMap::iterator it
= current_queries_
.find(target
);
4078 if (it
== current_queries_
.end()) {
4079 SetGLError(GL_INVALID_OPERATION
, "glEndQueryEXT", "no active query");
4083 QueryTracker::Query
* query
= it
->second
;
4085 current_queries_
.erase(it
);
4089 void GLES2Implementation::GetQueryivEXT(
4090 GLenum target
, GLenum pname
, GLint
* params
) {
4091 GPU_CLIENT_SINGLE_THREAD_CHECK();
4092 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
4093 << GLES2Util::GetStringQueryTarget(target
) << ", "
4094 << GLES2Util::GetStringQueryParameter(pname
) << ", "
4095 << static_cast<const void*>(params
) << ")");
4097 if (pname
!= GL_CURRENT_QUERY_EXT
) {
4098 SetGLErrorInvalidEnum("glGetQueryivEXT", pname
, "pname");
4101 QueryMap::iterator it
= current_queries_
.find(target
);
4102 if (it
!= current_queries_
.end()) {
4103 QueryTracker::Query
* query
= it
->second
;
4104 *params
= query
->id();
4108 GPU_CLIENT_LOG(" " << *params
);
4112 void GLES2Implementation::GetQueryObjectuivEXT(
4113 GLuint id
, GLenum pname
, GLuint
* params
) {
4114 GPU_CLIENT_SINGLE_THREAD_CHECK();
4115 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id
<< ", "
4116 << GLES2Util::GetStringQueryObjectParameter(pname
) << ", "
4117 << static_cast<const void*>(params
) << ")");
4119 QueryTracker::Query
* query
= query_tracker_
->GetQuery(id
);
4121 SetGLError(GL_INVALID_OPERATION
, "glQueryObjectuivEXT", "unknown query id");
4125 QueryMap::iterator it
= current_queries_
.find(query
->target());
4126 if (it
!= current_queries_
.end()) {
4128 GL_INVALID_OPERATION
,
4129 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
4133 if (query
->NeverUsed()) {
4135 GL_INVALID_OPERATION
,
4136 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
4141 case GL_QUERY_RESULT_EXT
:
4142 if (!query
->CheckResultsAvailable(helper_
)) {
4143 helper_
->WaitForToken(query
->token());
4144 if (!query
->CheckResultsAvailable(helper_
)) {
4146 CHECK(query
->CheckResultsAvailable(helper_
));
4149 *params
= query
->GetResult();
4151 case GL_QUERY_RESULT_AVAILABLE_EXT
:
4152 *params
= query
->CheckResultsAvailable(helper_
);
4155 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname
, "pname");
4158 GPU_CLIENT_LOG(" " << *params
);
4162 void GLES2Implementation::DrawArraysInstancedANGLE(
4163 GLenum mode
, GLint first
, GLsizei count
, GLsizei primcount
) {
4164 GPU_CLIENT_SINGLE_THREAD_CHECK();
4165 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
4166 << GLES2Util::GetStringDrawMode(mode
) << ", "
4167 << first
<< ", " << count
<< ", " << primcount
<< ")");
4169 SetGLError(GL_INVALID_VALUE
, "glDrawArraysInstancedANGLE", "count < 0");
4172 if (primcount
< 0) {
4173 SetGLError(GL_INVALID_VALUE
, "glDrawArraysInstancedANGLE", "primcount < 0");
4176 if (primcount
== 0) {
4179 bool simulated
= false;
4180 if (!vertex_array_object_manager_
->SetupSimulatedClientSideBuffers(
4181 "glDrawArraysInstancedANGLE", this, helper_
, first
+ count
, primcount
,
4185 helper_
->DrawArraysInstancedANGLE(mode
, first
, count
, primcount
);
4186 RestoreArrayBuffer(simulated
);
4190 void GLES2Implementation::DrawElementsInstancedANGLE(
4191 GLenum mode
, GLsizei count
, GLenum type
, const void* indices
,
4192 GLsizei primcount
) {
4193 GPU_CLIENT_SINGLE_THREAD_CHECK();
4194 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
4195 << GLES2Util::GetStringDrawMode(mode
) << ", "
4197 << GLES2Util::GetStringIndexType(type
) << ", "
4198 << static_cast<const void*>(indices
) << ", "
4199 << primcount
<< ")");
4201 SetGLError(GL_INVALID_VALUE
,
4202 "glDrawElementsInstancedANGLE", "count less than 0.");
4208 if (primcount
< 0) {
4209 SetGLError(GL_INVALID_VALUE
,
4210 "glDrawElementsInstancedANGLE", "primcount < 0");
4213 if (primcount
== 0) {
4216 if (vertex_array_object_manager_
->bound_element_array_buffer() != 0 &&
4217 !ValidateOffset("glDrawElementsInstancedANGLE",
4218 reinterpret_cast<GLintptr
>(indices
))) {
4222 bool simulated
= false;
4223 if (!vertex_array_object_manager_
->SetupSimulatedIndexAndClientSideBuffers(
4224 "glDrawElementsInstancedANGLE", this, helper_
, count
, type
, primcount
,
4225 indices
, &offset
, &simulated
)) {
4228 helper_
->DrawElementsInstancedANGLE(mode
, count
, type
, offset
, primcount
);
4229 RestoreElementAndArrayBuffers(simulated
);
4233 void GLES2Implementation::GenMailboxCHROMIUM(
4235 GPU_CLIENT_SINGLE_THREAD_CHECK();
4236 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
4237 << static_cast<const void*>(mailbox
) << ")");
4238 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
4240 gpu::Mailbox result
= gpu::Mailbox::Generate();
4241 memcpy(mailbox
, result
.name
, sizeof(result
.name
));
4244 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target
,
4245 const GLbyte
* data
) {
4246 GPU_CLIENT_SINGLE_THREAD_CHECK();
4247 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
4248 << static_cast<const void*>(data
) << ")");
4249 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
4250 DCHECK(mailbox
.Verify()) << "ProduceTextureCHROMIUM was passed a "
4251 "mailbox that was not generated by "
4252 "GenMailboxCHROMIUM.";
4253 helper_
->ProduceTextureCHROMIUMImmediate(target
, data
);
4257 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
4258 GLuint texture
, GLenum target
, const GLbyte
* data
) {
4259 GPU_CLIENT_SINGLE_THREAD_CHECK();
4260 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
4261 << static_cast<const void*>(data
) << ")");
4262 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
4263 DCHECK(mailbox
.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
4264 "mailbox that was not generated by "
4265 "GenMailboxCHROMIUM.";
4266 helper_
->ProduceTextureDirectCHROMIUMImmediate(texture
, target
, data
);
4270 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target
,
4271 const GLbyte
* data
) {
4272 GPU_CLIENT_SINGLE_THREAD_CHECK();
4273 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
4274 << static_cast<const void*>(data
) << ")");
4275 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
4276 DCHECK(mailbox
.Verify()) << "ConsumeTextureCHROMIUM was passed a "
4277 "mailbox that was not generated by "
4278 "GenMailboxCHROMIUM.";
4279 helper_
->ConsumeTextureCHROMIUMImmediate(target
, data
);
4283 GLuint
GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
4284 GLenum target
, const GLbyte
* data
) {
4285 GPU_CLIENT_SINGLE_THREAD_CHECK();
4286 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
4287 << static_cast<const void*>(data
) << ")");
4288 const Mailbox
& mailbox
= *reinterpret_cast<const Mailbox
*>(data
);
4289 DCHECK(mailbox
.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
4290 "mailbox that was not generated by "
4291 "GenMailboxCHROMIUM.";
4293 GetIdHandler(id_namespaces::kTextures
)->MakeIds(this, 0, 1, &client_id
);
4294 helper_
->CreateAndConsumeTextureCHROMIUMImmediate(target
,
4296 if (share_group_
->bind_generates_resource())
4297 helper_
->CommandBufferHelper::Flush();
4302 void GLES2Implementation::PushGroupMarkerEXT(
4303 GLsizei length
, const GLchar
* marker
) {
4304 GPU_CLIENT_SINGLE_THREAD_CHECK();
4305 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
4306 << length
<< ", " << marker
<< ")");
4312 (length
? std::string(marker
, length
) : std::string(marker
)));
4313 helper_
->PushGroupMarkerEXT(kResultBucketId
);
4314 helper_
->SetBucketSize(kResultBucketId
, 0);
4315 debug_marker_manager_
.PushGroup(
4316 length
? std::string(marker
, length
) : std::string(marker
));
4319 void GLES2Implementation::InsertEventMarkerEXT(
4320 GLsizei length
, const GLchar
* marker
) {
4321 GPU_CLIENT_SINGLE_THREAD_CHECK();
4322 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
4323 << length
<< ", " << marker
<< ")");
4329 (length
? std::string(marker
, length
) : std::string(marker
)));
4330 helper_
->InsertEventMarkerEXT(kResultBucketId
);
4331 helper_
->SetBucketSize(kResultBucketId
, 0);
4332 debug_marker_manager_
.SetMarker(
4333 length
? std::string(marker
, length
) : std::string(marker
));
4336 void GLES2Implementation::PopGroupMarkerEXT() {
4337 GPU_CLIENT_SINGLE_THREAD_CHECK();
4338 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
4339 helper_
->PopGroupMarkerEXT();
4340 debug_marker_manager_
.PopGroup();
4343 void GLES2Implementation::TraceBeginCHROMIUM(
4344 const char* category_name
, const char* trace_name
) {
4345 GPU_CLIENT_SINGLE_THREAD_CHECK();
4346 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
4347 << category_name
<< ", " << trace_name
<< ")");
4348 SetBucketAsCString(kResultBucketId
, category_name
);
4349 SetBucketAsCString(kResultBucketId
+ 1, trace_name
);
4350 helper_
->TraceBeginCHROMIUM(kResultBucketId
, kResultBucketId
+ 1);
4351 helper_
->SetBucketSize(kResultBucketId
, 0);
4352 helper_
->SetBucketSize(kResultBucketId
+ 1, 0);
4353 current_trace_stack_
++;
4356 void GLES2Implementation::TraceEndCHROMIUM() {
4357 GPU_CLIENT_SINGLE_THREAD_CHECK();
4358 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
4359 if (current_trace_stack_
== 0) {
4360 SetGLError(GL_INVALID_OPERATION
, "glTraceEndCHROMIUM",
4361 "missing begin trace");
4364 helper_
->TraceEndCHROMIUM();
4365 current_trace_stack_
--;
4368 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target
, GLenum access
) {
4369 GPU_CLIENT_SINGLE_THREAD_CHECK();
4370 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
4371 << target
<< ", " << GLES2Util::GetStringEnum(access
) << ")");
4373 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
:
4374 if (access
!= GL_READ_ONLY
) {
4375 SetGLError(GL_INVALID_ENUM
, "glMapBufferCHROMIUM", "bad access mode");
4379 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
:
4380 if (access
!= GL_WRITE_ONLY
) {
4381 SetGLError(GL_INVALID_ENUM
, "glMapBufferCHROMIUM", "bad access mode");
4387 GL_INVALID_ENUM
, "glMapBufferCHROMIUM", "invalid target");
4391 GetBoundPixelTransferBuffer(target
, "glMapBufferCHROMIUM", &buffer_id
);
4395 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
4397 SetGLError(GL_INVALID_OPERATION
, "glMapBufferCHROMIUM", "invalid buffer");
4400 if (buffer
->mapped()) {
4401 SetGLError(GL_INVALID_OPERATION
, "glMapBufferCHROMIUM", "already mapped");
4404 // Here we wait for previous transfer operations to be finished.
4405 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
4406 // with this method of synchronization. Until this is fixed,
4407 // MapBufferCHROMIUM will not block even if the transfer is not ready
4409 if (buffer
->last_usage_token()) {
4410 helper_
->WaitForToken(buffer
->last_usage_token());
4411 buffer
->set_last_usage_token(0);
4413 buffer
->set_mapped(true);
4415 GPU_CLIENT_LOG(" returned " << buffer
->address());
4417 return buffer
->address();
4420 GLboolean
GLES2Implementation::UnmapBufferCHROMIUM(GLuint target
) {
4421 GPU_CLIENT_SINGLE_THREAD_CHECK();
4423 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target
<< ")");
4425 if (!GetBoundPixelTransferBuffer(target
, "glMapBufferCHROMIUM", &buffer_id
)) {
4426 SetGLError(GL_INVALID_ENUM
, "glUnmapBufferCHROMIUM", "invalid target");
4431 BufferTracker::Buffer
* buffer
= buffer_tracker_
->GetBuffer(buffer_id
);
4433 SetGLError(GL_INVALID_OPERATION
, "glUnmapBufferCHROMIUM", "invalid buffer");
4436 if (!buffer
->mapped()) {
4437 SetGLError(GL_INVALID_OPERATION
, "glUnmapBufferCHROMIUM", "not mapped");
4440 buffer
->set_mapped(false);
4445 bool GLES2Implementation::EnsureAsyncUploadSync() {
4446 if (async_upload_sync_
)
4450 unsigned int shm_offset
;
4451 void* mem
= mapped_memory_
->Alloc(sizeof(AsyncUploadSync
),
4457 async_upload_sync_shm_id_
= shm_id
;
4458 async_upload_sync_shm_offset_
= shm_offset
;
4459 async_upload_sync_
= static_cast<AsyncUploadSync
*>(mem
);
4460 async_upload_sync_
->Reset();
4465 uint32
GLES2Implementation::NextAsyncUploadToken() {
4466 async_upload_token_
++;
4467 if (async_upload_token_
== 0)
4468 async_upload_token_
++;
4469 return async_upload_token_
;
4472 void GLES2Implementation::PollAsyncUploads() {
4473 if (!async_upload_sync_
)
4476 if (helper_
->IsContextLost()) {
4477 DetachedAsyncUploadMemoryList::iterator it
=
4478 detached_async_upload_memory_
.begin();
4479 while (it
!= detached_async_upload_memory_
.end()) {
4480 mapped_memory_
->Free(it
->first
);
4481 it
= detached_async_upload_memory_
.erase(it
);
4486 DetachedAsyncUploadMemoryList::iterator it
=
4487 detached_async_upload_memory_
.begin();
4488 while (it
!= detached_async_upload_memory_
.end()) {
4489 if (HasAsyncUploadTokenPassed(it
->second
)) {
4490 mapped_memory_
->Free(it
->first
);
4491 it
= detached_async_upload_memory_
.erase(it
);
4498 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
4499 // Free all completed unmanaged async uploads buffers.
4502 // Synchronously free rest of the unmanaged async upload buffers.
4503 if (!detached_async_upload_memory_
.empty()) {
4504 WaitAllAsyncTexImage2DCHROMIUM();
4510 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
4511 GLenum target
, GLint level
, GLenum internalformat
, GLsizei width
,
4512 GLsizei height
, GLint border
, GLenum format
, GLenum type
,
4513 const void* pixels
) {
4514 GPU_CLIENT_SINGLE_THREAD_CHECK();
4515 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
4516 << GLES2Util::GetStringTextureTarget(target
) << ", "
4518 << GLES2Util::GetStringTextureInternalFormat(internalformat
) << ", "
4519 << width
<< ", " << height
<< ", " << border
<< ", "
4520 << GLES2Util::GetStringTextureFormat(format
) << ", "
4521 << GLES2Util::GetStringPixelType(type
) << ", "
4522 << static_cast<const void*>(pixels
) << ")");
4523 if (level
< 0 || height
< 0 || width
< 0) {
4524 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "dimension < 0");
4528 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "border != 0");
4532 uint32 unpadded_row_size
;
4533 uint32 padded_row_size
;
4534 if (!GLES2Util::ComputeImageDataSizes(
4535 width
, height
, 1, format
, type
, unpack_alignment_
, &size
,
4536 &unpadded_row_size
, &padded_row_size
)) {
4537 SetGLError(GL_INVALID_VALUE
, "glTexImage2D", "image size too large");
4541 // If there's no data/buffer just issue the AsyncTexImage2D
4542 if (!pixels
&& !bound_pixel_unpack_transfer_buffer_id_
) {
4543 helper_
->AsyncTexImage2DCHROMIUM(
4544 target
, level
, internalformat
, width
, height
, format
, type
,
4549 if (!EnsureAsyncUploadSync()) {
4550 SetGLError(GL_OUT_OF_MEMORY
, "glTexImage2D", "out of memory");
4554 // Otherwise, async uploads require a transfer buffer to be bound.
4555 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
4556 // the buffer before the transfer is finished. (Currently such
4557 // synchronization has to be handled manually.)
4558 GLuint offset
= ToGLuint(pixels
);
4559 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
4560 bound_pixel_unpack_transfer_buffer_id_
,
4561 "glAsyncTexImage2DCHROMIUM", offset
, size
);
4562 if (buffer
&& buffer
->shm_id() != -1) {
4563 uint32 async_token
= NextAsyncUploadToken();
4564 buffer
->set_last_async_upload_token(async_token
);
4565 helper_
->AsyncTexImage2DCHROMIUM(
4566 target
, level
, internalformat
, width
, height
, format
, type
,
4567 buffer
->shm_id(), buffer
->shm_offset() + offset
,
4569 async_upload_sync_shm_id_
, async_upload_sync_shm_offset_
);
4573 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
4574 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
4575 GLsizei height
, GLenum format
, GLenum type
, const void* pixels
) {
4576 GPU_CLIENT_SINGLE_THREAD_CHECK();
4577 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
4578 << GLES2Util::GetStringTextureTarget(target
) << ", "
4580 << xoffset
<< ", " << yoffset
<< ", "
4581 << width
<< ", " << height
<< ", "
4582 << GLES2Util::GetStringTextureFormat(format
) << ", "
4583 << GLES2Util::GetStringPixelType(type
) << ", "
4584 << static_cast<const void*>(pixels
) << ")");
4585 if (level
< 0 || height
< 0 || width
< 0) {
4587 GL_INVALID_VALUE
, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
4592 uint32 unpadded_row_size
;
4593 uint32 padded_row_size
;
4594 if (!GLES2Util::ComputeImageDataSizes(
4595 width
, height
, 1, format
, type
, unpack_alignment_
, &size
,
4596 &unpadded_row_size
, &padded_row_size
)) {
4598 GL_INVALID_VALUE
, "glAsyncTexSubImage2DCHROMIUM", "size to large");
4602 if (!EnsureAsyncUploadSync()) {
4603 SetGLError(GL_OUT_OF_MEMORY
, "glTexImage2D", "out of memory");
4607 // Async uploads require a transfer buffer to be bound.
4608 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
4609 // the buffer before the transfer is finished. (Currently such
4610 // synchronization has to be handled manually.)
4611 GLuint offset
= ToGLuint(pixels
);
4612 BufferTracker::Buffer
* buffer
= GetBoundPixelUnpackTransferBufferIfValid(
4613 bound_pixel_unpack_transfer_buffer_id_
,
4614 "glAsyncTexSubImage2DCHROMIUM", offset
, size
);
4615 if (buffer
&& buffer
->shm_id() != -1) {
4616 uint32 async_token
= NextAsyncUploadToken();
4617 buffer
->set_last_async_upload_token(async_token
);
4618 helper_
->AsyncTexSubImage2DCHROMIUM(
4619 target
, level
, xoffset
, yoffset
, width
, height
, format
, type
,
4620 buffer
->shm_id(), buffer
->shm_offset() + offset
,
4622 async_upload_sync_shm_id_
, async_upload_sync_shm_offset_
);
4626 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target
) {
4627 GPU_CLIENT_SINGLE_THREAD_CHECK();
4628 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
4629 << GLES2Util::GetStringTextureTarget(target
) << ")");
4630 helper_
->WaitAsyncTexImage2DCHROMIUM(target
);
4634 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
4635 GPU_CLIENT_SINGLE_THREAD_CHECK();
4636 GPU_CLIENT_LOG("[" << GetLogPrefix()
4637 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
4638 helper_
->WaitAllAsyncTexImage2DCHROMIUM();
4642 GLuint
GLES2Implementation::InsertSyncPointCHROMIUM() {
4643 GPU_CLIENT_SINGLE_THREAD_CHECK();
4644 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
4645 helper_
->CommandBufferHelper::Flush();
4646 return gpu_control_
->InsertSyncPoint();
4649 GLuint
GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
4650 GPU_CLIENT_SINGLE_THREAD_CHECK();
4651 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
4652 DCHECK(capabilities_
.future_sync_points
);
4653 return gpu_control_
->InsertFutureSyncPoint();
4656 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point
) {
4657 GPU_CLIENT_SINGLE_THREAD_CHECK();
4658 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
4659 << sync_point
<< ")");
4660 DCHECK(capabilities_
.future_sync_points
);
4661 helper_
->CommandBufferHelper::Flush();
4662 gpu_control_
->RetireSyncPoint(sync_point
);
4667 bool ValidImageFormat(GLenum internalformat
) {
4668 switch (internalformat
) {
4677 bool ValidImageUsage(GLenum usage
) {
4679 case GL_MAP_CHROMIUM
:
4680 case GL_SCANOUT_CHROMIUM
:
4689 GLuint
GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer
,
4692 GLenum internalformat
) {
4694 SetGLError(GL_INVALID_VALUE
, "glCreateImageCHROMIUM", "width <= 0");
4699 SetGLError(GL_INVALID_VALUE
, "glCreateImageCHROMIUM", "height <= 0");
4703 if (!ValidImageFormat(internalformat
)) {
4704 SetGLError(GL_INVALID_VALUE
, "glCreateImageCHROMIUM", "invalid format");
4709 gpu_control_
->CreateImage(buffer
, width
, height
, internalformat
);
4711 SetGLError(GL_OUT_OF_MEMORY
, "glCreateImageCHROMIUM", "image_id < 0");
4717 GLuint
GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer
,
4720 GLenum internalformat
) {
4721 GPU_CLIENT_SINGLE_THREAD_CHECK();
4722 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
4723 << ", " << height
<< ", "
4724 << GLES2Util::GetStringImageInternalFormat(internalformat
)
4727 CreateImageCHROMIUMHelper(buffer
, width
, height
, internalformat
);
4732 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id
) {
4733 // Flush the command stream to make sure all pending commands
4734 // that may refer to the image_id are executed on the service side.
4735 helper_
->CommandBufferHelper::Flush();
4736 gpu_control_
->DestroyImage(image_id
);
4739 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id
) {
4740 GPU_CLIENT_SINGLE_THREAD_CHECK();
4741 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
4742 << image_id
<< ")");
4743 DestroyImageCHROMIUMHelper(image_id
);
4747 GLuint
GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
4750 GLenum internalformat
,
4754 GL_INVALID_VALUE
, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
4759 SetGLError(GL_INVALID_VALUE
,
4760 "glCreateGpuMemoryBufferImageCHROMIUM",
4765 if (!ValidImageFormat(internalformat
)) {
4766 SetGLError(GL_INVALID_VALUE
,
4767 "glCreateGpuMemoryBufferImageCHROMIUM",
4772 if (!ValidImageUsage(usage
)) {
4773 SetGLError(GL_INVALID_VALUE
,
4774 "glCreateGpuMemoryBufferImageCHROMIUM",
4779 // Flush the command stream to ensure ordering in case the newly
4780 // returned image_id has recently been in use with a different buffer.
4781 helper_
->CommandBufferHelper::Flush();
4782 int32_t image_id
= gpu_control_
->CreateGpuMemoryBufferImage(
4783 width
, height
, internalformat
, usage
);
4785 SetGLError(GL_OUT_OF_MEMORY
,
4786 "glCreateGpuMemoryBufferImageCHROMIUM",
4793 GLuint
GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
4796 GLenum internalformat
,
4798 GPU_CLIENT_SINGLE_THREAD_CHECK();
4799 GPU_CLIENT_LOG("[" << GetLogPrefix()
4800 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
4801 << ", " << height
<< ", "
4802 << GLES2Util::GetStringImageInternalFormat(internalformat
)
4803 << ", " << GLES2Util::GetStringImageUsage(usage
) << ")");
4804 GLuint image_id
= CreateGpuMemoryBufferImageCHROMIUMHelper(
4805 width
, height
, internalformat
, usage
);
4810 bool GLES2Implementation::ValidateSize(const char* func
, GLsizeiptr size
) {
4812 SetGLError(GL_INVALID_VALUE
, func
, "size < 0");
4815 if (!FitInt32NonNegative
<GLsizeiptr
>(size
)) {
4816 SetGLError(GL_INVALID_OPERATION
, func
, "size more than 32-bit");
4822 bool GLES2Implementation::ValidateOffset(const char* func
, GLintptr offset
) {
4824 SetGLError(GL_INVALID_VALUE
, func
, "offset < 0");
4827 if (!FitInt32NonNegative
<GLintptr
>(offset
)) {
4828 SetGLError(GL_INVALID_OPERATION
, func
, "offset more than 32-bit");
4834 bool GLES2Implementation::GetSamplerParameterfvHelper(
4835 GLuint
/* sampler */, GLenum
/* pname */, GLfloat
* /* params */) {
4836 // TODO(zmo): Implement client side caching.
4840 bool GLES2Implementation::GetSamplerParameterivHelper(
4841 GLuint
/* sampler */, GLenum
/* pname */, GLint
* /* params */) {
4842 // TODO(zmo): Implement client side caching.
4846 bool GLES2Implementation::PackStringsToBucket(GLsizei count
,
4847 const char* const* str
,
4848 const GLint
* length
,
4849 const char* func_name
) {
4850 DCHECK_LE(0, count
);
4851 // Compute the total size.
4852 base::CheckedNumeric
<size_t> total_size
= count
;
4854 total_size
*= sizeof(GLint
);
4855 if (!total_size
.IsValid()) {
4856 SetGLError(GL_INVALID_VALUE
, func_name
, "overflow");
4859 size_t header_size
= total_size
.ValueOrDefault(0);
4860 std::vector
<GLint
> header(count
+ 1);
4861 header
[0] = static_cast<GLint
>(count
);
4862 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
4865 len
= (length
&& length
[ii
] >= 0)
4867 : base::checked_cast
<GLint
>(strlen(str
[ii
]));
4870 total_size
+= 1; // NULL at the end of each char array.
4871 if (!total_size
.IsValid()) {
4872 SetGLError(GL_INVALID_VALUE
, func_name
, "overflow");
4875 header
[ii
+ 1] = len
;
4877 // Pack data into a bucket on the service.
4878 helper_
->SetBucketSize(kResultBucketId
, total_size
.ValueOrDefault(0));
4880 for (GLsizei ii
= 0; ii
<= count
; ++ii
) {
4882 (ii
== 0) ? reinterpret_cast<const char*>(&header
[0]) : str
[ii
- 1];
4883 base::CheckedNumeric
<size_t> checked_size
=
4884 (ii
== 0) ? header_size
: static_cast<size_t>(header
[ii
]);
4886 checked_size
+= 1; // NULL in the end.
4888 if (!checked_size
.IsValid()) {
4889 SetGLError(GL_INVALID_VALUE
, func_name
, "overflow");
4892 size_t size
= checked_size
.ValueOrDefault(0);
4894 ScopedTransferBufferPtr
buffer(size
, helper_
, transfer_buffer_
);
4895 if (!buffer
.valid() || buffer
.size() == 0) {
4896 SetGLError(GL_OUT_OF_MEMORY
, func_name
, "too large");
4899 size_t copy_size
= buffer
.size();
4900 if (ii
> 0 && buffer
.size() == size
)
4903 memcpy(buffer
.address(), src
, copy_size
);
4904 if (copy_size
< buffer
.size()) {
4905 // Append NULL in the end.
4906 DCHECK(copy_size
+ 1 == buffer
.size());
4907 char* str
= reinterpret_cast<char*>(buffer
.address());
4910 helper_
->SetBucketData(kResultBucketId
, offset
, buffer
.size(),
4911 buffer
.shm_id(), buffer
.offset());
4912 offset
+= buffer
.size();
4913 src
+= buffer
.size();
4914 size
-= buffer
.size();
4917 DCHECK_EQ(total_size
.ValueOrDefault(0), offset
);
4921 void GLES2Implementation::UniformBlockBinding(GLuint program
,
4924 GPU_CLIENT_SINGLE_THREAD_CHECK();
4925 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
4926 << ", " << index
<< ", " << binding
<< ")");
4927 share_group_
->program_info_manager()->UniformBlockBinding(
4928 this, program
, index
, binding
);
4929 helper_
->UniformBlockBinding(program
, index
, binding
);
4933 GLenum
GLES2Implementation::ClientWaitSync(
4934 GLsync sync
, GLbitfield flags
, GLuint64 timeout
) {
4935 GPU_CLIENT_SINGLE_THREAD_CHECK();
4936 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync
4937 << ", " << flags
<< ", " << timeout
<< ")");
4938 typedef cmds::ClientWaitSync::Result Result
;
4939 Result
* result
= GetResultAs
<Result
*>();
4941 SetGLError(GL_OUT_OF_MEMORY
, "ClientWaitSync", "");
4942 return GL_WAIT_FAILED
;
4944 *result
= GL_WAIT_FAILED
;
4945 uint32_t v32_0
= 0, v32_1
= 0;
4946 GLES2Util::MapUint64ToTwoUint32(timeout
, &v32_0
, &v32_1
);
4947 helper_
->ClientWaitSync(
4948 ToGLuint(sync
), flags
, v32_0
, v32_1
,
4949 GetResultShmId(), GetResultShmOffset());
4951 GPU_CLIENT_LOG("returned " << *result
);
4956 void GLES2Implementation::WaitSync(
4957 GLsync sync
, GLbitfield flags
, GLuint64 timeout
) {
4958 GPU_CLIENT_SINGLE_THREAD_CHECK();
4959 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync
<< ", "
4960 << flags
<< ", " << timeout
<< ")");
4961 uint32_t v32_0
= 0, v32_1
= 0;
4962 GLES2Util::MapUint64ToTwoUint32(timeout
, &v32_0
, &v32_1
);
4963 helper_
->WaitSync(ToGLuint(sync
), flags
, v32_0
, v32_1
);
4967 // Include the auto-generated part of this file. We split this because it means
4968 // we can easily edit the non-auto generated parts right here in this file
4969 // instead of having to edit some template or the code generator.
4970 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
4972 } // namespace gles2