Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blobd9e479c1dfa5d2feee4ca004f4204b254720d0f8
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>
12 #include <algorithm>
13 #include <limits>
14 #include <map>
15 #include <queue>
16 #include <set>
17 #include <sstream>
18 #include <string>
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"
34 #endif
36 namespace gpu {
37 namespace gles2 {
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;
47 #endif
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)
75 : helper_(helper),
76 transfer_buffer_(transfer_buffer),
77 angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
78 chromium_framebuffer_multisample_(kUnknownExtensionStatus),
79 pack_alignment_(4),
80 unpack_alignment_(4),
81 unpack_flip_y_(false),
82 unpack_row_length_(0),
83 unpack_image_height_(0),
84 unpack_skip_rows_(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),
93 current_program_(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),
101 error_bits_(0),
102 debug_(false),
103 lose_context_when_out_of_memory_(lose_context_when_out_of_memory),
104 support_client_side_arrays_(support_client_side_arrays),
105 use_count_(0),
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) {
111 DCHECK(helper);
112 DCHECK(transfer_buffer);
113 DCHECK(gpu_control);
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);
124 share_group_ =
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,
143 kStartingOffset,
144 min_transfer_buffer_size,
145 max_transfer_buffer_size,
146 kAlignment,
147 kSizeToFlush)) {
148 return false;
151 mapped_memory_.reset(
152 new MappedMemoryManager(
153 helper_,
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,
203 "Initialize",
204 "Service bind_generates_resource mismatch.");
205 return false;
208 return true;
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).
216 WaitForCmd();
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 remaining BufferRange mem; This is when a MapBufferRange() is
226 // called but not the UnmapBuffer() pair.
227 ClearMappedBufferRangeMap();
229 // Release any per-context data in share group.
230 share_group_->FreeContext(this);
232 buffer_tracker_.reset();
234 FreeAllAsyncUploadBuffers();
236 if (async_upload_sync_) {
237 mapped_memory_->Free(async_upload_sync_);
238 async_upload_sync_ = NULL;
241 // Make sure the commands make it the service.
242 WaitForCmd();
245 GLES2CmdHelper* GLES2Implementation::helper() const {
246 return helper_;
249 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
250 return share_group_->GetIdHandler(namespace_id);
253 IdAllocator* GLES2Implementation::GetIdAllocator(int namespace_id) const {
254 if (namespace_id == id_namespaces::kQueries)
255 return query_id_allocator_.get();
256 NOTREACHED();
257 return NULL;
260 void* GLES2Implementation::GetResultBuffer() {
261 return transfer_buffer_->GetResultBuffer();
264 int32 GLES2Implementation::GetResultShmId() {
265 return transfer_buffer_->GetShmId();
268 uint32 GLES2Implementation::GetResultShmOffset() {
269 return transfer_buffer_->GetResultOffset();
272 void GLES2Implementation::FreeUnusedSharedMemory() {
273 mapped_memory_->FreeUnused();
276 void GLES2Implementation::FreeEverything() {
277 FreeAllAsyncUploadBuffers();
278 WaitForCmd();
279 query_tracker_->Shrink();
280 FreeUnusedSharedMemory();
281 transfer_buffer_->Free();
282 helper_->FreeRingBuffer();
285 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
286 if (!helper_->IsContextLost())
287 callback.Run();
290 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
291 const base::Closure& callback) {
292 gpu_control_->SignalSyncPoint(
293 sync_point,
294 base::Bind(&GLES2Implementation::RunIfContextNotLost,
295 weak_ptr_factory_.GetWeakPtr(),
296 callback));
299 void GLES2Implementation::SignalQuery(uint32 query,
300 const base::Closure& callback) {
301 // Flush previously entered commands to ensure ordering with any
302 // glBeginQueryEXT() calls that may have been put into the context.
303 ShallowFlushCHROMIUM();
304 gpu_control_->SignalQuery(
305 query,
306 base::Bind(&GLES2Implementation::RunIfContextNotLost,
307 weak_ptr_factory_.GetWeakPtr(),
308 callback));
311 void GLES2Implementation::SetSurfaceVisible(bool visible) {
312 TRACE_EVENT1(
313 "gpu", "GLES2Implementation::SetSurfaceVisible", "visible", visible);
314 // TODO(piman): This probably should be ShallowFlushCHROMIUM().
315 Flush();
316 gpu_control_->SetSurfaceVisible(visible);
317 if (!visible)
318 FreeEverything();
321 void GLES2Implementation::WaitForCmd() {
322 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
323 helper_->CommandBufferHelper::Finish();
326 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
327 const char* extensions =
328 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
329 if (!extensions)
330 return false;
332 int length = strlen(ext);
333 while (true) {
334 int n = strcspn(extensions, " ");
335 if (n == length && 0 == strncmp(ext, extensions, length)) {
336 return true;
338 if ('\0' == extensions[n]) {
339 return false;
341 extensions += n + 1;
345 bool GLES2Implementation::IsExtensionAvailableHelper(
346 const char* extension, ExtensionStatus* status) {
347 switch (*status) {
348 case kAvailableExtensionStatus:
349 return true;
350 case kUnavailableExtensionStatus:
351 return false;
352 default: {
353 bool available = IsExtensionAvailable(extension);
354 *status = available ? kAvailableExtensionStatus :
355 kUnavailableExtensionStatus;
356 return available;
361 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
362 return IsExtensionAvailableHelper(
363 "GL_ANGLE_pack_reverse_row_order",
364 &angle_pack_reverse_row_order_status_);
367 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
368 return IsExtensionAvailableHelper(
369 "GL_CHROMIUM_framebuffer_multisample",
370 &chromium_framebuffer_multisample_);
373 const std::string& GLES2Implementation::GetLogPrefix() const {
374 const std::string& prefix(debug_marker_manager_.GetMarker());
375 return prefix.empty() ? this_in_hex_ : prefix;
378 GLenum GLES2Implementation::GetError() {
379 GPU_CLIENT_SINGLE_THREAD_CHECK();
380 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
381 GLenum err = GetGLError();
382 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
383 return err;
386 GLenum GLES2Implementation::GetClientSideGLError() {
387 if (error_bits_ == 0) {
388 return GL_NO_ERROR;
391 GLenum error = GL_NO_ERROR;
392 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
393 if ((error_bits_ & mask) != 0) {
394 error = GLES2Util::GLErrorBitToGLError(mask);
395 break;
398 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
399 return error;
402 GLenum GLES2Implementation::GetGLError() {
403 TRACE_EVENT0("gpu", "GLES2::GetGLError");
404 // Check the GL error first, then our wrapped error.
405 typedef cmds::GetError::Result Result;
406 Result* result = GetResultAs<Result*>();
407 // If we couldn't allocate a result the context is lost.
408 if (!result) {
409 return GL_NO_ERROR;
411 *result = GL_NO_ERROR;
412 helper_->GetError(GetResultShmId(), GetResultShmOffset());
413 WaitForCmd();
414 GLenum error = *result;
415 if (error == GL_NO_ERROR) {
416 error = GetClientSideGLError();
417 } else {
418 // There was an error, clear the corresponding wrapped error.
419 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
421 return error;
424 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
425 void GLES2Implementation::FailGLError(GLenum error) {
426 if (error != GL_NO_ERROR) {
427 NOTREACHED() << "Error";
430 // NOTE: Calling GetGLError overwrites data in the result buffer.
431 void GLES2Implementation::CheckGLError() {
432 FailGLError(GetGLError());
434 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
436 void GLES2Implementation::SetGLError(
437 GLenum error, const char* function_name, const char* msg) {
438 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
439 << GLES2Util::GetStringError(error) << ": "
440 << function_name << ": " << msg);
441 FailGLError(error);
442 if (msg) {
443 last_error_ = msg;
445 if (error_message_callback_) {
446 std::string temp(GLES2Util::GetStringError(error) + " : " +
447 function_name + ": " + (msg ? msg : ""));
448 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
450 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
452 if (error == GL_OUT_OF_MEMORY && lose_context_when_out_of_memory_) {
453 helper_->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
454 GL_UNKNOWN_CONTEXT_RESET_ARB);
458 void GLES2Implementation::SetGLErrorInvalidEnum(
459 const char* function_name, GLenum value, const char* label) {
460 SetGLError(GL_INVALID_ENUM, function_name,
461 (std::string(label) + " was " +
462 GLES2Util::GetStringEnum(value)).c_str());
465 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
466 std::vector<int8>* data) {
467 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
468 DCHECK(data);
469 const uint32 kStartSize = 32 * 1024;
470 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
471 if (!buffer.valid()) {
472 return false;
474 typedef cmd::GetBucketStart::Result Result;
475 Result* result = GetResultAs<Result*>();
476 if (!result) {
477 return false;
479 *result = 0;
480 helper_->GetBucketStart(
481 bucket_id, GetResultShmId(), GetResultShmOffset(),
482 buffer.size(), buffer.shm_id(), buffer.offset());
483 WaitForCmd();
484 uint32 size = *result;
485 data->resize(size);
486 if (size > 0u) {
487 uint32 offset = 0;
488 while (size) {
489 if (!buffer.valid()) {
490 buffer.Reset(size);
491 if (!buffer.valid()) {
492 return false;
494 helper_->GetBucketData(
495 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
496 WaitForCmd();
498 uint32 size_to_copy = std::min(size, buffer.size());
499 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
500 offset += size_to_copy;
501 size -= size_to_copy;
502 buffer.Release();
504 // Free the bucket. This is not required but it does free up the memory.
505 // and we don't have to wait for the result so from the client's perspective
506 // it's cheap.
507 helper_->SetBucketSize(bucket_id, 0);
509 return true;
512 void GLES2Implementation::SetBucketContents(
513 uint32 bucket_id, const void* data, size_t size) {
514 DCHECK(data);
515 helper_->SetBucketSize(bucket_id, size);
516 if (size > 0u) {
517 uint32 offset = 0;
518 while (size) {
519 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
520 if (!buffer.valid()) {
521 return;
523 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
524 buffer.size());
525 helper_->SetBucketData(
526 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
527 offset += buffer.size();
528 size -= buffer.size();
533 void GLES2Implementation::SetBucketAsCString(
534 uint32 bucket_id, const char* str) {
535 // NOTE: strings are passed NULL terminated. That means the empty
536 // string will have a size of 1 and no-string will have a size of 0
537 if (str) {
538 SetBucketContents(bucket_id, str, strlen(str) + 1);
539 } else {
540 helper_->SetBucketSize(bucket_id, 0);
544 bool GLES2Implementation::GetBucketAsString(
545 uint32 bucket_id, std::string* str) {
546 DCHECK(str);
547 std::vector<int8> data;
548 // NOTE: strings are passed NULL terminated. That means the empty
549 // string will have a size of 1 and no-string will have a size of 0
550 if (!GetBucketContents(bucket_id, &data)) {
551 return false;
553 if (data.empty()) {
554 return false;
556 str->assign(&data[0], &data[0] + data.size() - 1);
557 return true;
560 void GLES2Implementation::SetBucketAsString(
561 uint32 bucket_id, const std::string& str) {
562 // NOTE: strings are passed NULL terminated. That means the empty
563 // string will have a size of 1 and no-string will have a size of 0
564 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
567 void GLES2Implementation::Disable(GLenum cap) {
568 GPU_CLIENT_SINGLE_THREAD_CHECK();
569 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
570 << GLES2Util::GetStringCapability(cap) << ")");
571 bool changed = false;
572 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
573 helper_->Disable(cap);
575 CheckGLError();
578 void GLES2Implementation::Enable(GLenum cap) {
579 GPU_CLIENT_SINGLE_THREAD_CHECK();
580 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
581 << GLES2Util::GetStringCapability(cap) << ")");
582 bool changed = false;
583 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
584 helper_->Enable(cap);
586 CheckGLError();
589 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
590 GPU_CLIENT_SINGLE_THREAD_CHECK();
591 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
592 << GLES2Util::GetStringCapability(cap) << ")");
593 bool state = false;
594 if (!state_.GetEnabled(cap, &state)) {
595 typedef cmds::IsEnabled::Result Result;
596 Result* result = GetResultAs<Result*>();
597 if (!result) {
598 return GL_FALSE;
600 *result = 0;
601 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
602 WaitForCmd();
603 state = (*result) != 0;
606 GPU_CLIENT_LOG("returned " << state);
607 CheckGLError();
608 return state;
611 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
612 // TODO(zmo): For all the BINDING points, there is a possibility where
613 // resources are shared among multiple contexts, that the cached points
614 // are invalid. It is not a problem for now, but once we allow resource
615 // sharing in WebGL, we need to implement a mechanism to allow correct
616 // client side binding points tracking. crbug.com/465562.
618 // ES2 parameters.
619 switch (pname) {
620 case GL_ACTIVE_TEXTURE:
621 *params = active_texture_unit_ + GL_TEXTURE0;
622 return true;
623 case GL_ARRAY_BUFFER_BINDING:
624 *params = bound_array_buffer_id_;
625 return true;
626 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
627 *params =
628 vertex_array_object_manager_->bound_element_array_buffer();
629 return true;
630 case GL_FRAMEBUFFER_BINDING:
631 *params = bound_framebuffer_;
632 return true;
633 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
634 *params = capabilities_.max_combined_texture_image_units;
635 return true;
636 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
637 *params = capabilities_.max_cube_map_texture_size;
638 return true;
639 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
640 *params = capabilities_.max_fragment_uniform_vectors;
641 return true;
642 case GL_MAX_RENDERBUFFER_SIZE:
643 *params = capabilities_.max_renderbuffer_size;
644 return true;
645 case GL_MAX_TEXTURE_IMAGE_UNITS:
646 *params = capabilities_.max_texture_image_units;
647 return true;
648 case GL_MAX_TEXTURE_SIZE:
649 *params = capabilities_.max_texture_size;
650 return true;
651 case GL_MAX_VARYING_VECTORS:
652 *params = capabilities_.max_varying_vectors;
653 return true;
654 case GL_MAX_VERTEX_ATTRIBS:
655 *params = capabilities_.max_vertex_attribs;
656 return true;
657 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
658 *params = capabilities_.max_vertex_texture_image_units;
659 return true;
660 case GL_MAX_VERTEX_UNIFORM_VECTORS:
661 *params = capabilities_.max_vertex_uniform_vectors;
662 return true;
663 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
664 *params = capabilities_.num_compressed_texture_formats;
665 return true;
666 case GL_NUM_SHADER_BINARY_FORMATS:
667 *params = capabilities_.num_shader_binary_formats;
668 return true;
669 case GL_RENDERBUFFER_BINDING:
670 *params = bound_renderbuffer_;
671 return true;
672 case GL_TEXTURE_BINDING_2D:
673 *params = texture_units_[active_texture_unit_].bound_texture_2d;
674 return true;
675 case GL_TEXTURE_BINDING_CUBE_MAP:
676 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
677 return true;
679 // Non-standard parameters.
680 case GL_TEXTURE_BINDING_EXTERNAL_OES:
681 *params =
682 texture_units_[active_texture_unit_].bound_texture_external_oes;
683 return true;
684 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
685 *params = bound_pixel_pack_transfer_buffer_id_;
686 return true;
687 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
688 *params = bound_pixel_unpack_transfer_buffer_id_;
689 return true;
690 case GL_READ_FRAMEBUFFER_BINDING:
691 if (IsChromiumFramebufferMultisampleAvailable()) {
692 *params = bound_read_framebuffer_;
693 return true;
695 break;
697 // Non-cached parameters.
698 case GL_ALIASED_LINE_WIDTH_RANGE:
699 case GL_ALIASED_POINT_SIZE_RANGE:
700 case GL_ALPHA_BITS:
701 case GL_BLEND:
702 case GL_BLEND_COLOR:
703 case GL_BLEND_DST_ALPHA:
704 case GL_BLEND_DST_RGB:
705 case GL_BLEND_EQUATION_ALPHA:
706 case GL_BLEND_EQUATION_RGB:
707 case GL_BLEND_SRC_ALPHA:
708 case GL_BLEND_SRC_RGB:
709 case GL_BLUE_BITS:
710 case GL_COLOR_CLEAR_VALUE:
711 case GL_COLOR_WRITEMASK:
712 case GL_COMPRESSED_TEXTURE_FORMATS:
713 case GL_CULL_FACE:
714 case GL_CULL_FACE_MODE:
715 case GL_CURRENT_PROGRAM:
716 case GL_DEPTH_BITS:
717 case GL_DEPTH_CLEAR_VALUE:
718 case GL_DEPTH_FUNC:
719 case GL_DEPTH_RANGE:
720 case GL_DEPTH_TEST:
721 case GL_DEPTH_WRITEMASK:
722 case GL_DITHER:
723 case GL_FRONT_FACE:
724 case GL_GENERATE_MIPMAP_HINT:
725 case GL_GREEN_BITS:
726 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
727 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
728 case GL_LINE_WIDTH:
729 case GL_MAX_VIEWPORT_DIMS:
730 case GL_PACK_ALIGNMENT:
731 case GL_POLYGON_OFFSET_FACTOR:
732 case GL_POLYGON_OFFSET_FILL:
733 case GL_POLYGON_OFFSET_UNITS:
734 case GL_RED_BITS:
735 case GL_SAMPLE_ALPHA_TO_COVERAGE:
736 case GL_SAMPLE_BUFFERS:
737 case GL_SAMPLE_COVERAGE:
738 case GL_SAMPLE_COVERAGE_INVERT:
739 case GL_SAMPLE_COVERAGE_VALUE:
740 case GL_SAMPLES:
741 case GL_SCISSOR_BOX:
742 case GL_SCISSOR_TEST:
743 case GL_SHADER_BINARY_FORMATS:
744 case GL_SHADER_COMPILER:
745 case GL_STENCIL_BACK_FAIL:
746 case GL_STENCIL_BACK_FUNC:
747 case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
748 case GL_STENCIL_BACK_PASS_DEPTH_PASS:
749 case GL_STENCIL_BACK_REF:
750 case GL_STENCIL_BACK_VALUE_MASK:
751 case GL_STENCIL_BACK_WRITEMASK:
752 case GL_STENCIL_BITS:
753 case GL_STENCIL_CLEAR_VALUE:
754 case GL_STENCIL_FAIL:
755 case GL_STENCIL_FUNC:
756 case GL_STENCIL_PASS_DEPTH_FAIL:
757 case GL_STENCIL_PASS_DEPTH_PASS:
758 case GL_STENCIL_REF:
759 case GL_STENCIL_TEST:
760 case GL_STENCIL_VALUE_MASK:
761 case GL_STENCIL_WRITEMASK:
762 case GL_SUBPIXEL_BITS:
763 case GL_UNPACK_ALIGNMENT:
764 case GL_VIEWPORT:
765 return false;
766 default:
767 break;
770 if (capabilities_.major_version < 3) {
771 return false;
774 // ES3 parameters.
775 switch (pname) {
776 case GL_MAJOR_VERSION:
777 *params = capabilities_.major_version;
778 return true;
779 case GL_MAX_3D_TEXTURE_SIZE:
780 *params = capabilities_.max_3d_texture_size;
781 return true;
782 case GL_MAX_ARRAY_TEXTURE_LAYERS:
783 *params = capabilities_.max_array_texture_layers;
784 return true;
785 case GL_MAX_COLOR_ATTACHMENTS:
786 *params = capabilities_.max_color_attachments;
787 return true;
788 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
789 *params = capabilities_.max_combined_fragment_uniform_components;
790 return true;
791 case GL_MAX_COMBINED_UNIFORM_BLOCKS:
792 *params = capabilities_.max_combined_uniform_blocks;
793 return true;
794 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
795 *params = capabilities_.max_combined_vertex_uniform_components;
796 return true;
797 case GL_MAX_DRAW_BUFFERS:
798 *params = capabilities_.max_draw_buffers;
799 return true;
800 case GL_MAX_ELEMENT_INDEX:
801 *params = capabilities_.max_element_index;
802 return true;
803 case GL_MAX_ELEMENTS_INDICES:
804 *params = capabilities_.max_elements_indices;
805 return true;
806 case GL_MAX_ELEMENTS_VERTICES:
807 *params = capabilities_.max_elements_vertices;
808 return true;
809 case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
810 *params = capabilities_.max_fragment_input_components;
811 return true;
812 case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
813 *params = capabilities_.max_fragment_uniform_blocks;
814 return true;
815 case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
816 *params = capabilities_.max_fragment_uniform_components;
817 return true;
818 case GL_MAX_PROGRAM_TEXEL_OFFSET:
819 *params = capabilities_.max_program_texel_offset;
820 return true;
821 case GL_MAX_SAMPLES:
822 *params = capabilities_.max_samples;
823 return true;
824 case GL_MAX_SERVER_WAIT_TIMEOUT:
825 *params = capabilities_.max_server_wait_timeout;
826 return true;
827 case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
828 *params = capabilities_.max_transform_feedback_interleaved_components;
829 return true;
830 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
831 *params = capabilities_.max_transform_feedback_separate_attribs;
832 return true;
833 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
834 *params = capabilities_.max_transform_feedback_separate_components;
835 return true;
836 case GL_MAX_UNIFORM_BLOCK_SIZE:
837 *params = capabilities_.max_uniform_block_size;
838 return true;
839 case GL_MAX_UNIFORM_BUFFER_BINDINGS:
840 *params = capabilities_.max_uniform_buffer_bindings;
841 return true;
842 case GL_MAX_VARYING_COMPONENTS:
843 *params = capabilities_.max_varying_components;
844 return true;
845 case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
846 *params = capabilities_.max_vertex_output_components;
847 return true;
848 case GL_MAX_VERTEX_UNIFORM_BLOCKS:
849 *params = capabilities_.max_vertex_uniform_blocks;
850 return true;
851 case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
852 *params = capabilities_.max_vertex_uniform_components;
853 return true;
854 case GL_MIN_PROGRAM_TEXEL_OFFSET:
855 *params = capabilities_.min_program_texel_offset;
856 return true;
857 case GL_MINOR_VERSION:
858 *params = capabilities_.minor_version;
859 return true;
860 case GL_NUM_EXTENSIONS:
861 *params = capabilities_.num_extensions;
862 return true;
863 case GL_NUM_PROGRAM_BINARY_FORMATS:
864 *params = capabilities_.num_program_binary_formats;
865 return true;
866 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
867 *params = capabilities_.uniform_buffer_offset_alignment;
868 return true;
870 // Non-cached ES3 parameters.
871 case GL_COPY_READ_BUFFER_BINDING:
872 case GL_COPY_WRITE_BUFFER_BINDING:
873 case GL_DRAW_BUFFER0:
874 case GL_DRAW_BUFFER1:
875 case GL_DRAW_BUFFER2:
876 case GL_DRAW_BUFFER3:
877 case GL_DRAW_BUFFER4:
878 case GL_DRAW_BUFFER5:
879 case GL_DRAW_BUFFER6:
880 case GL_DRAW_BUFFER7:
881 case GL_DRAW_BUFFER8:
882 case GL_DRAW_BUFFER9:
883 case GL_DRAW_BUFFER10:
884 case GL_DRAW_BUFFER11:
885 case GL_DRAW_BUFFER12:
886 case GL_DRAW_BUFFER13:
887 case GL_DRAW_BUFFER14:
888 case GL_DRAW_BUFFER15:
889 case GL_DRAW_FRAMEBUFFER_BINDING:
890 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
891 case GL_MAX_TEXTURE_LOD_BIAS:
892 case GL_PACK_ROW_LENGTH:
893 case GL_PACK_SKIP_PIXELS:
894 case GL_PACK_SKIP_ROWS:
895 case GL_PIXEL_PACK_BUFFER_BINDING:
896 case GL_PIXEL_UNPACK_BUFFER_BINDING:
897 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
898 case GL_PROGRAM_BINARY_FORMATS:
899 case GL_RASTERIZER_DISCARD:
900 case GL_READ_BUFFER:
901 case GL_READ_FRAMEBUFFER_BINDING:
902 case GL_SAMPLER_BINDING:
903 case GL_TEXTURE_BINDING_2D_ARRAY:
904 case GL_TEXTURE_BINDING_3D:
905 case GL_TRANSFORM_FEEDBACK_BINDING:
906 case GL_TRANSFORM_FEEDBACK_ACTIVE:
907 case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
908 case GL_TRANSFORM_FEEDBACK_PAUSED:
909 case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
910 case GL_TRANSFORM_FEEDBACK_BUFFER_START:
911 case GL_UNIFORM_BUFFER_BINDING:
912 case GL_UNIFORM_BUFFER_SIZE:
913 case GL_UNIFORM_BUFFER_START:
914 case GL_UNPACK_IMAGE_HEIGHT:
915 case GL_UNPACK_ROW_LENGTH:
916 case GL_UNPACK_SKIP_IMAGES:
917 case GL_UNPACK_SKIP_PIXELS:
918 case GL_UNPACK_SKIP_ROWS:
919 case GL_VERTEX_ARRAY_BINDING:
920 return false;
921 default:
922 return false;
926 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
927 // TODO(gman): Make this handle pnames that return more than 1 value.
928 GLint value;
929 if (!GetHelper(pname, &value)) {
930 return false;
932 *params = static_cast<GLboolean>(value);
933 return true;
936 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
937 // TODO(gman): Make this handle pnames that return more than 1 value.
938 GLint value;
939 if (!GetHelper(pname, &value)) {
940 return false;
942 *params = static_cast<GLfloat>(value);
943 return true;
946 bool GLES2Implementation::GetInteger64vHelper(GLenum pname, GLint64* params) {
947 // TODO(zmo): we limit values to 32-bit, which is OK for now.
948 GLint value;
949 if (!GetHelper(pname, &value)) {
950 return false;
952 *params = value;
953 return true;
956 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
957 return GetHelper(pname, params);
960 bool GLES2Implementation::GetIntegeri_vHelper(
961 GLenum pname, GLuint index, GLint* data) {
962 // TODO(zmo): Implement client side caching.
963 return false;
966 bool GLES2Implementation::GetInteger64i_vHelper(
967 GLenum pname, GLuint index, GLint64* data) {
968 // TODO(zmo): Implement client side caching.
969 return false;
972 bool GLES2Implementation::GetInternalformativHelper(
973 GLenum target, GLenum format, GLenum pname, GLsizei bufSize,
974 GLint* params) {
975 // TODO(zmo): Implement the client side caching.
976 return false;
979 bool GLES2Implementation::GetSyncivHelper(
980 GLsync sync, GLenum pname, GLsizei bufsize, GLsizei* length,
981 GLint* values) {
982 GLint value = 0;
983 switch (pname) {
984 case GL_OBJECT_TYPE:
985 value = GL_SYNC_FENCE;
986 break;
987 case GL_SYNC_CONDITION:
988 value = GL_SYNC_GPU_COMMANDS_COMPLETE;
989 break;
990 case GL_SYNC_FLAGS:
991 value = 0;
992 break;
993 default:
994 return false;
996 if (bufsize > 0) {
997 DCHECK(values);
998 *values = value;
1000 if (length) {
1001 *length = 1;
1003 return true;
1006 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
1007 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1008 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
1009 Result* result = GetResultAs<Result*>();
1010 if (!result) {
1011 return 0;
1013 *result = 0;
1014 helper_->GetMaxValueInBufferCHROMIUM(
1015 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
1016 WaitForCmd();
1017 return *result;
1020 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
1021 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1022 GPU_CLIENT_SINGLE_THREAD_CHECK();
1023 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
1024 << buffer_id << ", " << count << ", "
1025 << GLES2Util::GetStringGetMaxIndexType(type)
1026 << ", " << offset << ")");
1027 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
1028 buffer_id, count, type, offset);
1029 GPU_CLIENT_LOG("returned " << result);
1030 CheckGLError();
1031 return result;
1034 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
1035 if (restore) {
1036 RestoreArrayBuffer(restore);
1037 // Restore the element array binding.
1038 // We only need to restore it if it wasn't a client side array.
1039 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
1040 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1045 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
1046 if (restore) {
1047 // Restore the user's current binding.
1048 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_);
1052 void GLES2Implementation::DrawElements(
1053 GLenum mode, GLsizei count, GLenum type, const void* indices) {
1054 GPU_CLIENT_SINGLE_THREAD_CHECK();
1055 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
1056 << GLES2Util::GetStringDrawMode(mode) << ", "
1057 << count << ", "
1058 << GLES2Util::GetStringIndexType(type) << ", "
1059 << static_cast<const void*>(indices) << ")");
1060 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1063 void GLES2Implementation::DrawRangeElements(
1064 GLenum mode, GLuint start, GLuint end,
1065 GLsizei count, GLenum type, const void* indices) {
1066 GPU_CLIENT_SINGLE_THREAD_CHECK();
1067 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawRangeElements("
1068 << GLES2Util::GetStringDrawMode(mode) << ", "
1069 << start << ", " << end << ", " << count << ", "
1070 << GLES2Util::GetStringIndexType(type) << ", "
1071 << static_cast<const void*>(indices) << ")");
1072 if (end < start) {
1073 SetGLError(GL_INVALID_VALUE, "glDrawRangeElements", "end < start");
1074 return;
1076 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1079 void GLES2Implementation::DrawElementsImpl(
1080 GLenum mode, GLsizei count, GLenum type, const void* indices,
1081 const char* func_name) {
1082 if (count < 0) {
1083 SetGLError(GL_INVALID_VALUE, func_name, "count < 0");
1084 return;
1086 bool simulated = false;
1087 GLuint offset = ToGLuint(indices);
1088 if (count > 0) {
1089 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
1090 !ValidateOffset(func_name, reinterpret_cast<GLintptr>(indices))) {
1091 return;
1093 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
1094 func_name, this, helper_, count, type, 0, indices,
1095 &offset, &simulated)) {
1096 return;
1099 helper_->DrawElements(mode, count, type, offset);
1100 RestoreElementAndArrayBuffers(simulated);
1101 CheckGLError();
1104 void GLES2Implementation::Flush() {
1105 GPU_CLIENT_SINGLE_THREAD_CHECK();
1106 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
1107 // Insert the cmd to call glFlush
1108 helper_->Flush();
1109 // Flush our command buffer
1110 // (tell the service to execute up to the flush cmd.)
1111 helper_->CommandBufferHelper::Flush();
1114 void GLES2Implementation::ShallowFlushCHROMIUM() {
1115 GPU_CLIENT_SINGLE_THREAD_CHECK();
1116 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
1117 // Flush our command buffer
1118 // (tell the service to execute up to the flush cmd.)
1119 helper_->CommandBufferHelper::Flush();
1120 // TODO(piman): Add the FreeEverything() logic here.
1123 void GLES2Implementation::OrderingBarrierCHROMIUM() {
1124 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOrderingBarrierCHROMIUM");
1125 // Flush command buffer at the GPU channel level. May be implemented as
1126 // Flush().
1127 helper_->CommandBufferHelper::OrderingBarrier();
1130 void GLES2Implementation::Finish() {
1131 GPU_CLIENT_SINGLE_THREAD_CHECK();
1132 FinishHelper();
1135 void GLES2Implementation::ShallowFinishCHROMIUM() {
1136 GPU_CLIENT_SINGLE_THREAD_CHECK();
1137 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
1138 // Flush our command buffer (tell the service to execute up to the flush cmd
1139 // and don't return until it completes).
1140 helper_->CommandBufferHelper::Finish();
1143 void GLES2Implementation::FinishHelper() {
1144 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
1145 TRACE_EVENT0("gpu", "GLES2::Finish");
1146 // Insert the cmd to call glFinish
1147 helper_->Finish();
1148 // Finish our command buffer
1149 // (tell the service to execute up to the Finish cmd and wait for it to
1150 // execute.)
1151 helper_->CommandBufferHelper::Finish();
1154 void GLES2Implementation::SwapBuffers() {
1155 GPU_CLIENT_SINGLE_THREAD_CHECK();
1156 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
1157 // TODO(piman): Strictly speaking we'd want to insert the token after the
1158 // swap, but the state update with the updated token might not have happened
1159 // by the time the SwapBuffer callback gets called, forcing us to synchronize
1160 // with the GPU process more than needed. So instead, make it happen before.
1161 // All it means is that we could be slightly looser on the kMaxSwapBuffers
1162 // semantics if the client doesn't use the callback mechanism, and by chance
1163 // the scheduler yields between the InsertToken and the SwapBuffers.
1164 swap_buffers_tokens_.push(helper_->InsertToken());
1165 helper_->SwapBuffers();
1166 helper_->CommandBufferHelper::Flush();
1167 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
1168 // compensate for TODO above.
1169 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
1170 helper_->WaitForToken(swap_buffers_tokens_.front());
1171 swap_buffers_tokens_.pop();
1175 void GLES2Implementation::SwapInterval(int interval) {
1176 GPU_CLIENT_SINGLE_THREAD_CHECK();
1177 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapInterval("
1178 << interval << ")");
1179 helper_->SwapInterval(interval);
1182 void GLES2Implementation::BindAttribLocation(
1183 GLuint program, GLuint index, const char* name) {
1184 GPU_CLIENT_SINGLE_THREAD_CHECK();
1185 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
1186 << program << ", " << index << ", " << name << ")");
1187 SetBucketAsString(kResultBucketId, name);
1188 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
1189 helper_->SetBucketSize(kResultBucketId, 0);
1190 CheckGLError();
1193 void GLES2Implementation::BindUniformLocationCHROMIUM(
1194 GLuint program, GLint location, const char* name) {
1195 GPU_CLIENT_SINGLE_THREAD_CHECK();
1196 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1197 << program << ", " << location << ", " << name << ")");
1198 SetBucketAsString(kResultBucketId, name);
1199 helper_->BindUniformLocationCHROMIUMBucket(
1200 program, location, kResultBucketId);
1201 helper_->SetBucketSize(kResultBucketId, 0);
1202 CheckGLError();
1205 void GLES2Implementation::GetVertexAttribPointerv(
1206 GLuint index, GLenum pname, void** ptr) {
1207 GPU_CLIENT_SINGLE_THREAD_CHECK();
1208 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1209 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1210 << static_cast<void*>(ptr) << ")");
1211 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
1212 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1213 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1214 typedef cmds::GetVertexAttribPointerv::Result Result;
1215 Result* result = GetResultAs<Result*>();
1216 if (!result) {
1217 return;
1219 result->SetNumResults(0);
1220 helper_->GetVertexAttribPointerv(
1221 index, pname, GetResultShmId(), GetResultShmOffset());
1222 WaitForCmd();
1223 result->CopyResult(ptr);
1224 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1226 GPU_CLIENT_LOG_CODE_BLOCK({
1227 for (int32 i = 0; i < num_results; ++i) {
1228 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
1231 CheckGLError();
1234 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1235 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1236 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
1237 SetGLError(
1238 GL_INVALID_VALUE,
1239 "glDeleteProgram", "id not created by this context.");
1240 return false;
1242 if (program == current_program_) {
1243 current_program_ = 0;
1245 return true;
1248 void GLES2Implementation::DeleteProgramStub(
1249 GLsizei n, const GLuint* programs) {
1250 DCHECK_EQ(1, n);
1251 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1252 helper_->DeleteProgram(programs[0]);
1255 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1256 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1257 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1258 SetGLError(
1259 GL_INVALID_VALUE,
1260 "glDeleteShader", "id not created by this context.");
1261 return false;
1263 return true;
1266 void GLES2Implementation::DeleteShaderStub(
1267 GLsizei n, const GLuint* shaders) {
1268 DCHECK_EQ(1, n);
1269 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1270 helper_->DeleteShader(shaders[0]);
1273 void GLES2Implementation::DeleteSyncHelper(GLsync sync) {
1274 GLuint sync_uint = ToGLuint(sync);
1275 if (!GetIdHandler(id_namespaces::kSyncs)->FreeIds(
1276 this, 1, &sync_uint, &GLES2Implementation::DeleteSyncStub)) {
1277 SetGLError(
1278 GL_INVALID_VALUE,
1279 "glDeleteSync", "id not created by this context.");
1283 void GLES2Implementation::DeleteSyncStub(GLsizei n, const GLuint* syncs) {
1284 DCHECK_EQ(1, n);
1285 helper_->DeleteSync(syncs[0]);
1288 GLint GLES2Implementation::GetAttribLocationHelper(
1289 GLuint program, const char* name) {
1290 typedef cmds::GetAttribLocation::Result Result;
1291 Result* result = GetResultAs<Result*>();
1292 if (!result) {
1293 return -1;
1295 *result = -1;
1296 SetBucketAsCString(kResultBucketId, name);
1297 helper_->GetAttribLocation(
1298 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1299 WaitForCmd();
1300 helper_->SetBucketSize(kResultBucketId, 0);
1301 return *result;
1304 GLint GLES2Implementation::GetAttribLocation(
1305 GLuint program, const char* name) {
1306 GPU_CLIENT_SINGLE_THREAD_CHECK();
1307 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1308 << ", " << name << ")");
1309 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1310 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1311 this, program, name);
1312 GPU_CLIENT_LOG("returned " << loc);
1313 CheckGLError();
1314 return loc;
1317 GLint GLES2Implementation::GetUniformLocationHelper(
1318 GLuint program, const char* name) {
1319 typedef cmds::GetUniformLocation::Result Result;
1320 Result* result = GetResultAs<Result*>();
1321 if (!result) {
1322 return -1;
1324 *result = -1;
1325 SetBucketAsCString(kResultBucketId, name);
1326 helper_->GetUniformLocation(program, kResultBucketId,
1327 GetResultShmId(), GetResultShmOffset());
1328 WaitForCmd();
1329 helper_->SetBucketSize(kResultBucketId, 0);
1330 return *result;
1333 GLint GLES2Implementation::GetUniformLocation(
1334 GLuint program, const char* name) {
1335 GPU_CLIENT_SINGLE_THREAD_CHECK();
1336 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1337 << ", " << name << ")");
1338 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1339 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1340 this, program, name);
1341 GPU_CLIENT_LOG("returned " << loc);
1342 CheckGLError();
1343 return loc;
1346 bool GLES2Implementation::GetUniformIndicesHelper(
1347 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1348 typedef cmds::GetUniformIndices::Result Result;
1349 Result* result = GetResultAs<Result*>();
1350 if (!result) {
1351 return false;
1353 result->SetNumResults(0);
1354 if (!PackStringsToBucket(count, names, NULL, "glGetUniformIndices")) {
1355 return false;
1357 helper_->GetUniformIndices(program, kResultBucketId,
1358 GetResultShmId(), GetResultShmOffset());
1359 WaitForCmd();
1360 if (result->GetNumResults() != count) {
1361 return false;
1363 result->CopyResult(indices);
1364 return true;
1367 void GLES2Implementation::GetUniformIndices(
1368 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1369 GPU_CLIENT_SINGLE_THREAD_CHECK();
1370 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
1371 << ", " << count << ", " << names << ", " << indices << ")");
1372 TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
1373 if (count < 0) {
1374 SetGLError(GL_INVALID_VALUE, "glGetUniformIndices", "count < 0");
1375 return;
1377 if (count == 0) {
1378 return;
1380 bool success = share_group_->program_info_manager()->GetUniformIndices(
1381 this, program, count, names, indices);
1382 if (success) {
1383 GPU_CLIENT_LOG_CODE_BLOCK({
1384 for (GLsizei ii = 0; ii < count; ++ii) {
1385 GPU_CLIENT_LOG(" " << ii << ": " << indices[ii]);
1389 CheckGLError();
1392 bool GLES2Implementation::GetProgramivHelper(
1393 GLuint program, GLenum pname, GLint* params) {
1394 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1395 this, program, pname, params);
1396 GPU_CLIENT_LOG_CODE_BLOCK({
1397 if (got_value) {
1398 GPU_CLIENT_LOG(" 0: " << *params);
1401 return got_value;
1404 GLint GLES2Implementation::GetFragDataLocationHelper(
1405 GLuint program, const char* name) {
1406 typedef cmds::GetFragDataLocation::Result Result;
1407 Result* result = GetResultAs<Result*>();
1408 if (!result) {
1409 return -1;
1411 *result = -1;
1412 SetBucketAsCString(kResultBucketId, name);
1413 helper_->GetFragDataLocation(
1414 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1415 WaitForCmd();
1416 helper_->SetBucketSize(kResultBucketId, 0);
1417 return *result;
1420 GLint GLES2Implementation::GetFragDataLocation(
1421 GLuint program, const char* name) {
1422 GPU_CLIENT_SINGLE_THREAD_CHECK();
1423 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataLocation("
1424 << program << ", " << name << ")");
1425 TRACE_EVENT0("gpu", "GLES2::GetFragDataLocation");
1426 GLint loc = share_group_->program_info_manager()->GetFragDataLocation(
1427 this, program, name);
1428 GPU_CLIENT_LOG("returned " << loc);
1429 CheckGLError();
1430 return loc;
1433 GLuint GLES2Implementation::GetUniformBlockIndexHelper(
1434 GLuint program, const char* name) {
1435 typedef cmds::GetUniformBlockIndex::Result Result;
1436 Result* result = GetResultAs<Result*>();
1437 if (!result) {
1438 return GL_INVALID_INDEX;
1440 *result = GL_INVALID_INDEX;
1441 SetBucketAsCString(kResultBucketId, name);
1442 helper_->GetUniformBlockIndex(
1443 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1444 WaitForCmd();
1445 helper_->SetBucketSize(kResultBucketId, 0);
1446 return *result;
1449 GLuint GLES2Implementation::GetUniformBlockIndex(
1450 GLuint program, const char* name) {
1451 GPU_CLIENT_SINGLE_THREAD_CHECK();
1452 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformBlockIndex("
1453 << program << ", " << name << ")");
1454 TRACE_EVENT0("gpu", "GLES2::GetUniformBlockIndex");
1455 GLuint index = share_group_->program_info_manager()->GetUniformBlockIndex(
1456 this, program, name);
1457 GPU_CLIENT_LOG("returned " << index);
1458 CheckGLError();
1459 return index;
1462 void GLES2Implementation::LinkProgram(GLuint program) {
1463 GPU_CLIENT_SINGLE_THREAD_CHECK();
1464 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1465 helper_->LinkProgram(program);
1466 share_group_->program_info_manager()->CreateInfo(program);
1467 CheckGLError();
1470 void GLES2Implementation::ShaderBinary(
1471 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1472 GLsizei length) {
1473 GPU_CLIENT_SINGLE_THREAD_CHECK();
1474 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1475 << static_cast<const void*>(shaders) << ", "
1476 << GLES2Util::GetStringEnum(binaryformat) << ", "
1477 << static_cast<const void*>(binary) << ", "
1478 << length << ")");
1479 if (n < 0) {
1480 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1481 return;
1483 if (length < 0) {
1484 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1485 return;
1487 // TODO(gman): ShaderBinary should use buckets.
1488 unsigned int shader_id_size = n * sizeof(*shaders);
1489 ScopedTransferBufferArray<GLint> buffer(
1490 shader_id_size + length, helper_, transfer_buffer_);
1491 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1492 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1493 return;
1495 void* shader_ids = buffer.elements();
1496 void* shader_data = buffer.elements() + shader_id_size;
1497 memcpy(shader_ids, shaders, shader_id_size);
1498 memcpy(shader_data, binary, length);
1499 helper_->ShaderBinary(
1501 buffer.shm_id(),
1502 buffer.offset(),
1503 binaryformat,
1504 buffer.shm_id(),
1505 buffer.offset() + shader_id_size,
1506 length);
1507 CheckGLError();
1510 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1511 GPU_CLIENT_SINGLE_THREAD_CHECK();
1512 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1513 << GLES2Util::GetStringPixelStore(pname) << ", "
1514 << param << ")");
1515 switch (pname) {
1516 case GL_PACK_ALIGNMENT:
1517 pack_alignment_ = param;
1518 break;
1519 case GL_UNPACK_ALIGNMENT:
1520 unpack_alignment_ = param;
1521 break;
1522 case GL_UNPACK_ROW_LENGTH_EXT:
1523 unpack_row_length_ = param;
1524 return;
1525 case GL_UNPACK_IMAGE_HEIGHT:
1526 unpack_image_height_ = param;
1527 return;
1528 case GL_UNPACK_SKIP_ROWS_EXT:
1529 unpack_skip_rows_ = param;
1530 return;
1531 case GL_UNPACK_SKIP_PIXELS_EXT:
1532 unpack_skip_pixels_ = param;
1533 return;
1534 case GL_UNPACK_SKIP_IMAGES:
1535 unpack_skip_images_ = param;
1536 return;
1537 case GL_UNPACK_FLIP_Y_CHROMIUM:
1538 unpack_flip_y_ = (param != 0);
1539 break;
1540 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1541 pack_reverse_row_order_ =
1542 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1543 break;
1544 default:
1545 break;
1547 helper_->PixelStorei(pname, param);
1548 CheckGLError();
1551 void GLES2Implementation::VertexAttribIPointer(
1552 GLuint index, GLint size, GLenum type, GLsizei stride, const void* ptr) {
1553 GPU_CLIENT_SINGLE_THREAD_CHECK();
1554 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribIPointer("
1555 << index << ", "
1556 << size << ", "
1557 << GLES2Util::GetStringVertexAttribIType(type) << ", "
1558 << stride << ", "
1559 << ptr << ")");
1560 // Record the info on the client side.
1561 if (!vertex_array_object_manager_->SetAttribPointer(
1562 bound_array_buffer_id_, index, size, type, GL_FALSE, stride, ptr)) {
1563 SetGLError(GL_INVALID_OPERATION, "glVertexAttribIPointer",
1564 "client side arrays are not allowed in vertex array objects.");
1565 return;
1567 if (!support_client_side_arrays_ || bound_array_buffer_id_ != 0) {
1568 // Only report NON client side buffers to the service.
1569 if (!ValidateOffset("glVertexAttribIPointer",
1570 reinterpret_cast<GLintptr>(ptr))) {
1571 return;
1573 helper_->VertexAttribIPointer(index, size, type, stride, ToGLuint(ptr));
1575 CheckGLError();
1578 void GLES2Implementation::VertexAttribPointer(
1579 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1580 const void* ptr) {
1581 GPU_CLIENT_SINGLE_THREAD_CHECK();
1582 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1583 << index << ", "
1584 << size << ", "
1585 << GLES2Util::GetStringVertexAttribType(type) << ", "
1586 << GLES2Util::GetStringBool(normalized) << ", "
1587 << stride << ", "
1588 << ptr << ")");
1589 // Record the info on the client side.
1590 if (!vertex_array_object_manager_->SetAttribPointer(
1591 bound_array_buffer_id_, index, size, type, normalized, stride, ptr)) {
1592 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1593 "client side arrays are not allowed in vertex array objects.");
1594 return;
1596 if (!support_client_side_arrays_ || bound_array_buffer_id_ != 0) {
1597 // Only report NON client side buffers to the service.
1598 if (!ValidateOffset("glVertexAttribPointer",
1599 reinterpret_cast<GLintptr>(ptr))) {
1600 return;
1602 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1603 ToGLuint(ptr));
1605 CheckGLError();
1608 void GLES2Implementation::VertexAttribDivisorANGLE(
1609 GLuint index, GLuint divisor) {
1610 GPU_CLIENT_SINGLE_THREAD_CHECK();
1611 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1612 << index << ", "
1613 << divisor << ") ");
1614 // Record the info on the client side.
1615 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1616 helper_->VertexAttribDivisorANGLE(index, divisor);
1617 CheckGLError();
1620 void GLES2Implementation::BufferDataHelper(
1621 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1622 if (!ValidateSize("glBufferData", size))
1623 return;
1625 #if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
1626 // Do not upload uninitialized data. Even if it's not a bug, it can cause a
1627 // bogus MSan report during a readback later. This is because MSan doesn't
1628 // understand shared memory and would assume we were reading back the same
1629 // unintialized data.
1630 if (data) __msan_check_mem_is_initialized(data, size);
1631 #endif
1633 GLuint buffer_id;
1634 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1635 if (!buffer_id) {
1636 return;
1639 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1640 if (buffer)
1641 RemoveTransferBuffer(buffer);
1643 // Create new buffer.
1644 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1645 DCHECK(buffer);
1646 if (buffer->address() && data)
1647 memcpy(buffer->address(), data, size);
1648 return;
1651 RemoveMappedBufferRangeByTarget(target);
1653 // If there is no data just send BufferData
1654 if (size == 0 || !data) {
1655 helper_->BufferData(target, size, 0, 0, usage);
1656 return;
1659 // See if we can send all at once.
1660 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1661 if (!buffer.valid()) {
1662 return;
1665 if (buffer.size() >= static_cast<unsigned int>(size)) {
1666 memcpy(buffer.address(), data, size);
1667 helper_->BufferData(
1668 target,
1669 size,
1670 buffer.shm_id(),
1671 buffer.offset(),
1672 usage);
1673 return;
1676 // Make the buffer with BufferData then send via BufferSubData
1677 helper_->BufferData(target, size, 0, 0, usage);
1678 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1679 CheckGLError();
1682 void GLES2Implementation::BufferData(
1683 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1684 GPU_CLIENT_SINGLE_THREAD_CHECK();
1685 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1686 << GLES2Util::GetStringBufferTarget(target) << ", "
1687 << size << ", "
1688 << static_cast<const void*>(data) << ", "
1689 << GLES2Util::GetStringBufferUsage(usage) << ")");
1690 BufferDataHelper(target, size, data, usage);
1691 CheckGLError();
1694 void GLES2Implementation::BufferSubDataHelper(
1695 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1696 if (size == 0) {
1697 return;
1700 if (!ValidateSize("glBufferSubData", size) ||
1701 !ValidateOffset("glBufferSubData", offset)) {
1702 return;
1705 GLuint buffer_id;
1706 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1707 if (!buffer_id) {
1708 return;
1710 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1711 if (!buffer) {
1712 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1713 return;
1716 int32 end = 0;
1717 int32 buffer_size = buffer->size();
1718 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1719 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1720 return;
1723 if (buffer->address() && data)
1724 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1725 return;
1728 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1729 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1732 void GLES2Implementation::BufferSubDataHelperImpl(
1733 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1734 ScopedTransferBufferPtr* buffer) {
1735 DCHECK(buffer);
1736 DCHECK_GT(size, 0);
1738 const int8* source = static_cast<const int8*>(data);
1739 while (size) {
1740 if (!buffer->valid() || buffer->size() == 0) {
1741 buffer->Reset(size);
1742 if (!buffer->valid()) {
1743 return;
1746 memcpy(buffer->address(), source, buffer->size());
1747 helper_->BufferSubData(
1748 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1749 offset += buffer->size();
1750 source += buffer->size();
1751 size -= buffer->size();
1752 buffer->Release();
1756 void GLES2Implementation::BufferSubData(
1757 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1758 GPU_CLIENT_SINGLE_THREAD_CHECK();
1759 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1760 << GLES2Util::GetStringBufferTarget(target) << ", "
1761 << offset << ", " << size << ", "
1762 << static_cast<const void*>(data) << ")");
1763 BufferSubDataHelper(target, offset, size, data);
1764 CheckGLError();
1767 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
1768 int32 token = buffer->last_usage_token();
1769 uint32 async_token = buffer->last_async_upload_token();
1771 if (async_token) {
1772 if (HasAsyncUploadTokenPassed(async_token)) {
1773 buffer_tracker_->Free(buffer);
1774 } else {
1775 detached_async_upload_memory_.push_back(
1776 std::make_pair(buffer->address(), async_token));
1777 buffer_tracker_->Unmanage(buffer);
1779 } else if (token) {
1780 if (helper_->HasTokenPassed(token))
1781 buffer_tracker_->Free(buffer);
1782 else
1783 buffer_tracker_->FreePendingToken(buffer, token);
1784 } else {
1785 buffer_tracker_->Free(buffer);
1788 buffer_tracker_->RemoveBuffer(buffer->id());
1791 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1792 GLenum target,
1793 const char* function_name,
1794 GLuint* buffer_id) {
1795 *buffer_id = 0;
1797 switch (target) {
1798 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1799 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1800 break;
1801 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1802 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1803 break;
1804 default:
1805 // Unknown target
1806 return false;
1808 if (!*buffer_id) {
1809 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1811 return true;
1814 BufferTracker::Buffer*
1815 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1816 GLuint buffer_id,
1817 const char* function_name,
1818 GLuint offset, GLsizei size) {
1819 DCHECK(buffer_id);
1820 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1821 if (!buffer) {
1822 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1823 return NULL;
1825 if (buffer->mapped()) {
1826 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1827 return NULL;
1829 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1830 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1831 return NULL;
1833 return buffer;
1836 void GLES2Implementation::CompressedTexImage2D(
1837 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1838 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1839 GPU_CLIENT_SINGLE_THREAD_CHECK();
1840 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1841 << GLES2Util::GetStringTextureTarget(target) << ", "
1842 << level << ", "
1843 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1844 << width << ", " << height << ", " << border << ", "
1845 << image_size << ", "
1846 << static_cast<const void*>(data) << ")");
1847 if (width < 0 || height < 0 || level < 0) {
1848 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1849 return;
1851 if (border != 0) {
1852 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "border != 0");
1853 return;
1855 if (height == 0 || width == 0) {
1856 return;
1858 // If there's a pixel unpack buffer bound use it when issuing
1859 // CompressedTexImage2D.
1860 if (bound_pixel_unpack_transfer_buffer_id_) {
1861 GLuint offset = ToGLuint(data);
1862 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1863 bound_pixel_unpack_transfer_buffer_id_,
1864 "glCompressedTexImage2D", offset, image_size);
1865 if (buffer && buffer->shm_id() != -1) {
1866 helper_->CompressedTexImage2D(
1867 target, level, internalformat, width, height, image_size,
1868 buffer->shm_id(), buffer->shm_offset() + offset);
1869 buffer->set_last_usage_token(helper_->InsertToken());
1871 return;
1873 SetBucketContents(kResultBucketId, data, image_size);
1874 helper_->CompressedTexImage2DBucket(
1875 target, level, internalformat, width, height, kResultBucketId);
1876 // Free the bucket. This is not required but it does free up the memory.
1877 // and we don't have to wait for the result so from the client's perspective
1878 // it's cheap.
1879 helper_->SetBucketSize(kResultBucketId, 0);
1880 CheckGLError();
1883 void GLES2Implementation::CompressedTexSubImage2D(
1884 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1885 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1886 GPU_CLIENT_SINGLE_THREAD_CHECK();
1887 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1888 << GLES2Util::GetStringTextureTarget(target) << ", "
1889 << level << ", "
1890 << xoffset << ", " << yoffset << ", "
1891 << width << ", " << height << ", "
1892 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1893 << image_size << ", "
1894 << static_cast<const void*>(data) << ")");
1895 if (width < 0 || height < 0 || level < 0) {
1896 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1897 return;
1899 // If there's a pixel unpack buffer bound use it when issuing
1900 // CompressedTexSubImage2D.
1901 if (bound_pixel_unpack_transfer_buffer_id_) {
1902 GLuint offset = ToGLuint(data);
1903 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1904 bound_pixel_unpack_transfer_buffer_id_,
1905 "glCompressedTexSubImage2D", offset, image_size);
1906 if (buffer && buffer->shm_id() != -1) {
1907 helper_->CompressedTexSubImage2D(
1908 target, level, xoffset, yoffset, width, height, format, image_size,
1909 buffer->shm_id(), buffer->shm_offset() + offset);
1910 buffer->set_last_usage_token(helper_->InsertToken());
1911 CheckGLError();
1913 return;
1915 SetBucketContents(kResultBucketId, data, image_size);
1916 helper_->CompressedTexSubImage2DBucket(
1917 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1918 // Free the bucket. This is not required but it does free up the memory.
1919 // and we don't have to wait for the result so from the client's perspective
1920 // it's cheap.
1921 helper_->SetBucketSize(kResultBucketId, 0);
1922 CheckGLError();
1925 void GLES2Implementation::CompressedTexImage3D(
1926 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1927 GLsizei height, GLsizei depth, GLint border, GLsizei image_size,
1928 const void* data) {
1929 GPU_CLIENT_SINGLE_THREAD_CHECK();
1930 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage3D("
1931 << GLES2Util::GetStringTexture3DTarget(target) << ", " << level << ", "
1932 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1933 << width << ", " << height << ", " << depth << ", " << border << ", "
1934 << image_size << ", " << static_cast<const void*>(data) << ")");
1935 if (width < 0 || height < 0 || depth < 0 || level < 0) {
1936 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "dimension < 0");
1937 return;
1939 if (border != 0) {
1940 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "border != 0");
1941 return;
1943 if (height == 0 || width == 0 || depth == 0) {
1944 return;
1946 // If there's a pixel unpack buffer bound use it when issuing
1947 // CompressedTexImage3D.
1948 if (bound_pixel_unpack_transfer_buffer_id_) {
1949 GLuint offset = ToGLuint(data);
1950 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1951 bound_pixel_unpack_transfer_buffer_id_,
1952 "glCompressedTexImage3D", offset, image_size);
1953 if (buffer && buffer->shm_id() != -1) {
1954 helper_->CompressedTexImage3D(
1955 target, level, internalformat, width, height, depth, image_size,
1956 buffer->shm_id(), buffer->shm_offset() + offset);
1957 buffer->set_last_usage_token(helper_->InsertToken());
1959 return;
1961 SetBucketContents(kResultBucketId, data, image_size);
1962 helper_->CompressedTexImage3DBucket(
1963 target, level, internalformat, width, height, depth, kResultBucketId);
1964 // Free the bucket. This is not required but it does free up the memory.
1965 // and we don't have to wait for the result so from the client's perspective
1966 // it's cheap.
1967 helper_->SetBucketSize(kResultBucketId, 0);
1968 CheckGLError();
1971 namespace {
1973 void CopyRectToBuffer(
1974 const void* pixels,
1975 uint32 height,
1976 uint32 unpadded_row_size,
1977 uint32 pixels_padded_row_size,
1978 bool flip_y,
1979 void* buffer,
1980 uint32 buffer_padded_row_size) {
1981 const int8* source = static_cast<const int8*>(pixels);
1982 int8* dest = static_cast<int8*>(buffer);
1983 if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
1984 if (flip_y) {
1985 dest += buffer_padded_row_size * (height - 1);
1987 // the last row is copied unpadded at the end
1988 for (; height > 1; --height) {
1989 memcpy(dest, source, buffer_padded_row_size);
1990 if (flip_y) {
1991 dest -= buffer_padded_row_size;
1992 } else {
1993 dest += buffer_padded_row_size;
1995 source += pixels_padded_row_size;
1997 memcpy(dest, source, unpadded_row_size);
1998 } else {
1999 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
2000 memcpy(dest, source, size);
2004 } // anonymous namespace
2006 void GLES2Implementation::TexImage2D(
2007 GLenum target, GLint level, GLint internalformat, GLsizei width,
2008 GLsizei height, GLint border, GLenum format, GLenum type,
2009 const void* pixels) {
2010 GPU_CLIENT_SINGLE_THREAD_CHECK();
2011 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
2012 << GLES2Util::GetStringTextureTarget(target) << ", "
2013 << level << ", "
2014 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2015 << width << ", " << height << ", " << border << ", "
2016 << GLES2Util::GetStringTextureFormat(format) << ", "
2017 << GLES2Util::GetStringPixelType(type) << ", "
2018 << static_cast<const void*>(pixels) << ")");
2019 if (level < 0 || height < 0 || width < 0) {
2020 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
2021 return;
2023 if (border != 0) {
2024 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
2025 return;
2027 uint32 size;
2028 uint32 unpadded_row_size;
2029 uint32 padded_row_size;
2030 if (!GLES2Util::ComputeImageDataSizes(
2031 width, height, 1, format, type, unpack_alignment_, &size,
2032 &unpadded_row_size, &padded_row_size)) {
2033 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
2034 return;
2037 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
2038 if (bound_pixel_unpack_transfer_buffer_id_) {
2039 GLuint offset = ToGLuint(pixels);
2040 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2041 bound_pixel_unpack_transfer_buffer_id_,
2042 "glTexImage2D", offset, size);
2043 if (buffer && buffer->shm_id() != -1) {
2044 helper_->TexImage2D(
2045 target, level, internalformat, width, height, format, type,
2046 buffer->shm_id(), buffer->shm_offset() + offset);
2047 buffer->set_last_usage_token(helper_->InsertToken());
2048 CheckGLError();
2050 return;
2053 // If there's no data just issue TexImage2D
2054 if (!pixels) {
2055 helper_->TexImage2D(
2056 target, level, internalformat, width, height, format, type,
2057 0, 0);
2058 CheckGLError();
2059 return;
2062 // compute the advance bytes per row for the src pixels
2063 uint32 src_padded_row_size;
2064 if (unpack_row_length_ > 0) {
2065 if (!GLES2Util::ComputeImagePaddedRowSize(
2066 unpack_row_length_, format, type, unpack_alignment_,
2067 &src_padded_row_size)) {
2068 SetGLError(
2069 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2070 return;
2072 } else {
2073 src_padded_row_size = padded_row_size;
2076 // advance pixels pointer past the skip rows and skip pixels
2077 pixels = reinterpret_cast<const int8*>(pixels) +
2078 unpack_skip_rows_ * src_padded_row_size;
2079 if (unpack_skip_pixels_) {
2080 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2081 pixels = reinterpret_cast<const int8*>(pixels) +
2082 unpack_skip_pixels_ * group_size;
2085 // Check if we can send it all at once.
2086 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
2087 if (!buffer.valid()) {
2088 return;
2091 if (buffer.size() >= size) {
2092 CopyRectToBuffer(
2093 pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
2094 buffer.address(), padded_row_size);
2095 helper_->TexImage2D(
2096 target, level, internalformat, width, height, format, type,
2097 buffer.shm_id(), buffer.offset());
2098 CheckGLError();
2099 return;
2102 // No, so send it using TexSubImage2D.
2103 helper_->TexImage2D(
2104 target, level, internalformat, width, height, format, type,
2105 0, 0);
2106 TexSubImage2DImpl(
2107 target, level, 0, 0, width, height, format, type, unpadded_row_size,
2108 pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
2109 CheckGLError();
2112 void GLES2Implementation::TexImage3D(
2113 GLenum target, GLint level, GLint internalformat, GLsizei width,
2114 GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type,
2115 const void* pixels) {
2116 GPU_CLIENT_SINGLE_THREAD_CHECK();
2117 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D("
2118 << GLES2Util::GetStringTextureTarget(target) << ", "
2119 << level << ", "
2120 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2121 << width << ", " << height << ", " << depth << ", " << border << ", "
2122 << GLES2Util::GetStringTextureFormat(format) << ", "
2123 << GLES2Util::GetStringPixelType(type) << ", "
2124 << static_cast<const void*>(pixels) << ")");
2125 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2126 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "dimension < 0");
2127 return;
2129 if (border != 0) {
2130 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "border != 0");
2131 return;
2133 uint32 size;
2134 uint32 unpadded_row_size;
2135 uint32 padded_row_size;
2136 if (!GLES2Util::ComputeImageDataSizes(
2137 width, height, depth, format, type, unpack_alignment_, &size,
2138 &unpadded_row_size, &padded_row_size)) {
2139 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large");
2140 return;
2143 // If there's a pixel unpack buffer bound use it when issuing TexImage3D.
2144 if (bound_pixel_unpack_transfer_buffer_id_) {
2145 GLuint offset = ToGLuint(pixels);
2146 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2147 bound_pixel_unpack_transfer_buffer_id_,
2148 "glTexImage3D", offset, size);
2149 if (buffer && buffer->shm_id() != -1) {
2150 helper_->TexImage3D(
2151 target, level, internalformat, width, height, depth, format, type,
2152 buffer->shm_id(), buffer->shm_offset() + offset);
2153 buffer->set_last_usage_token(helper_->InsertToken());
2154 CheckGLError();
2156 return;
2159 // If there's no data just issue TexImage3D
2160 if (!pixels) {
2161 helper_->TexImage3D(
2162 target, level, internalformat, width, height, depth, format, type,
2163 0, 0);
2164 CheckGLError();
2165 return;
2168 // compute the advance bytes per row for the src pixels
2169 uint32 src_padded_row_size;
2170 if (unpack_row_length_ > 0) {
2171 if (!GLES2Util::ComputeImagePaddedRowSize(
2172 unpack_row_length_, format, type, unpack_alignment_,
2173 &src_padded_row_size)) {
2174 SetGLError(
2175 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2176 return;
2178 } else {
2179 src_padded_row_size = padded_row_size;
2181 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2183 // advance pixels pointer past the skip images/rows/pixels
2184 pixels = reinterpret_cast<const int8*>(pixels) +
2185 unpack_skip_images_ * src_padded_row_size * src_height +
2186 unpack_skip_rows_ * src_padded_row_size;
2187 if (unpack_skip_pixels_) {
2188 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2189 pixels = reinterpret_cast<const int8*>(pixels) +
2190 unpack_skip_pixels_ * group_size;
2193 // Check if we can send it all at once.
2194 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
2195 if (!buffer.valid()) {
2196 return;
2199 if (buffer.size() >= size) {
2200 void* buffer_pointer = buffer.address();
2201 for (GLsizei z = 0; z < depth; ++z) {
2202 // Only the last row of the last image is unpadded.
2203 uint32 src_unpadded_row_size =
2204 (z == depth - 1) ? unpadded_row_size : src_padded_row_size;
2205 // TODO(zmo): Ignore flip_y flag for now.
2206 CopyRectToBuffer(
2207 pixels, height, src_unpadded_row_size, src_padded_row_size, false,
2208 buffer_pointer, padded_row_size);
2209 pixels = reinterpret_cast<const int8*>(pixels) +
2210 src_padded_row_size * src_height;
2211 buffer_pointer = reinterpret_cast<int8*>(buffer_pointer) +
2212 padded_row_size * height;
2214 helper_->TexImage3D(
2215 target, level, internalformat, width, height, depth, format, type,
2216 buffer.shm_id(), buffer.offset());
2217 CheckGLError();
2218 return;
2221 // No, so send it using TexSubImage3D.
2222 helper_->TexImage3D(
2223 target, level, internalformat, width, height, depth, format, type,
2224 0, 0);
2225 TexSubImage3DImpl(
2226 target, level, 0, 0, 0, width, height, depth, format, type,
2227 unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &buffer,
2228 padded_row_size);
2229 CheckGLError();
2232 void GLES2Implementation::TexSubImage2D(
2233 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2234 GLsizei height, GLenum format, GLenum type, const void* pixels) {
2235 GPU_CLIENT_SINGLE_THREAD_CHECK();
2236 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
2237 << GLES2Util::GetStringTextureTarget(target) << ", "
2238 << level << ", "
2239 << xoffset << ", " << yoffset << ", "
2240 << width << ", " << height << ", "
2241 << GLES2Util::GetStringTextureFormat(format) << ", "
2242 << GLES2Util::GetStringPixelType(type) << ", "
2243 << static_cast<const void*>(pixels) << ")");
2245 if (level < 0 || height < 0 || width < 0) {
2246 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
2247 return;
2249 if (height == 0 || width == 0) {
2250 return;
2253 uint32 temp_size;
2254 uint32 unpadded_row_size;
2255 uint32 padded_row_size;
2256 if (!GLES2Util::ComputeImageDataSizes(
2257 width, height, 1, format, type, unpack_alignment_, &temp_size,
2258 &unpadded_row_size, &padded_row_size)) {
2259 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
2260 return;
2263 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2264 if (bound_pixel_unpack_transfer_buffer_id_) {
2265 GLuint offset = ToGLuint(pixels);
2266 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2267 bound_pixel_unpack_transfer_buffer_id_,
2268 "glTexSubImage2D", offset, temp_size);
2269 if (buffer && buffer->shm_id() != -1) {
2270 helper_->TexSubImage2D(
2271 target, level, xoffset, yoffset, width, height, format, type,
2272 buffer->shm_id(), buffer->shm_offset() + offset, false);
2273 buffer->set_last_usage_token(helper_->InsertToken());
2274 CheckGLError();
2276 return;
2279 // compute the advance bytes per row for the src pixels
2280 uint32 src_padded_row_size;
2281 if (unpack_row_length_ > 0) {
2282 if (!GLES2Util::ComputeImagePaddedRowSize(
2283 unpack_row_length_, format, type, unpack_alignment_,
2284 &src_padded_row_size)) {
2285 SetGLError(
2286 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2287 return;
2289 } else {
2290 src_padded_row_size = padded_row_size;
2293 // advance pixels pointer past the skip rows and skip pixels
2294 pixels = reinterpret_cast<const int8*>(pixels) +
2295 unpack_skip_rows_ * src_padded_row_size;
2296 if (unpack_skip_pixels_) {
2297 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2298 pixels = reinterpret_cast<const int8*>(pixels) +
2299 unpack_skip_pixels_ * group_size;
2302 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2303 TexSubImage2DImpl(
2304 target, level, xoffset, yoffset, width, height, format, type,
2305 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
2306 padded_row_size);
2307 CheckGLError();
2310 void GLES2Implementation::TexSubImage3D(
2311 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2312 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2313 const void* pixels) {
2314 GPU_CLIENT_SINGLE_THREAD_CHECK();
2315 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D("
2316 << GLES2Util::GetStringTextureTarget(target) << ", "
2317 << level << ", "
2318 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2319 << width << ", " << height << ", " << depth << ", "
2320 << GLES2Util::GetStringTextureFormat(format) << ", "
2321 << GLES2Util::GetStringPixelType(type) << ", "
2322 << static_cast<const void*>(pixels) << ")");
2324 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2325 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "dimension < 0");
2326 return;
2328 if (height == 0 || width == 0 || depth == 0) {
2329 return;
2332 uint32 temp_size;
2333 uint32 unpadded_row_size;
2334 uint32 padded_row_size;
2335 if (!GLES2Util::ComputeImageDataSizes(
2336 width, height, depth, format, type, unpack_alignment_, &temp_size,
2337 &unpadded_row_size, &padded_row_size)) {
2338 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "size to large");
2339 return;
2342 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2343 if (bound_pixel_unpack_transfer_buffer_id_) {
2344 GLuint offset = ToGLuint(pixels);
2345 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2346 bound_pixel_unpack_transfer_buffer_id_,
2347 "glTexSubImage3D", offset, temp_size);
2348 if (buffer && buffer->shm_id() != -1) {
2349 helper_->TexSubImage3D(
2350 target, level, xoffset, yoffset, zoffset, width, height, depth,
2351 format, type, buffer->shm_id(), buffer->shm_offset() + offset, false);
2352 buffer->set_last_usage_token(helper_->InsertToken());
2353 CheckGLError();
2355 return;
2358 // compute the advance bytes per row for the src pixels
2359 uint32 src_padded_row_size;
2360 if (unpack_row_length_ > 0) {
2361 if (!GLES2Util::ComputeImagePaddedRowSize(
2362 unpack_row_length_, format, type, unpack_alignment_,
2363 &src_padded_row_size)) {
2364 SetGLError(
2365 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2366 return;
2368 } else {
2369 src_padded_row_size = padded_row_size;
2371 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2373 // advance pixels pointer past the skip images/rows/pixels
2374 pixels = reinterpret_cast<const int8*>(pixels) +
2375 unpack_skip_images_ * src_padded_row_size * src_height +
2376 unpack_skip_rows_ * src_padded_row_size;
2377 if (unpack_skip_pixels_) {
2378 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2379 pixels = reinterpret_cast<const int8*>(pixels) +
2380 unpack_skip_pixels_ * group_size;
2383 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2384 TexSubImage3DImpl(
2385 target, level, xoffset, yoffset, zoffset, width, height, depth,
2386 format, type, unpadded_row_size, pixels, src_padded_row_size, GL_FALSE,
2387 &buffer, padded_row_size);
2388 CheckGLError();
2391 static GLint ComputeNumRowsThatFitInBuffer(
2392 uint32 padded_row_size, uint32 unpadded_row_size,
2393 unsigned int size, GLsizei remaining_rows) {
2394 DCHECK_GE(unpadded_row_size, 0u);
2395 if (padded_row_size == 0) {
2396 return 1;
2398 GLint num_rows = size / padded_row_size;
2399 if (num_rows + 1 == remaining_rows &&
2400 size - num_rows * padded_row_size >= unpadded_row_size) {
2401 num_rows++;
2403 return num_rows;
2406 void GLES2Implementation::TexSubImage2DImpl(
2407 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2408 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
2409 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
2410 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
2411 DCHECK(buffer);
2412 DCHECK_GE(level, 0);
2413 DCHECK_GT(height, 0);
2414 DCHECK_GT(width, 0);
2416 const int8* source = reinterpret_cast<const int8*>(pixels);
2417 GLint original_yoffset = yoffset;
2418 // Transfer by rows.
2419 while (height) {
2420 unsigned int desired_size =
2421 buffer_padded_row_size * (height - 1) + unpadded_row_size;
2422 if (!buffer->valid() || buffer->size() == 0) {
2423 buffer->Reset(desired_size);
2424 if (!buffer->valid()) {
2425 return;
2429 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2430 buffer_padded_row_size, unpadded_row_size, buffer->size(), height);
2431 num_rows = std::min(num_rows, height);
2432 CopyRectToBuffer(
2433 source, num_rows, unpadded_row_size, pixels_padded_row_size,
2434 unpack_flip_y_, buffer->address(), buffer_padded_row_size);
2435 GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
2436 helper_->TexSubImage2D(
2437 target, level, xoffset, y, width, num_rows, format, type,
2438 buffer->shm_id(), buffer->offset(), internal);
2439 buffer->Release();
2440 yoffset += num_rows;
2441 source += num_rows * pixels_padded_row_size;
2442 height -= num_rows;
2446 void GLES2Implementation::TexSubImage3DImpl(
2447 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei zoffset,
2448 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2449 uint32 unpadded_row_size, const void* pixels, uint32 pixels_padded_row_size,
2450 GLboolean internal, ScopedTransferBufferPtr* buffer,
2451 uint32 buffer_padded_row_size) {
2452 DCHECK(buffer);
2453 DCHECK_GE(level, 0);
2454 DCHECK_GT(height, 0);
2455 DCHECK_GT(width, 0);
2456 DCHECK_GT(depth, 0);
2457 const int8* source = reinterpret_cast<const int8*>(pixels);
2458 GLsizei total_rows = height * depth;
2459 GLint row_index = 0, depth_index = 0;
2460 while (total_rows) {
2461 // Each time, we either copy one or more images, or copy one or more rows
2462 // within a single image, depending on the buffer size limit.
2463 GLsizei max_rows;
2464 unsigned int desired_size;
2465 if (row_index > 0) {
2466 // We are in the middle of an image. Send the remaining of the image.
2467 max_rows = height - row_index;
2468 if (total_rows <= height) {
2469 // Last image, so last row is unpadded.
2470 desired_size = buffer_padded_row_size * (max_rows - 1) +
2471 unpadded_row_size;
2472 } else {
2473 desired_size = buffer_padded_row_size * max_rows;
2475 } else {
2476 // Send all the remaining data if possible.
2477 max_rows = total_rows;
2478 desired_size =
2479 buffer_padded_row_size * (max_rows - 1) + unpadded_row_size;
2481 if (!buffer->valid() || buffer->size() == 0) {
2482 buffer->Reset(desired_size);
2483 if (!buffer->valid()) {
2484 return;
2487 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2488 buffer_padded_row_size, unpadded_row_size, buffer->size(), total_rows);
2489 num_rows = std::min(num_rows, max_rows);
2490 GLint num_images = num_rows / height;
2491 GLsizei my_height, my_depth;
2492 if (num_images > 0) {
2493 num_rows = num_images * height;
2494 my_height = height;
2495 my_depth = num_images;
2496 } else {
2497 my_height = num_rows;
2498 my_depth = 1;
2501 // TODO(zmo): Ignore flip_y flag for now.
2502 if (num_images > 0) {
2503 int8* buffer_pointer = reinterpret_cast<int8*>(buffer->address());
2504 uint32 src_height =
2505 unpack_image_height_ > 0 ? unpack_image_height_ : height;
2506 uint32 image_size_dst = buffer_padded_row_size * height;
2507 uint32 image_size_src = pixels_padded_row_size * src_height;
2508 for (GLint ii = 0; ii < num_images; ++ii) {
2509 uint32 my_unpadded_row_size;
2510 if (total_rows == num_rows && ii + 1 == num_images)
2511 my_unpadded_row_size = unpadded_row_size;
2512 else
2513 my_unpadded_row_size = pixels_padded_row_size;
2514 CopyRectToBuffer(
2515 source + ii * image_size_src, my_height, my_unpadded_row_size,
2516 pixels_padded_row_size, false, buffer_pointer + ii * image_size_dst,
2517 buffer_padded_row_size);
2519 } else {
2520 uint32 my_unpadded_row_size;
2521 if (total_rows == num_rows)
2522 my_unpadded_row_size = unpadded_row_size;
2523 else
2524 my_unpadded_row_size = pixels_padded_row_size;
2525 CopyRectToBuffer(
2526 source, my_height, my_unpadded_row_size, pixels_padded_row_size,
2527 false, buffer->address(), buffer_padded_row_size);
2529 helper_->TexSubImage3D(
2530 target, level, xoffset, yoffset + row_index, zoffset + depth_index,
2531 width, my_height, my_depth,
2532 format, type, buffer->shm_id(), buffer->offset(), internal);
2533 buffer->Release();
2535 total_rows -= num_rows;
2536 if (total_rows > 0) {
2537 GLint num_image_paddings;
2538 if (num_images > 0) {
2539 DCHECK_EQ(row_index, 0);
2540 depth_index += num_images;
2541 num_image_paddings = num_images;
2542 } else {
2543 row_index = (row_index + my_height) % height;
2544 num_image_paddings = 0;
2545 if (my_height > 0 && row_index == 0) {
2546 depth_index++;
2547 num_image_paddings++;
2550 source += num_rows * pixels_padded_row_size;
2551 if (unpack_image_height_ > height && num_image_paddings > 0) {
2552 source += num_image_paddings * (unpack_image_height_ - height) *
2553 pixels_padded_row_size;
2559 bool GLES2Implementation::GetActiveAttribHelper(
2560 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2561 GLenum* type, char* name) {
2562 // Clear the bucket so if the command fails nothing will be in it.
2563 helper_->SetBucketSize(kResultBucketId, 0);
2564 typedef cmds::GetActiveAttrib::Result Result;
2565 Result* result = GetResultAs<Result*>();
2566 if (!result) {
2567 return false;
2569 // Set as failed so if the command fails we'll recover.
2570 result->success = false;
2571 helper_->GetActiveAttrib(program, index, kResultBucketId,
2572 GetResultShmId(), GetResultShmOffset());
2573 WaitForCmd();
2574 if (result->success) {
2575 if (size) {
2576 *size = result->size;
2578 if (type) {
2579 *type = result->type;
2581 if (length || name) {
2582 std::vector<int8> str;
2583 GetBucketContents(kResultBucketId, &str);
2584 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2585 std::max(static_cast<size_t>(0),
2586 str.size() - 1));
2587 if (length) {
2588 *length = max_size;
2590 if (name && bufsize > 0) {
2591 memcpy(name, &str[0], max_size);
2592 name[max_size] = '\0';
2596 return result->success != 0;
2599 void GLES2Implementation::GetActiveAttrib(
2600 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2601 GLenum* type, char* name) {
2602 GPU_CLIENT_SINGLE_THREAD_CHECK();
2603 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2604 << program << ", " << index << ", " << bufsize << ", "
2605 << static_cast<const void*>(length) << ", "
2606 << static_cast<const void*>(size) << ", "
2607 << static_cast<const void*>(type) << ", "
2608 << static_cast<const void*>(name) << ", ");
2609 if (bufsize < 0) {
2610 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
2611 return;
2613 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2614 bool success = share_group_->program_info_manager()->GetActiveAttrib(
2615 this, program, index, bufsize, length, size, type, name);
2616 if (success) {
2617 if (size) {
2618 GPU_CLIENT_LOG(" size: " << *size);
2620 if (type) {
2621 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2623 if (name) {
2624 GPU_CLIENT_LOG(" name: " << name);
2627 CheckGLError();
2630 bool GLES2Implementation::GetActiveUniformHelper(
2631 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2632 GLenum* type, char* name) {
2633 // Clear the bucket so if the command fails nothing will be in it.
2634 helper_->SetBucketSize(kResultBucketId, 0);
2635 typedef cmds::GetActiveUniform::Result Result;
2636 Result* result = GetResultAs<Result*>();
2637 if (!result) {
2638 return false;
2640 // Set as failed so if the command fails we'll recover.
2641 result->success = false;
2642 helper_->GetActiveUniform(program, index, kResultBucketId,
2643 GetResultShmId(), GetResultShmOffset());
2644 WaitForCmd();
2645 if (result->success) {
2646 if (size) {
2647 *size = result->size;
2649 if (type) {
2650 *type = result->type;
2652 if (length || name) {
2653 std::vector<int8> str;
2654 GetBucketContents(kResultBucketId, &str);
2655 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2656 std::max(static_cast<size_t>(0),
2657 str.size() - 1));
2658 if (length) {
2659 *length = max_size;
2661 if (name && bufsize > 0) {
2662 memcpy(name, &str[0], max_size);
2663 name[max_size] = '\0';
2667 return result->success != 0;
2670 void GLES2Implementation::GetActiveUniform(
2671 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2672 GLenum* type, char* name) {
2673 GPU_CLIENT_SINGLE_THREAD_CHECK();
2674 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2675 << program << ", " << index << ", " << bufsize << ", "
2676 << static_cast<const void*>(length) << ", "
2677 << static_cast<const void*>(size) << ", "
2678 << static_cast<const void*>(type) << ", "
2679 << static_cast<const void*>(name) << ", ");
2680 if (bufsize < 0) {
2681 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2682 return;
2684 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2685 bool success = share_group_->program_info_manager()->GetActiveUniform(
2686 this, program, index, bufsize, length, size, type, name);
2687 if (success) {
2688 if (size) {
2689 GPU_CLIENT_LOG(" size: " << *size);
2691 if (type) {
2692 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2694 if (name) {
2695 GPU_CLIENT_LOG(" name: " << name);
2698 CheckGLError();
2701 bool GLES2Implementation::GetActiveUniformBlockNameHelper(
2702 GLuint program, GLuint index, GLsizei bufsize,
2703 GLsizei* length, char* name) {
2704 DCHECK_LE(0, bufsize);
2705 // Clear the bucket so if the command fails nothing will be in it.
2706 helper_->SetBucketSize(kResultBucketId, 0);
2707 typedef cmds::GetActiveUniformBlockName::Result Result;
2708 Result* result = GetResultAs<Result*>();
2709 if (!result) {
2710 return false;
2712 // Set as failed so if the command fails we'll recover.
2713 *result = 0;
2714 helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
2715 GetResultShmId(), GetResultShmOffset());
2716 WaitForCmd();
2717 if (*result) {
2718 if (bufsize == 0) {
2719 if (length) {
2720 *length = 0;
2722 } else if (length || name) {
2723 std::vector<int8> str;
2724 GetBucketContents(kResultBucketId, &str);
2725 DCHECK_GT(str.size(), 0u);
2726 GLsizei max_size =
2727 std::min(bufsize, static_cast<GLsizei>(str.size())) - 1;
2728 if (length) {
2729 *length = max_size;
2731 if (name) {
2732 memcpy(name, &str[0], max_size);
2733 name[max_size] = '\0';
2737 return *result != 0;
2740 void GLES2Implementation::GetActiveUniformBlockName(
2741 GLuint program, GLuint index, GLsizei bufsize,
2742 GLsizei* length, char* name) {
2743 GPU_CLIENT_SINGLE_THREAD_CHECK();
2744 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
2745 << program << ", " << index << ", " << bufsize << ", "
2746 << static_cast<const void*>(length) << ", "
2747 << static_cast<const void*>(name) << ")");
2748 if (bufsize < 0) {
2749 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformBlockName", "bufsize < 0");
2750 return;
2752 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockName");
2753 bool success =
2754 share_group_->program_info_manager()->GetActiveUniformBlockName(
2755 this, program, index, bufsize, length, name);
2756 if (success) {
2757 if (name) {
2758 GPU_CLIENT_LOG(" name: " << name);
2761 CheckGLError();
2764 bool GLES2Implementation::GetActiveUniformBlockivHelper(
2765 GLuint program, GLuint index, GLenum pname, GLint* params) {
2766 typedef cmds::GetActiveUniformBlockiv::Result Result;
2767 Result* result = GetResultAs<Result*>();
2768 if (!result) {
2769 return false;
2771 result->SetNumResults(0);
2772 helper_->GetActiveUniformBlockiv(
2773 program, index, pname, GetResultShmId(), GetResultShmOffset());
2774 WaitForCmd();
2775 if (result->GetNumResults() > 0) {
2776 if (params) {
2777 result->CopyResult(params);
2779 GPU_CLIENT_LOG_CODE_BLOCK({
2780 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
2781 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2784 return true;
2786 return false;
2789 void GLES2Implementation::GetActiveUniformBlockiv(
2790 GLuint program, GLuint index, GLenum pname, GLint* params) {
2791 GPU_CLIENT_SINGLE_THREAD_CHECK();
2792 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
2793 << program << ", " << index << ", "
2794 << GLES2Util::GetStringUniformBlockParameter(pname) << ", "
2795 << static_cast<const void*>(params) << ")");
2796 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
2797 bool success =
2798 share_group_->program_info_manager()->GetActiveUniformBlockiv(
2799 this, program, index, pname, params);
2800 if (success) {
2801 if (params) {
2802 // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
2803 // be more than one value returned in params.
2804 GPU_CLIENT_LOG(" params: " << params[0]);
2807 CheckGLError();
2810 bool GLES2Implementation::GetActiveUniformsivHelper(
2811 GLuint program, GLsizei count, const GLuint* indices,
2812 GLenum pname, GLint* params) {
2813 typedef cmds::GetActiveUniformsiv::Result Result;
2814 Result* result = GetResultAs<Result*>();
2815 if (!result) {
2816 return false;
2818 result->SetNumResults(0);
2819 base::CheckedNumeric<size_t> bytes = static_cast<size_t>(count);
2820 bytes *= sizeof(GLuint);
2821 if (!bytes.IsValid()) {
2822 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count overflow");
2823 return false;
2825 SetBucketContents(kResultBucketId, indices, bytes.ValueOrDefault(0));
2826 helper_->GetActiveUniformsiv(
2827 program, kResultBucketId, pname, GetResultShmId(), GetResultShmOffset());
2828 WaitForCmd();
2829 bool success = result->GetNumResults() == count;
2830 if (success) {
2831 if (params) {
2832 result->CopyResult(params);
2834 GPU_CLIENT_LOG_CODE_BLOCK({
2835 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
2836 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2840 helper_->SetBucketSize(kResultBucketId, 0);
2841 return success;
2844 void GLES2Implementation::GetActiveUniformsiv(
2845 GLuint program, GLsizei count, const GLuint* indices,
2846 GLenum pname, GLint* params) {
2847 GPU_CLIENT_SINGLE_THREAD_CHECK();
2848 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv("
2849 << program << ", " << count << ", "
2850 << static_cast<const void*>(indices) << ", "
2851 << GLES2Util::GetStringUniformParameter(pname) << ", "
2852 << static_cast<const void*>(params) << ")");
2853 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
2854 if (count < 0) {
2855 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count < 0");
2856 return;
2858 bool success = share_group_->program_info_manager()->GetActiveUniformsiv(
2859 this, program, count, indices, pname, params);
2860 if (success) {
2861 if (params) {
2862 GPU_CLIENT_LOG_CODE_BLOCK({
2863 for (GLsizei ii = 0; ii < count; ++ii) {
2864 GPU_CLIENT_LOG(" " << ii << ": " << params[ii]);
2869 CheckGLError();
2872 void GLES2Implementation::GetAttachedShaders(
2873 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
2874 GPU_CLIENT_SINGLE_THREAD_CHECK();
2875 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2876 << program << ", " << maxcount << ", "
2877 << static_cast<const void*>(count) << ", "
2878 << static_cast<const void*>(shaders) << ", ");
2879 if (maxcount < 0) {
2880 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
2881 return;
2883 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2884 typedef cmds::GetAttachedShaders::Result Result;
2885 uint32 size = Result::ComputeSize(maxcount);
2886 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
2887 if (!result) {
2888 return;
2890 result->SetNumResults(0);
2891 helper_->GetAttachedShaders(
2892 program,
2893 transfer_buffer_->GetShmId(),
2894 transfer_buffer_->GetOffset(result),
2895 size);
2896 int32 token = helper_->InsertToken();
2897 WaitForCmd();
2898 if (count) {
2899 *count = result->GetNumResults();
2901 result->CopyResult(shaders);
2902 GPU_CLIENT_LOG_CODE_BLOCK({
2903 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2904 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2907 transfer_buffer_->FreePendingToken(result, token);
2908 CheckGLError();
2911 void GLES2Implementation::GetShaderPrecisionFormat(
2912 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
2913 GPU_CLIENT_SINGLE_THREAD_CHECK();
2914 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2915 << GLES2Util::GetStringShaderType(shadertype) << ", "
2916 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
2917 << static_cast<const void*>(range) << ", "
2918 << static_cast<const void*>(precision) << ", ");
2919 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2920 typedef cmds::GetShaderPrecisionFormat::Result Result;
2921 Result* result = GetResultAs<Result*>();
2922 if (!result) {
2923 return;
2926 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
2927 GLStaticState::ShaderPrecisionMap::iterator i =
2928 static_state_.shader_precisions.find(key);
2929 if (i != static_state_.shader_precisions.end()) {
2930 *result = i->second;
2931 } else {
2932 result->success = false;
2933 helper_->GetShaderPrecisionFormat(
2934 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
2935 WaitForCmd();
2936 if (result->success)
2937 static_state_.shader_precisions[key] = *result;
2940 if (result->success) {
2941 if (range) {
2942 range[0] = result->min_range;
2943 range[1] = result->max_range;
2944 GPU_CLIENT_LOG(" min_range: " << range[0]);
2945 GPU_CLIENT_LOG(" min_range: " << range[1]);
2947 if (precision) {
2948 precision[0] = result->precision;
2949 GPU_CLIENT_LOG(" min_range: " << precision[0]);
2952 CheckGLError();
2955 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
2956 const char* result = NULL;
2957 // Clears the bucket so if the command fails nothing will be in it.
2958 helper_->SetBucketSize(kResultBucketId, 0);
2959 helper_->GetString(name, kResultBucketId);
2960 std::string str;
2961 if (GetBucketAsString(kResultBucketId, &str)) {
2962 // Adds extensions implemented on client side only.
2963 switch (name) {
2964 case GL_EXTENSIONS:
2965 str += std::string(str.empty() ? "" : " ") +
2966 "GL_CHROMIUM_flipy "
2967 "GL_EXT_unpack_subimage "
2968 "GL_CHROMIUM_map_sub";
2969 if (capabilities_.image)
2970 str += " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
2971 if (capabilities_.future_sync_points)
2972 str += " GL_CHROMIUM_future_sync_point";
2973 break;
2974 default:
2975 break;
2978 // Because of WebGL the extensions can change. We have to cache each unique
2979 // result since we don't know when the client will stop referring to a
2980 // previous one it queries.
2981 GLStringMap::iterator it = gl_strings_.find(name);
2982 if (it == gl_strings_.end()) {
2983 std::set<std::string> strings;
2984 std::pair<GLStringMap::iterator, bool> insert_result =
2985 gl_strings_.insert(std::make_pair(name, strings));
2986 DCHECK(insert_result.second);
2987 it = insert_result.first;
2989 std::set<std::string>& string_set = it->second;
2990 std::set<std::string>::const_iterator sit = string_set.find(str);
2991 if (sit != string_set.end()) {
2992 result = sit->c_str();
2993 } else {
2994 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2995 string_set.insert(str);
2996 DCHECK(insert_result.second);
2997 result = insert_result.first->c_str();
3000 return reinterpret_cast<const GLubyte*>(result);
3003 const GLubyte* GLES2Implementation::GetString(GLenum name) {
3004 GPU_CLIENT_SINGLE_THREAD_CHECK();
3005 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
3006 << GLES2Util::GetStringStringType(name) << ")");
3007 TRACE_EVENT0("gpu", "GLES2::GetString");
3008 const GLubyte* result = GetStringHelper(name);
3009 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
3010 CheckGLError();
3011 return result;
3014 bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
3015 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3016 GLenum* type, char* name) {
3017 // Clear the bucket so if the command fails nothing will be in it.
3018 helper_->SetBucketSize(kResultBucketId, 0);
3019 typedef cmds::GetTransformFeedbackVarying::Result Result;
3020 Result* result = GetResultAs<Result*>();
3021 if (!result) {
3022 return false;
3024 // Set as failed so if the command fails we'll recover.
3025 result->success = false;
3026 helper_->GetTransformFeedbackVarying(
3027 program, index, kResultBucketId, GetResultShmId(), GetResultShmOffset());
3028 WaitForCmd();
3029 if (result->success) {
3030 if (size) {
3031 *size = result->size;
3033 if (type) {
3034 *type = result->type;
3036 if (length || name) {
3037 std::vector<int8> str;
3038 GetBucketContents(kResultBucketId, &str);
3039 GLsizei max_size = std::min(bufsize, static_cast<GLsizei>(str.size()));
3040 if (max_size > 0) {
3041 --max_size;
3043 if (length) {
3044 *length = max_size;
3046 if (name) {
3047 if (max_size > 0) {
3048 memcpy(name, &str[0], max_size);
3049 name[max_size] = '\0';
3050 } else if (bufsize > 0) {
3051 name[0] = '\0';
3056 return result->success != 0;
3059 void GLES2Implementation::GetTransformFeedbackVarying(
3060 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3061 GLenum* type, char* name) {
3062 GPU_CLIENT_SINGLE_THREAD_CHECK();
3063 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
3064 << program << ", " << index << ", " << bufsize << ", "
3065 << static_cast<const void*>(length) << ", "
3066 << static_cast<const void*>(size) << ", "
3067 << static_cast<const void*>(type) << ", "
3068 << static_cast<const void*>(name) << ", ");
3069 if (bufsize < 0) {
3070 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVarying",
3071 "bufsize < 0");
3072 return;
3074 TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
3075 bool success =
3076 share_group_->program_info_manager()->GetTransformFeedbackVarying(
3077 this, program, index, bufsize, length, size, type, name);
3078 if (success) {
3079 if (size) {
3080 GPU_CLIENT_LOG(" size: " << *size);
3082 if (type) {
3083 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
3085 if (name) {
3086 GPU_CLIENT_LOG(" name: " << name);
3089 CheckGLError();
3092 void GLES2Implementation::GetUniformfv(
3093 GLuint program, GLint location, GLfloat* params) {
3094 GPU_CLIENT_SINGLE_THREAD_CHECK();
3095 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
3096 << program << ", " << location << ", "
3097 << static_cast<const void*>(params) << ")");
3098 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
3099 typedef cmds::GetUniformfv::Result Result;
3100 Result* result = GetResultAs<Result*>();
3101 if (!result) {
3102 return;
3104 result->SetNumResults(0);
3105 helper_->GetUniformfv(
3106 program, location, GetResultShmId(), GetResultShmOffset());
3107 WaitForCmd();
3108 result->CopyResult(params);
3109 GPU_CLIENT_LOG_CODE_BLOCK({
3110 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3111 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3114 CheckGLError();
3117 void GLES2Implementation::GetUniformiv(
3118 GLuint program, GLint location, GLint* params) {
3119 GPU_CLIENT_SINGLE_THREAD_CHECK();
3120 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
3121 << program << ", " << location << ", "
3122 << static_cast<const void*>(params) << ")");
3123 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
3124 typedef cmds::GetUniformiv::Result Result;
3125 Result* result = GetResultAs<Result*>();
3126 if (!result) {
3127 return;
3129 result->SetNumResults(0);
3130 helper_->GetUniformiv(
3131 program, location, GetResultShmId(), GetResultShmOffset());
3132 WaitForCmd();
3133 GetResultAs<cmds::GetUniformfv::Result*>()->CopyResult(params);
3134 GPU_CLIENT_LOG_CODE_BLOCK({
3135 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3136 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3139 CheckGLError();
3142 void GLES2Implementation::ReadPixels(
3143 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
3144 GLenum type, void* pixels) {
3145 GPU_CLIENT_SINGLE_THREAD_CHECK();
3146 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
3147 << xoffset << ", " << yoffset << ", "
3148 << width << ", " << height << ", "
3149 << GLES2Util::GetStringReadPixelFormat(format) << ", "
3150 << GLES2Util::GetStringPixelType(type) << ", "
3151 << static_cast<const void*>(pixels) << ")");
3152 if (width < 0 || height < 0) {
3153 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
3154 return;
3156 if (width == 0 || height == 0) {
3157 return;
3160 // glReadPixel pads the size of each row of pixels by an amount specified by
3161 // glPixelStorei. So, we have to take that into account both in the fact that
3162 // the pixels returned from the ReadPixel command will include that padding
3163 // and that when we copy the results to the user's buffer we need to not
3164 // write those padding bytes but leave them as they are.
3166 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
3167 typedef cmds::ReadPixels::Result Result;
3169 int8* dest = reinterpret_cast<int8*>(pixels);
3170 uint32 temp_size;
3171 uint32 unpadded_row_size;
3172 uint32 padded_row_size;
3173 if (!GLES2Util::ComputeImageDataSizes(
3174 width, 2, 1, format, type, pack_alignment_, &temp_size,
3175 &unpadded_row_size, &padded_row_size)) {
3176 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
3177 return;
3180 if (bound_pixel_pack_transfer_buffer_id_) {
3181 GLuint offset = ToGLuint(pixels);
3182 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3183 bound_pixel_pack_transfer_buffer_id_,
3184 "glReadPixels", offset, padded_row_size * height);
3185 if (buffer && buffer->shm_id() != -1) {
3186 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
3187 buffer->shm_id(), buffer->shm_offset(),
3188 0, 0, true);
3189 CheckGLError();
3191 return;
3194 if (!pixels) {
3195 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
3196 return;
3199 // Transfer by rows.
3200 // The max rows we can transfer.
3201 while (height) {
3202 GLsizei desired_size = padded_row_size * (height - 1) + unpadded_row_size;
3203 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
3204 if (!buffer.valid()) {
3205 return;
3207 GLint num_rows = ComputeNumRowsThatFitInBuffer(
3208 padded_row_size, unpadded_row_size, buffer.size(), height);
3209 num_rows = std::min(num_rows, height);
3210 // NOTE: We must look up the address of the result area AFTER allocation
3211 // of the transfer buffer since the transfer buffer may be reallocated.
3212 Result* result = GetResultAs<Result*>();
3213 if (!result) {
3214 return;
3216 *result = 0; // mark as failed.
3217 helper_->ReadPixels(
3218 xoffset, yoffset, width, num_rows, format, type,
3219 buffer.shm_id(), buffer.offset(),
3220 GetResultShmId(), GetResultShmOffset(),
3221 false);
3222 WaitForCmd();
3223 if (*result != 0) {
3224 // when doing a y-flip we have to iterate through top-to-bottom chunks
3225 // of the dst. The service side handles reversing the rows within a
3226 // chunk.
3227 int8* rows_dst;
3228 if (pack_reverse_row_order_) {
3229 rows_dst = dest + (height - num_rows) * padded_row_size;
3230 } else {
3231 rows_dst = dest;
3233 // We have to copy 1 row at a time to avoid writing pad bytes.
3234 const int8* src = static_cast<const int8*>(buffer.address());
3235 for (GLint yy = 0; yy < num_rows; ++yy) {
3236 memcpy(rows_dst, src, unpadded_row_size);
3237 rows_dst += padded_row_size;
3238 src += padded_row_size;
3240 if (!pack_reverse_row_order_) {
3241 dest = rows_dst;
3244 // If it was not marked as successful exit.
3245 if (*result == 0) {
3246 return;
3248 yoffset += num_rows;
3249 height -= num_rows;
3251 CheckGLError();
3254 void GLES2Implementation::ActiveTexture(GLenum texture) {
3255 GPU_CLIENT_SINGLE_THREAD_CHECK();
3256 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
3257 << GLES2Util::GetStringEnum(texture) << ")");
3258 GLuint texture_index = texture - GL_TEXTURE0;
3259 if (texture_index >=
3260 static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
3261 SetGLErrorInvalidEnum(
3262 "glActiveTexture", texture, "texture");
3263 return;
3266 active_texture_unit_ = texture_index;
3267 helper_->ActiveTexture(texture);
3268 CheckGLError();
3271 void GLES2Implementation::GenBuffersHelper(
3272 GLsizei /* n */, const GLuint* /* buffers */) {
3275 void GLES2Implementation::GenFramebuffersHelper(
3276 GLsizei /* n */, const GLuint* /* framebuffers */) {
3279 void GLES2Implementation::GenRenderbuffersHelper(
3280 GLsizei /* n */, const GLuint* /* renderbuffers */) {
3283 void GLES2Implementation::GenTexturesHelper(
3284 GLsizei /* n */, const GLuint* /* textures */) {
3287 void GLES2Implementation::GenVertexArraysOESHelper(
3288 GLsizei n, const GLuint* arrays) {
3289 vertex_array_object_manager_->GenVertexArrays(n, arrays);
3292 void GLES2Implementation::GenQueriesEXTHelper(
3293 GLsizei /* n */, const GLuint* /* queries */) {
3296 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
3297 GLsizei /* n */,
3298 const GLuint* /* valuebuffers */) {
3301 void GLES2Implementation::GenSamplersHelper(
3302 GLsizei /* n */, const GLuint* /* samplers */) {
3305 void GLES2Implementation::GenTransformFeedbacksHelper(
3306 GLsizei /* n */, const GLuint* /* transformfeedbacks */) {
3309 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
3310 // generates a new resource. On newer versions of OpenGL they don't. The code
3311 // related to binding below will need to change if we switch to the new OpenGL
3312 // model. Specifically it assumes a bind will succeed which is always true in
3313 // the old model but possibly not true in the new model if another context has
3314 // deleted the resource.
3316 // NOTE #2: There is a bug in some BindXXXHelpers, that IDs might be marked as
3317 // used even when Bind has failed. However, the bug is minor compared to the
3318 // overhead & duplicated checking in client side.
3320 void GLES2Implementation::BindBufferHelper(
3321 GLenum target, GLuint buffer_id) {
3322 // TODO(gman): See note #1 above.
3323 bool changed = false;
3324 switch (target) {
3325 case GL_ARRAY_BUFFER:
3326 if (bound_array_buffer_id_ != buffer_id) {
3327 bound_array_buffer_id_ = buffer_id;
3328 changed = true;
3330 break;
3331 case GL_ELEMENT_ARRAY_BUFFER:
3332 changed = vertex_array_object_manager_->BindElementArray(buffer_id);
3333 break;
3334 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3335 bound_pixel_pack_transfer_buffer_id_ = buffer_id;
3336 break;
3337 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3338 bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
3339 break;
3340 default:
3341 changed = true;
3342 break;
3344 // TODO(gman): See note #2 above.
3345 if (changed) {
3346 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3347 this, target, buffer_id, &GLES2Implementation::BindBufferStub);
3351 void GLES2Implementation::BindBufferStub(GLenum target, GLuint buffer) {
3352 helper_->BindBuffer(target, buffer);
3353 if (share_group_->bind_generates_resource())
3354 helper_->CommandBufferHelper::Flush();
3357 void GLES2Implementation::BindBufferBaseHelper(
3358 GLenum target, GLuint index, GLuint buffer_id) {
3359 // TODO(zmo): See note #1 above.
3360 // TODO(zmo): See note #2 above.
3361 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3362 this, target, index, buffer_id, &GLES2Implementation::BindBufferBaseStub);
3365 void GLES2Implementation::BindBufferBaseStub(
3366 GLenum target, GLuint index, GLuint buffer) {
3367 helper_->BindBufferBase(target, index, buffer);
3368 if (share_group_->bind_generates_resource())
3369 helper_->CommandBufferHelper::Flush();
3372 void GLES2Implementation::BindBufferRangeHelper(
3373 GLenum target, GLuint index, GLuint buffer_id,
3374 GLintptr offset, GLsizeiptr size) {
3375 // TODO(zmo): See note #1 above.
3376 // TODO(zmo): See note #2 above.
3377 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3378 this, target, index, buffer_id, offset, size,
3379 &GLES2Implementation::BindBufferRangeStub);
3382 void GLES2Implementation::BindBufferRangeStub(
3383 GLenum target, GLuint index, GLuint buffer,
3384 GLintptr offset, GLsizeiptr size) {
3385 helper_->BindBufferRange(target, index, buffer, offset, size);
3386 if (share_group_->bind_generates_resource())
3387 helper_->CommandBufferHelper::Flush();
3390 void GLES2Implementation::BindFramebufferHelper(
3391 GLenum target, GLuint framebuffer) {
3392 // TODO(gman): See note #1 above.
3393 bool changed = false;
3394 switch (target) {
3395 case GL_FRAMEBUFFER:
3396 if (bound_framebuffer_ != framebuffer ||
3397 bound_read_framebuffer_ != framebuffer) {
3398 bound_framebuffer_ = framebuffer;
3399 bound_read_framebuffer_ = framebuffer;
3400 changed = true;
3402 break;
3403 case GL_READ_FRAMEBUFFER:
3404 if (!IsChromiumFramebufferMultisampleAvailable()) {
3405 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3406 return;
3408 if (bound_read_framebuffer_ != framebuffer) {
3409 bound_read_framebuffer_ = framebuffer;
3410 changed = true;
3412 break;
3413 case GL_DRAW_FRAMEBUFFER:
3414 if (!IsChromiumFramebufferMultisampleAvailable()) {
3415 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3416 return;
3418 if (bound_framebuffer_ != framebuffer) {
3419 bound_framebuffer_ = framebuffer;
3420 changed = true;
3422 break;
3423 default:
3424 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3425 return;
3428 if (changed) {
3429 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(
3430 this, target, framebuffer, &GLES2Implementation::BindFramebufferStub);
3434 void GLES2Implementation::BindFramebufferStub(GLenum target,
3435 GLuint framebuffer) {
3436 helper_->BindFramebuffer(target, framebuffer);
3437 if (share_group_->bind_generates_resource())
3438 helper_->CommandBufferHelper::Flush();
3441 void GLES2Implementation::BindRenderbufferHelper(
3442 GLenum target, GLuint renderbuffer) {
3443 // TODO(gman): See note #1 above.
3444 bool changed = false;
3445 switch (target) {
3446 case GL_RENDERBUFFER:
3447 if (bound_renderbuffer_ != renderbuffer) {
3448 bound_renderbuffer_ = renderbuffer;
3449 changed = true;
3451 break;
3452 default:
3453 changed = true;
3454 break;
3456 // TODO(zmo): See note #2 above.
3457 if (changed) {
3458 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(
3459 this, target, renderbuffer,
3460 &GLES2Implementation::BindRenderbufferStub);
3464 void GLES2Implementation::BindRenderbufferStub(GLenum target,
3465 GLuint renderbuffer) {
3466 helper_->BindRenderbuffer(target, renderbuffer);
3467 if (share_group_->bind_generates_resource())
3468 helper_->CommandBufferHelper::Flush();
3471 void GLES2Implementation::BindSamplerHelper(GLuint unit,
3472 GLuint sampler) {
3473 helper_->BindSampler(unit, sampler);
3476 void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
3477 // TODO(gman): See note #1 above.
3478 // TODO(gman): Change this to false once we figure out why it's failing
3479 // on daisy.
3480 bool changed = true;
3481 TextureUnit& unit = texture_units_[active_texture_unit_];
3482 switch (target) {
3483 case GL_TEXTURE_2D:
3484 if (unit.bound_texture_2d != texture) {
3485 unit.bound_texture_2d = texture;
3486 changed = true;
3488 break;
3489 case GL_TEXTURE_CUBE_MAP:
3490 if (unit.bound_texture_cube_map != texture) {
3491 unit.bound_texture_cube_map = texture;
3492 changed = true;
3494 break;
3495 case GL_TEXTURE_EXTERNAL_OES:
3496 if (unit.bound_texture_external_oes != texture) {
3497 unit.bound_texture_external_oes = texture;
3498 changed = true;
3500 break;
3501 default:
3502 changed = true;
3503 break;
3505 // TODO(gman): See note #2 above.
3506 if (changed) {
3507 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(
3508 this, target, texture, &GLES2Implementation::BindTextureStub);
3512 void GLES2Implementation::BindTextureStub(GLenum target, GLuint texture) {
3513 helper_->BindTexture(target, texture);
3514 if (share_group_->bind_generates_resource())
3515 helper_->CommandBufferHelper::Flush();
3518 void GLES2Implementation::BindTransformFeedbackHelper(
3519 GLenum target, GLuint transformfeedback) {
3520 helper_->BindTransformFeedback(target, transformfeedback);
3523 void GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
3524 bool changed = false;
3525 if (vertex_array_object_manager_->BindVertexArray(array, &changed)) {
3526 if (changed) {
3527 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
3528 // because unlike other resources VertexArrayObject ids must
3529 // be generated by GenVertexArrays. A random id to Bind will not
3530 // generate a new object.
3531 helper_->BindVertexArrayOES(array);
3533 } else {
3534 SetGLError(
3535 GL_INVALID_OPERATION, "glBindVertexArrayOES",
3536 "id was not generated with glGenVertexArrayOES");
3540 void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
3541 GLuint valuebuffer) {
3542 bool changed = false;
3543 switch (target) {
3544 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
3545 if (bound_valuebuffer_ != valuebuffer) {
3546 bound_valuebuffer_ = valuebuffer;
3547 changed = true;
3549 break;
3550 default:
3551 changed = true;
3552 break;
3554 // TODO(gman): See note #2 above.
3555 if (changed) {
3556 GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(
3557 this, target, valuebuffer,
3558 &GLES2Implementation::BindValuebufferCHROMIUMStub);
3562 void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target,
3563 GLuint valuebuffer) {
3564 helper_->BindValuebufferCHROMIUM(target, valuebuffer);
3565 if (share_group_->bind_generates_resource())
3566 helper_->CommandBufferHelper::Flush();
3569 void GLES2Implementation::UseProgramHelper(GLuint program) {
3570 if (current_program_ != program) {
3571 current_program_ = program;
3572 helper_->UseProgram(program);
3576 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
3577 return vertex_array_object_manager_->IsReservedId(id);
3580 void GLES2Implementation::DeleteBuffersHelper(
3581 GLsizei n, const GLuint* buffers) {
3582 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
3583 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
3584 SetGLError(
3585 GL_INVALID_VALUE,
3586 "glDeleteBuffers", "id not created by this context.");
3587 return;
3589 for (GLsizei ii = 0; ii < n; ++ii) {
3590 if (buffers[ii] == bound_array_buffer_id_) {
3591 bound_array_buffer_id_ = 0;
3593 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
3595 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
3596 if (buffer)
3597 RemoveTransferBuffer(buffer);
3599 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
3600 bound_pixel_unpack_transfer_buffer_id_ = 0;
3603 RemoveMappedBufferRangeById(buffers[ii]);
3607 void GLES2Implementation::DeleteBuffersStub(
3608 GLsizei n, const GLuint* buffers) {
3609 helper_->DeleteBuffersImmediate(n, buffers);
3613 void GLES2Implementation::DeleteFramebuffersHelper(
3614 GLsizei n, const GLuint* framebuffers) {
3615 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
3616 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
3617 SetGLError(
3618 GL_INVALID_VALUE,
3619 "glDeleteFramebuffers", "id not created by this context.");
3620 return;
3622 for (GLsizei ii = 0; ii < n; ++ii) {
3623 if (framebuffers[ii] == bound_framebuffer_) {
3624 bound_framebuffer_ = 0;
3626 if (framebuffers[ii] == bound_read_framebuffer_) {
3627 bound_read_framebuffer_ = 0;
3632 void GLES2Implementation::DeleteFramebuffersStub(
3633 GLsizei n, const GLuint* framebuffers) {
3634 helper_->DeleteFramebuffersImmediate(n, framebuffers);
3637 void GLES2Implementation::DeleteRenderbuffersHelper(
3638 GLsizei n, const GLuint* renderbuffers) {
3639 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
3640 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
3641 SetGLError(
3642 GL_INVALID_VALUE,
3643 "glDeleteRenderbuffers", "id not created by this context.");
3644 return;
3646 for (GLsizei ii = 0; ii < n; ++ii) {
3647 if (renderbuffers[ii] == bound_renderbuffer_) {
3648 bound_renderbuffer_ = 0;
3653 void GLES2Implementation::DeleteRenderbuffersStub(
3654 GLsizei n, const GLuint* renderbuffers) {
3655 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
3658 void GLES2Implementation::DeleteTexturesHelper(
3659 GLsizei n, const GLuint* textures) {
3660 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
3661 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
3662 SetGLError(
3663 GL_INVALID_VALUE,
3664 "glDeleteTextures", "id not created by this context.");
3665 return;
3667 for (GLsizei ii = 0; ii < n; ++ii) {
3668 for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
3669 ++tt) {
3670 TextureUnit& unit = texture_units_[tt];
3671 if (textures[ii] == unit.bound_texture_2d) {
3672 unit.bound_texture_2d = 0;
3674 if (textures[ii] == unit.bound_texture_cube_map) {
3675 unit.bound_texture_cube_map = 0;
3677 if (textures[ii] == unit.bound_texture_external_oes) {
3678 unit.bound_texture_external_oes = 0;
3684 void GLES2Implementation::DeleteTexturesStub(GLsizei n,
3685 const GLuint* textures) {
3686 helper_->DeleteTexturesImmediate(n, textures);
3689 void GLES2Implementation::DeleteVertexArraysOESHelper(
3690 GLsizei n, const GLuint* arrays) {
3691 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
3692 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
3693 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
3694 SetGLError(
3695 GL_INVALID_VALUE,
3696 "glDeleteVertexArraysOES", "id not created by this context.");
3697 return;
3701 void GLES2Implementation::DeleteVertexArraysOESStub(
3702 GLsizei n, const GLuint* arrays) {
3703 helper_->DeleteVertexArraysOESImmediate(n, arrays);
3706 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
3707 GLsizei n,
3708 const GLuint* valuebuffers) {
3709 if (!GetIdHandler(id_namespaces::kValuebuffers)
3710 ->FreeIds(this, n, valuebuffers,
3711 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
3712 SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
3713 "id not created by this context.");
3714 return;
3716 for (GLsizei ii = 0; ii < n; ++ii) {
3717 if (valuebuffers[ii] == bound_valuebuffer_) {
3718 bound_valuebuffer_ = 0;
3723 void GLES2Implementation::DeleteSamplersStub(
3724 GLsizei n, const GLuint* samplers) {
3725 helper_->DeleteSamplersImmediate(n, samplers);
3728 void GLES2Implementation::DeleteSamplersHelper(
3729 GLsizei n, const GLuint* samplers) {
3730 if (!GetIdHandler(id_namespaces::kSamplers)->FreeIds(
3731 this, n, samplers, &GLES2Implementation::DeleteSamplersStub)) {
3732 SetGLError(
3733 GL_INVALID_VALUE,
3734 "glDeleteSamplers", "id not created by this context.");
3735 return;
3739 void GLES2Implementation::DeleteTransformFeedbacksStub(
3740 GLsizei n, const GLuint* transformfeedbacks) {
3741 helper_->DeleteTransformFeedbacksImmediate(n, transformfeedbacks);
3744 void GLES2Implementation::DeleteTransformFeedbacksHelper(
3745 GLsizei n, const GLuint* transformfeedbacks) {
3746 if (!GetIdHandler(id_namespaces::kTransformFeedbacks)->FreeIds(
3747 this, n, transformfeedbacks,
3748 &GLES2Implementation::DeleteTransformFeedbacksStub)) {
3749 SetGLError(
3750 GL_INVALID_VALUE,
3751 "glDeleteTransformFeedbacks", "id not created by this context.");
3752 return;
3756 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
3757 GLsizei n,
3758 const GLuint* valuebuffers) {
3759 helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
3762 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
3763 GPU_CLIENT_SINGLE_THREAD_CHECK();
3764 GPU_CLIENT_LOG(
3765 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
3766 vertex_array_object_manager_->SetAttribEnable(index, false);
3767 helper_->DisableVertexAttribArray(index);
3768 CheckGLError();
3771 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
3772 GPU_CLIENT_SINGLE_THREAD_CHECK();
3773 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
3774 << index << ")");
3775 vertex_array_object_manager_->SetAttribEnable(index, true);
3776 helper_->EnableVertexAttribArray(index);
3777 CheckGLError();
3780 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
3781 GPU_CLIENT_SINGLE_THREAD_CHECK();
3782 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
3783 << GLES2Util::GetStringDrawMode(mode) << ", "
3784 << first << ", " << count << ")");
3785 if (count < 0) {
3786 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
3787 return;
3789 bool simulated = false;
3790 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
3791 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
3792 return;
3794 helper_->DrawArrays(mode, first, count);
3795 RestoreArrayBuffer(simulated);
3796 CheckGLError();
3799 void GLES2Implementation::GetVertexAttribfv(
3800 GLuint index, GLenum pname, GLfloat* params) {
3801 GPU_CLIENT_SINGLE_THREAD_CHECK();
3802 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
3803 << index << ", "
3804 << GLES2Util::GetStringVertexAttribute(pname) << ", "
3805 << static_cast<const void*>(params) << ")");
3806 uint32 value = 0;
3807 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
3808 *params = static_cast<float>(value);
3809 return;
3811 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
3812 typedef cmds::GetVertexAttribfv::Result Result;
3813 Result* result = GetResultAs<Result*>();
3814 if (!result) {
3815 return;
3817 result->SetNumResults(0);
3818 helper_->GetVertexAttribfv(
3819 index, pname, GetResultShmId(), GetResultShmOffset());
3820 WaitForCmd();
3821 result->CopyResult(params);
3822 GPU_CLIENT_LOG_CODE_BLOCK({
3823 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3824 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3827 CheckGLError();
3830 void GLES2Implementation::GetVertexAttribiv(
3831 GLuint index, GLenum pname, GLint* params) {
3832 GPU_CLIENT_SINGLE_THREAD_CHECK();
3833 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
3834 << index << ", "
3835 << GLES2Util::GetStringVertexAttribute(pname) << ", "
3836 << static_cast<const void*>(params) << ")");
3837 uint32 value = 0;
3838 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
3839 *params = value;
3840 return;
3842 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
3843 typedef cmds::GetVertexAttribiv::Result Result;
3844 Result* result = GetResultAs<Result*>();
3845 if (!result) {
3846 return;
3848 result->SetNumResults(0);
3849 helper_->GetVertexAttribiv(
3850 index, pname, GetResultShmId(), GetResultShmOffset());
3851 WaitForCmd();
3852 result->CopyResult(params);
3853 GPU_CLIENT_LOG_CODE_BLOCK({
3854 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3855 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3858 CheckGLError();
3861 void GLES2Implementation::Swap() {
3862 SwapBuffers();
3865 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
3866 PostSubBufferCHROMIUM(
3867 sub_buffer.x(), sub_buffer.y(), sub_buffer.width(), sub_buffer.height());
3870 static GLenum GetGLESOverlayTransform(gfx::OverlayTransform plane_transform) {
3871 switch (plane_transform) {
3872 case gfx::OVERLAY_TRANSFORM_INVALID:
3873 break;
3874 case gfx::OVERLAY_TRANSFORM_NONE:
3875 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
3876 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
3877 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM;
3878 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
3879 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM;
3880 case gfx::OVERLAY_TRANSFORM_ROTATE_90:
3881 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM;
3882 case gfx::OVERLAY_TRANSFORM_ROTATE_180:
3883 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM;
3884 case gfx::OVERLAY_TRANSFORM_ROTATE_270:
3885 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM;
3887 NOTREACHED();
3888 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
3891 void GLES2Implementation::ScheduleOverlayPlane(
3892 int plane_z_order,
3893 gfx::OverlayTransform plane_transform,
3894 unsigned overlay_texture_id,
3895 const gfx::Rect& display_bounds,
3896 const gfx::RectF& uv_rect) {
3897 ScheduleOverlayPlaneCHROMIUM(plane_z_order,
3898 GetGLESOverlayTransform(plane_transform),
3899 overlay_texture_id,
3900 display_bounds.x(),
3901 display_bounds.y(),
3902 display_bounds.width(),
3903 display_bounds.height(),
3904 uv_rect.x(),
3905 uv_rect.y(),
3906 uv_rect.width(),
3907 uv_rect.height());
3910 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
3911 const char* feature) {
3912 GPU_CLIENT_SINGLE_THREAD_CHECK();
3913 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
3914 << feature << ")");
3915 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
3916 typedef cmds::EnableFeatureCHROMIUM::Result Result;
3917 Result* result = GetResultAs<Result*>();
3918 if (!result) {
3919 return false;
3921 *result = 0;
3922 SetBucketAsCString(kResultBucketId, feature);
3923 helper_->EnableFeatureCHROMIUM(
3924 kResultBucketId, GetResultShmId(), GetResultShmOffset());
3925 WaitForCmd();
3926 helper_->SetBucketSize(kResultBucketId, 0);
3927 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
3928 return *result != 0;
3931 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
3932 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
3933 GPU_CLIENT_SINGLE_THREAD_CHECK();
3934 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
3935 << target << ", " << offset << ", " << size << ", "
3936 << GLES2Util::GetStringEnum(access) << ")");
3937 // NOTE: target is NOT checked because the service will check it
3938 // and we don't know what targets are valid.
3939 if (access != GL_WRITE_ONLY) {
3940 SetGLErrorInvalidEnum(
3941 "glMapBufferSubDataCHROMIUM", access, "access");
3942 return NULL;
3944 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
3945 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
3946 return NULL;
3949 int32 shm_id;
3950 unsigned int shm_offset;
3951 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
3952 if (!mem) {
3953 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
3954 return NULL;
3957 std::pair<MappedBufferMap::iterator, bool> result =
3958 mapped_buffers_.insert(std::make_pair(
3959 mem,
3960 MappedBuffer(
3961 access, shm_id, mem, shm_offset, target, offset, size)));
3962 DCHECK(result.second);
3963 GPU_CLIENT_LOG(" returned " << mem);
3964 return mem;
3967 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
3968 GPU_CLIENT_SINGLE_THREAD_CHECK();
3969 GPU_CLIENT_LOG(
3970 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
3971 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
3972 if (it == mapped_buffers_.end()) {
3973 SetGLError(
3974 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
3975 return;
3977 const MappedBuffer& mb = it->second;
3978 helper_->BufferSubData(
3979 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
3980 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
3981 mapped_buffers_.erase(it);
3982 CheckGLError();
3985 GLuint GLES2Implementation::GetBoundBufferHelper(GLenum target) {
3986 GLenum binding = GLES2Util::MapBufferTargetToBindingEnum(target);
3987 GLint id = 0;
3988 bool cached = GetHelper(binding, &id);
3989 DCHECK(cached);
3990 return static_cast<GLuint>(id);
3993 void GLES2Implementation::RemoveMappedBufferRangeByTarget(GLenum target) {
3994 GLuint buffer = GetBoundBufferHelper(target);
3995 RemoveMappedBufferRangeById(buffer);
3998 void GLES2Implementation::RemoveMappedBufferRangeById(GLuint buffer) {
3999 if (buffer > 0) {
4000 auto iter = mapped_buffer_range_map_.find(buffer);
4001 if (iter != mapped_buffer_range_map_.end() && iter->second.shm_memory) {
4002 mapped_memory_->FreePendingToken(
4003 iter->second.shm_memory, helper_->InsertToken());
4004 mapped_buffer_range_map_.erase(iter);
4009 void GLES2Implementation::ClearMappedBufferRangeMap() {
4010 for (auto& buffer_range : mapped_buffer_range_map_) {
4011 if (buffer_range.second.shm_memory) {
4012 mapped_memory_->FreePendingToken(
4013 buffer_range.second.shm_memory, helper_->InsertToken());
4016 mapped_buffer_range_map_.clear();
4019 void* GLES2Implementation::MapBufferRange(
4020 GLenum target, GLintptr offset, GLsizeiptr size, GLbitfield access) {
4021 GPU_CLIENT_SINGLE_THREAD_CHECK();
4022 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferRange("
4023 << GLES2Util::GetStringEnum(target) << ", " << offset << ", "
4024 << size << ", " << access << ")");
4025 if (!ValidateSize("glMapBufferRange", size) ||
4026 !ValidateOffset("glMapBufferRange", offset)) {
4027 return nullptr;
4030 int32 shm_id;
4031 unsigned int shm_offset;
4032 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4033 if (!mem) {
4034 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferRange", "out of memory");
4035 return nullptr;
4038 typedef cmds::MapBufferRange::Result Result;
4039 Result* result = GetResultAs<Result*>();
4040 *result = 0;
4041 helper_->MapBufferRange(target, offset, size, access, shm_id, shm_offset,
4042 GetResultShmId(), GetResultShmOffset());
4043 // TODO(zmo): For write only mode with MAP_INVALID_*_BIT, we should
4044 // consider an early return without WaitForCmd(). crbug.com/465804.
4045 WaitForCmd();
4046 if (*result) {
4047 const GLbitfield kInvalidateBits =
4048 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
4049 if ((access & kInvalidateBits) != 0) {
4050 // We do not read back from the buffer, therefore, we set the client
4051 // side memory to zero to avoid uninitialized data.
4052 memset(mem, 0, size);
4054 GLuint buffer = GetBoundBufferHelper(target);
4055 DCHECK_NE(0u, buffer);
4056 // glMapBufferRange fails on an already mapped buffer.
4057 DCHECK(mapped_buffer_range_map_.find(buffer) ==
4058 mapped_buffer_range_map_.end());
4059 auto iter = mapped_buffer_range_map_.insert(std::make_pair(
4060 buffer,
4061 MappedBuffer(access, shm_id, mem, shm_offset, target, offset, size)));
4062 DCHECK(iter.second);
4063 } else {
4064 mapped_memory_->Free(mem);
4065 mem = nullptr;
4068 GPU_CLIENT_LOG(" returned " << mem);
4069 CheckGLError();
4070 return mem;
4073 GLboolean GLES2Implementation::UnmapBuffer(GLenum target) {
4074 GPU_CLIENT_SINGLE_THREAD_CHECK();
4075 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapBuffer("
4076 << GLES2Util::GetStringEnum(target) << ")");
4077 switch (target) {
4078 case GL_ARRAY_BUFFER:
4079 case GL_ELEMENT_ARRAY_BUFFER:
4080 case GL_COPY_READ_BUFFER:
4081 case GL_COPY_WRITE_BUFFER:
4082 case GL_PIXEL_PACK_BUFFER:
4083 case GL_PIXEL_UNPACK_BUFFER:
4084 case GL_TRANSFORM_FEEDBACK_BUFFER:
4085 case GL_UNIFORM_BUFFER:
4086 break;
4087 default:
4088 SetGLError(GL_INVALID_ENUM, "glUnmapBuffer", "invalid target");
4089 return GL_FALSE;
4091 GLuint buffer = GetBoundBufferHelper(target);
4092 if (buffer == 0) {
4093 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "no buffer bound");
4094 return GL_FALSE;
4096 auto iter = mapped_buffer_range_map_.find(buffer);
4097 if (iter == mapped_buffer_range_map_.end()) {
4098 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "buffer is unmapped");
4099 return GL_FALSE;
4102 helper_->UnmapBuffer(target);
4103 RemoveMappedBufferRangeById(buffer);
4104 // TODO(zmo): There is a rare situation that data might be corrupted and
4105 // GL_FALSE should be returned. We lose context on that sitatuon, so we
4106 // don't have to WaitForCmd().
4107 GPU_CLIENT_LOG(" returned " << GL_TRUE);
4108 CheckGLError();
4109 return GL_TRUE;
4112 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
4113 GLenum target,
4114 GLint level,
4115 GLint xoffset,
4116 GLint yoffset,
4117 GLsizei width,
4118 GLsizei height,
4119 GLenum format,
4120 GLenum type,
4121 GLenum access) {
4122 GPU_CLIENT_SINGLE_THREAD_CHECK();
4123 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
4124 << target << ", " << level << ", "
4125 << xoffset << ", " << yoffset << ", "
4126 << width << ", " << height << ", "
4127 << GLES2Util::GetStringTextureFormat(format) << ", "
4128 << GLES2Util::GetStringPixelType(type) << ", "
4129 << GLES2Util::GetStringEnum(access) << ")");
4130 if (access != GL_WRITE_ONLY) {
4131 SetGLErrorInvalidEnum(
4132 "glMapTexSubImage2DCHROMIUM", access, "access");
4133 return NULL;
4135 // NOTE: target is NOT checked because the service will check it
4136 // and we don't know what targets are valid.
4137 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
4138 SetGLError(
4139 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
4140 return NULL;
4142 uint32 size;
4143 if (!GLES2Util::ComputeImageDataSizes(
4144 width, height, 1, format, type, unpack_alignment_, &size, NULL, NULL)) {
4145 SetGLError(
4146 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
4147 return NULL;
4149 int32 shm_id;
4150 unsigned int shm_offset;
4151 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4152 if (!mem) {
4153 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
4154 return NULL;
4157 std::pair<MappedTextureMap::iterator, bool> result =
4158 mapped_textures_.insert(std::make_pair(
4159 mem,
4160 MappedTexture(
4161 access, shm_id, mem, shm_offset,
4162 target, level, xoffset, yoffset, width, height, format, type)));
4163 DCHECK(result.second);
4164 GPU_CLIENT_LOG(" returned " << mem);
4165 return mem;
4168 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
4169 GPU_CLIENT_SINGLE_THREAD_CHECK();
4170 GPU_CLIENT_LOG(
4171 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
4172 MappedTextureMap::iterator it = mapped_textures_.find(mem);
4173 if (it == mapped_textures_.end()) {
4174 SetGLError(
4175 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
4176 return;
4178 const MappedTexture& mt = it->second;
4179 helper_->TexSubImage2D(
4180 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
4181 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
4182 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
4183 mapped_textures_.erase(it);
4184 CheckGLError();
4187 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
4188 float scale_factor) {
4189 GPU_CLIENT_SINGLE_THREAD_CHECK();
4190 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
4191 << width << ", " << height << ", " << scale_factor << ")");
4192 helper_->ResizeCHROMIUM(width, height, scale_factor);
4193 CheckGLError();
4196 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
4197 GPU_CLIENT_SINGLE_THREAD_CHECK();
4198 GPU_CLIENT_LOG("[" << GetLogPrefix()
4199 << "] glGetRequestableExtensionsCHROMIUM()");
4200 TRACE_EVENT0("gpu",
4201 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
4202 const char* result = NULL;
4203 // Clear the bucket so if the command fails nothing will be in it.
4204 helper_->SetBucketSize(kResultBucketId, 0);
4205 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
4206 std::string str;
4207 if (GetBucketAsString(kResultBucketId, &str)) {
4208 // The set of requestable extensions shrinks as we enable
4209 // them. Because we don't know when the client will stop referring
4210 // to a previous one it queries (see GetString) we need to cache
4211 // the unique results.
4212 std::set<std::string>::const_iterator sit =
4213 requestable_extensions_set_.find(str);
4214 if (sit != requestable_extensions_set_.end()) {
4215 result = sit->c_str();
4216 } else {
4217 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
4218 requestable_extensions_set_.insert(str);
4219 DCHECK(insert_result.second);
4220 result = insert_result.first->c_str();
4223 GPU_CLIENT_LOG(" returned " << result);
4224 return reinterpret_cast<const GLchar*>(result);
4227 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
4228 // with VirtualGL contexts.
4229 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
4230 GPU_CLIENT_SINGLE_THREAD_CHECK();
4231 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
4232 << extension << ")");
4233 SetBucketAsCString(kResultBucketId, extension);
4234 helper_->RequestExtensionCHROMIUM(kResultBucketId);
4235 helper_->SetBucketSize(kResultBucketId, 0);
4237 struct ExtensionCheck {
4238 const char* extension;
4239 ExtensionStatus* status;
4241 const ExtensionCheck checks[] = {
4243 "GL_ANGLE_pack_reverse_row_order",
4244 &angle_pack_reverse_row_order_status_,
4247 "GL_CHROMIUM_framebuffer_multisample",
4248 &chromium_framebuffer_multisample_,
4251 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
4252 for (size_t ii = 0; ii < kNumChecks; ++ii) {
4253 const ExtensionCheck& check = checks[ii];
4254 if (*check.status == kUnavailableExtensionStatus &&
4255 !strcmp(extension, check.extension)) {
4256 *check.status = kUnknownExtensionStatus;
4261 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
4262 GPU_CLIENT_SINGLE_THREAD_CHECK();
4263 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
4264 // Wait if this would add too many rate limit tokens.
4265 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
4266 helper_->WaitForToken(rate_limit_tokens_.front());
4267 rate_limit_tokens_.pop();
4269 rate_limit_tokens_.push(helper_->InsertToken());
4272 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
4273 GLuint program, std::vector<int8>* result) {
4274 DCHECK(result);
4275 // Clear the bucket so if the command fails nothing will be in it.
4276 helper_->SetBucketSize(kResultBucketId, 0);
4277 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
4278 GetBucketContents(kResultBucketId, result);
4281 void GLES2Implementation::GetProgramInfoCHROMIUM(
4282 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4283 GPU_CLIENT_SINGLE_THREAD_CHECK();
4284 if (bufsize < 0) {
4285 SetGLError(
4286 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
4287 return;
4289 if (size == NULL) {
4290 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
4291 return;
4293 // Make sure they've set size to 0 else the value will be undefined on
4294 // lost context.
4295 DCHECK_EQ(0, *size);
4296 std::vector<int8> result;
4297 GetProgramInfoCHROMIUMHelper(program, &result);
4298 if (result.empty()) {
4299 return;
4301 *size = result.size();
4302 if (!info) {
4303 return;
4305 if (static_cast<size_t>(bufsize) < result.size()) {
4306 SetGLError(GL_INVALID_OPERATION,
4307 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
4308 return;
4310 memcpy(info, &result[0], result.size());
4313 void GLES2Implementation::GetUniformBlocksCHROMIUMHelper(
4314 GLuint program, std::vector<int8>* result) {
4315 DCHECK(result);
4316 // Clear the bucket so if the command fails nothing will be in it.
4317 helper_->SetBucketSize(kResultBucketId, 0);
4318 helper_->GetUniformBlocksCHROMIUM(program, kResultBucketId);
4319 GetBucketContents(kResultBucketId, result);
4322 void GLES2Implementation::GetUniformBlocksCHROMIUM(
4323 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4324 GPU_CLIENT_SINGLE_THREAD_CHECK();
4325 if (bufsize < 0) {
4326 SetGLError(
4327 GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "bufsize less than 0.");
4328 return;
4330 if (size == NULL) {
4331 SetGLError(GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "size is null.");
4332 return;
4334 // Make sure they've set size to 0 else the value will be undefined on
4335 // lost context.
4336 DCHECK_EQ(0, *size);
4337 std::vector<int8> result;
4338 GetUniformBlocksCHROMIUMHelper(program, &result);
4339 if (result.empty()) {
4340 return;
4342 *size = result.size();
4343 if (!info) {
4344 return;
4346 if (static_cast<size_t>(bufsize) < result.size()) {
4347 SetGLError(GL_INVALID_OPERATION, "glGetUniformBlocksCHROMIUM",
4348 "bufsize is too small for result.");
4349 return;
4351 memcpy(info, &result[0], result.size());
4354 void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
4355 GLuint program, std::vector<int8>* result) {
4356 DCHECK(result);
4357 // Clear the bucket so if the command fails nothing will be in it.
4358 helper_->SetBucketSize(kResultBucketId, 0);
4359 helper_->GetUniformsES3CHROMIUM(program, kResultBucketId);
4360 GetBucketContents(kResultBucketId, result);
4363 void GLES2Implementation::GetUniformsES3CHROMIUM(
4364 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4365 GPU_CLIENT_SINGLE_THREAD_CHECK();
4366 if (bufsize < 0) {
4367 SetGLError(
4368 GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "bufsize less than 0.");
4369 return;
4371 if (size == NULL) {
4372 SetGLError(GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "size is null.");
4373 return;
4375 // Make sure they've set size to 0 else the value will be undefined on
4376 // lost context.
4377 DCHECK_EQ(0, *size);
4378 std::vector<int8> result;
4379 GetUniformsES3CHROMIUMHelper(program, &result);
4380 if (result.empty()) {
4381 return;
4383 *size = result.size();
4384 if (!info) {
4385 return;
4387 if (static_cast<size_t>(bufsize) < result.size()) {
4388 SetGLError(GL_INVALID_OPERATION,
4389 "glGetUniformsES3CHROMIUM", "bufsize is too small for result.");
4390 return;
4392 memcpy(info, &result[0], result.size());
4395 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
4396 GLuint program, std::vector<int8>* result) {
4397 DCHECK(result);
4398 // Clear the bucket so if the command fails nothing will be in it.
4399 helper_->SetBucketSize(kResultBucketId, 0);
4400 helper_->GetTransformFeedbackVaryingsCHROMIUM(program, kResultBucketId);
4401 GetBucketContents(kResultBucketId, result);
4404 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(
4405 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4406 GPU_CLIENT_SINGLE_THREAD_CHECK();
4407 if (bufsize < 0) {
4408 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4409 "bufsize less than 0.");
4410 return;
4412 if (size == NULL) {
4413 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4414 "size is null.");
4415 return;
4417 // Make sure they've set size to 0 else the value will be undefined on
4418 // lost context.
4419 DCHECK_EQ(0, *size);
4420 std::vector<int8> result;
4421 GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
4422 if (result.empty()) {
4423 return;
4425 *size = result.size();
4426 if (!info) {
4427 return;
4429 if (static_cast<size_t>(bufsize) < result.size()) {
4430 SetGLError(GL_INVALID_OPERATION, "glGetTransformFeedbackVaryingsCHROMIUM",
4431 "bufsize is too small for result.");
4432 return;
4434 memcpy(info, &result[0], result.size());
4437 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
4438 GPU_CLIENT_SINGLE_THREAD_CHECK();
4439 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
4440 << texture << ")");
4441 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
4442 helper_->CommandBufferHelper::Flush();
4443 return gpu_control_->CreateStreamTexture(texture);
4446 void GLES2Implementation::PostSubBufferCHROMIUM(
4447 GLint x, GLint y, GLint width, GLint height) {
4448 GPU_CLIENT_SINGLE_THREAD_CHECK();
4449 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
4450 << x << ", " << y << ", " << width << ", " << height << ")");
4451 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
4452 "width", width, "height", height);
4454 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
4455 swap_buffers_tokens_.push(helper_->InsertToken());
4456 helper_->PostSubBufferCHROMIUM(x, y, width, height);
4457 helper_->CommandBufferHelper::Flush();
4458 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
4459 helper_->WaitForToken(swap_buffers_tokens_.front());
4460 swap_buffers_tokens_.pop();
4464 void GLES2Implementation::DeleteQueriesEXTHelper(
4465 GLsizei n, const GLuint* queries) {
4466 for (GLsizei ii = 0; ii < n; ++ii) {
4467 query_tracker_->RemoveQuery(queries[ii]);
4468 query_id_allocator_->FreeID(queries[ii]);
4471 helper_->DeleteQueriesEXTImmediate(n, queries);
4474 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
4475 GPU_CLIENT_SINGLE_THREAD_CHECK();
4476 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
4478 // TODO(gman): To be spec compliant IDs from other contexts sharing
4479 // resources need to return true here even though you can't share
4480 // queries across contexts?
4481 return query_tracker_->GetQuery(id) != NULL;
4484 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
4485 GPU_CLIENT_SINGLE_THREAD_CHECK();
4486 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
4487 << GLES2Util::GetStringQueryTarget(target)
4488 << ", " << id << ")");
4490 // if any outstanding queries INV_OP
4491 QueryMap::iterator it = current_queries_.find(target);
4492 if (it != current_queries_.end()) {
4493 SetGLError(
4494 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
4495 return;
4498 // id = 0 INV_OP
4499 if (id == 0) {
4500 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
4501 return;
4504 // if not GENned INV_OPERATION
4505 if (!query_id_allocator_->InUse(id)) {
4506 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "invalid id");
4507 return;
4510 // if id does not have an object
4511 QueryTracker::Query* query = query_tracker_->GetQuery(id);
4512 if (!query) {
4513 query = query_tracker_->CreateQuery(id, target);
4514 if (!query) {
4515 SetGLError(GL_OUT_OF_MEMORY,
4516 "glBeginQueryEXT",
4517 "transfer buffer allocation failed");
4518 return;
4520 } else if (query->target() != target) {
4521 SetGLError(
4522 GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
4523 return;
4526 current_queries_[target] = query;
4528 query->Begin(this);
4529 CheckGLError();
4532 void GLES2Implementation::EndQueryEXT(GLenum target) {
4533 GPU_CLIENT_SINGLE_THREAD_CHECK();
4534 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
4535 << GLES2Util::GetStringQueryTarget(target) << ")");
4536 // Don't do anything if the context is lost.
4537 if (helper_->IsContextLost()) {
4538 return;
4541 QueryMap::iterator it = current_queries_.find(target);
4542 if (it == current_queries_.end()) {
4543 SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
4544 return;
4547 QueryTracker::Query* query = it->second;
4548 query->End(this);
4549 current_queries_.erase(it);
4550 CheckGLError();
4553 void GLES2Implementation::GetQueryivEXT(
4554 GLenum target, GLenum pname, GLint* params) {
4555 GPU_CLIENT_SINGLE_THREAD_CHECK();
4556 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
4557 << GLES2Util::GetStringQueryTarget(target) << ", "
4558 << GLES2Util::GetStringQueryParameter(pname) << ", "
4559 << static_cast<const void*>(params) << ")");
4561 if (pname != GL_CURRENT_QUERY_EXT) {
4562 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
4563 return;
4565 QueryMap::iterator it = current_queries_.find(target);
4566 if (it != current_queries_.end()) {
4567 QueryTracker::Query* query = it->second;
4568 *params = query->id();
4569 } else {
4570 *params = 0;
4572 GPU_CLIENT_LOG(" " << *params);
4573 CheckGLError();
4576 void GLES2Implementation::GetQueryObjectuivEXT(
4577 GLuint id, GLenum pname, GLuint* params) {
4578 GPU_CLIENT_SINGLE_THREAD_CHECK();
4579 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
4580 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
4581 << static_cast<const void*>(params) << ")");
4583 QueryTracker::Query* query = query_tracker_->GetQuery(id);
4584 if (!query) {
4585 SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
4586 return;
4589 QueryMap::iterator it = current_queries_.find(query->target());
4590 if (it != current_queries_.end()) {
4591 SetGLError(
4592 GL_INVALID_OPERATION,
4593 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
4594 return;
4597 if (query->NeverUsed()) {
4598 SetGLError(
4599 GL_INVALID_OPERATION,
4600 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
4601 return;
4604 switch (pname) {
4605 case GL_QUERY_RESULT_EXT:
4606 if (!query->CheckResultsAvailable(helper_)) {
4607 helper_->WaitForToken(query->token());
4608 if (!query->CheckResultsAvailable(helper_)) {
4609 FinishHelper();
4610 CHECK(query->CheckResultsAvailable(helper_));
4613 *params = query->GetResult();
4614 break;
4615 case GL_QUERY_RESULT_AVAILABLE_EXT:
4616 *params = query->CheckResultsAvailable(helper_);
4617 break;
4618 default:
4619 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
4620 break;
4622 GPU_CLIENT_LOG(" " << *params);
4623 CheckGLError();
4626 void GLES2Implementation::DrawArraysInstancedANGLE(
4627 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
4628 GPU_CLIENT_SINGLE_THREAD_CHECK();
4629 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
4630 << GLES2Util::GetStringDrawMode(mode) << ", "
4631 << first << ", " << count << ", " << primcount << ")");
4632 if (count < 0) {
4633 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
4634 return;
4636 if (primcount < 0) {
4637 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
4638 return;
4640 if (primcount == 0) {
4641 return;
4643 bool simulated = false;
4644 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
4645 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
4646 &simulated)) {
4647 return;
4649 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
4650 RestoreArrayBuffer(simulated);
4651 CheckGLError();
4654 void GLES2Implementation::DrawElementsInstancedANGLE(
4655 GLenum mode, GLsizei count, GLenum type, const void* indices,
4656 GLsizei primcount) {
4657 GPU_CLIENT_SINGLE_THREAD_CHECK();
4658 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
4659 << GLES2Util::GetStringDrawMode(mode) << ", "
4660 << count << ", "
4661 << GLES2Util::GetStringIndexType(type) << ", "
4662 << static_cast<const void*>(indices) << ", "
4663 << primcount << ")");
4664 if (count < 0) {
4665 SetGLError(GL_INVALID_VALUE,
4666 "glDrawElementsInstancedANGLE", "count less than 0.");
4667 return;
4669 if (count == 0) {
4670 return;
4672 if (primcount < 0) {
4673 SetGLError(GL_INVALID_VALUE,
4674 "glDrawElementsInstancedANGLE", "primcount < 0");
4675 return;
4677 if (primcount == 0) {
4678 return;
4680 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
4681 !ValidateOffset("glDrawElementsInstancedANGLE",
4682 reinterpret_cast<GLintptr>(indices))) {
4683 return;
4685 GLuint offset = 0;
4686 bool simulated = false;
4687 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
4688 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
4689 indices, &offset, &simulated)) {
4690 return;
4692 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
4693 RestoreElementAndArrayBuffers(simulated);
4694 CheckGLError();
4697 void GLES2Implementation::GenMailboxCHROMIUM(
4698 GLbyte* mailbox) {
4699 GPU_CLIENT_SINGLE_THREAD_CHECK();
4700 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
4701 << static_cast<const void*>(mailbox) << ")");
4702 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
4704 gpu::Mailbox result = gpu::Mailbox::Generate();
4705 memcpy(mailbox, result.name, sizeof(result.name));
4708 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target,
4709 const GLbyte* data) {
4710 GPU_CLIENT_SINGLE_THREAD_CHECK();
4711 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
4712 << static_cast<const void*>(data) << ")");
4713 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4714 DCHECK(mailbox.Verify()) << "ProduceTextureCHROMIUM was passed a "
4715 "mailbox that was not generated by "
4716 "GenMailboxCHROMIUM.";
4717 helper_->ProduceTextureCHROMIUMImmediate(target, data);
4718 CheckGLError();
4721 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
4722 GLuint texture, GLenum target, const GLbyte* data) {
4723 GPU_CLIENT_SINGLE_THREAD_CHECK();
4724 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
4725 << static_cast<const void*>(data) << ")");
4726 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4727 DCHECK(mailbox.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
4728 "mailbox that was not generated by "
4729 "GenMailboxCHROMIUM.";
4730 helper_->ProduceTextureDirectCHROMIUMImmediate(texture, target, data);
4731 CheckGLError();
4734 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target,
4735 const GLbyte* data) {
4736 GPU_CLIENT_SINGLE_THREAD_CHECK();
4737 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
4738 << static_cast<const void*>(data) << ")");
4739 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4740 DCHECK(mailbox.Verify()) << "ConsumeTextureCHROMIUM was passed a "
4741 "mailbox that was not generated by "
4742 "GenMailboxCHROMIUM.";
4743 helper_->ConsumeTextureCHROMIUMImmediate(target, data);
4744 CheckGLError();
4747 GLuint GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
4748 GLenum target, const GLbyte* data) {
4749 GPU_CLIENT_SINGLE_THREAD_CHECK();
4750 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
4751 << static_cast<const void*>(data) << ")");
4752 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4753 DCHECK(mailbox.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
4754 "mailbox that was not generated by "
4755 "GenMailboxCHROMIUM.";
4756 GLuint client_id;
4757 GetIdHandler(id_namespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
4758 helper_->CreateAndConsumeTextureCHROMIUMImmediate(target,
4759 client_id, data);
4760 if (share_group_->bind_generates_resource())
4761 helper_->CommandBufferHelper::Flush();
4762 CheckGLError();
4763 return client_id;
4766 void GLES2Implementation::PushGroupMarkerEXT(
4767 GLsizei length, const GLchar* marker) {
4768 GPU_CLIENT_SINGLE_THREAD_CHECK();
4769 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
4770 << length << ", " << marker << ")");
4771 if (!marker) {
4772 marker = "";
4774 SetBucketAsString(
4775 kResultBucketId,
4776 (length ? std::string(marker, length) : std::string(marker)));
4777 helper_->PushGroupMarkerEXT(kResultBucketId);
4778 helper_->SetBucketSize(kResultBucketId, 0);
4779 debug_marker_manager_.PushGroup(
4780 length ? std::string(marker, length) : std::string(marker));
4783 void GLES2Implementation::InsertEventMarkerEXT(
4784 GLsizei length, const GLchar* marker) {
4785 GPU_CLIENT_SINGLE_THREAD_CHECK();
4786 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
4787 << length << ", " << marker << ")");
4788 if (!marker) {
4789 marker = "";
4791 SetBucketAsString(
4792 kResultBucketId,
4793 (length ? std::string(marker, length) : std::string(marker)));
4794 helper_->InsertEventMarkerEXT(kResultBucketId);
4795 helper_->SetBucketSize(kResultBucketId, 0);
4796 debug_marker_manager_.SetMarker(
4797 length ? std::string(marker, length) : std::string(marker));
4800 void GLES2Implementation::PopGroupMarkerEXT() {
4801 GPU_CLIENT_SINGLE_THREAD_CHECK();
4802 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
4803 helper_->PopGroupMarkerEXT();
4804 debug_marker_manager_.PopGroup();
4807 void GLES2Implementation::TraceBeginCHROMIUM(
4808 const char* category_name, const char* trace_name) {
4809 GPU_CLIENT_SINGLE_THREAD_CHECK();
4810 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
4811 << category_name << ", " << trace_name << ")");
4812 SetBucketAsCString(kResultBucketId, category_name);
4813 SetBucketAsCString(kResultBucketId + 1, trace_name);
4814 helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1);
4815 helper_->SetBucketSize(kResultBucketId, 0);
4816 helper_->SetBucketSize(kResultBucketId + 1, 0);
4817 current_trace_stack_++;
4820 void GLES2Implementation::TraceEndCHROMIUM() {
4821 GPU_CLIENT_SINGLE_THREAD_CHECK();
4822 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
4823 if (current_trace_stack_ == 0) {
4824 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
4825 "missing begin trace");
4826 return;
4828 helper_->TraceEndCHROMIUM();
4829 current_trace_stack_--;
4832 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
4833 GPU_CLIENT_SINGLE_THREAD_CHECK();
4834 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
4835 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
4836 switch (target) {
4837 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
4838 if (access != GL_READ_ONLY) {
4839 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
4840 return NULL;
4842 break;
4843 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
4844 if (access != GL_WRITE_ONLY) {
4845 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
4846 return NULL;
4848 break;
4849 default:
4850 SetGLError(
4851 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
4852 return NULL;
4854 GLuint buffer_id;
4855 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
4856 if (!buffer_id) {
4857 return NULL;
4859 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
4860 if (!buffer) {
4861 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
4862 return NULL;
4864 if (buffer->mapped()) {
4865 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
4866 return NULL;
4868 // Here we wait for previous transfer operations to be finished.
4869 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
4870 // with this method of synchronization. Until this is fixed,
4871 // MapBufferCHROMIUM will not block even if the transfer is not ready
4872 // for these calls.
4873 if (buffer->last_usage_token()) {
4874 helper_->WaitForToken(buffer->last_usage_token());
4875 buffer->set_last_usage_token(0);
4877 buffer->set_mapped(true);
4879 GPU_CLIENT_LOG(" returned " << buffer->address());
4880 CheckGLError();
4881 return buffer->address();
4884 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
4885 GPU_CLIENT_SINGLE_THREAD_CHECK();
4886 GPU_CLIENT_LOG(
4887 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
4888 GLuint buffer_id;
4889 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
4890 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
4892 if (!buffer_id) {
4893 return false;
4895 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
4896 if (!buffer) {
4897 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
4898 return false;
4900 if (!buffer->mapped()) {
4901 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
4902 return false;
4904 buffer->set_mapped(false);
4905 CheckGLError();
4906 return true;
4909 bool GLES2Implementation::EnsureAsyncUploadSync() {
4910 if (async_upload_sync_)
4911 return true;
4913 int32 shm_id;
4914 unsigned int shm_offset;
4915 void* mem = mapped_memory_->Alloc(sizeof(AsyncUploadSync),
4916 &shm_id,
4917 &shm_offset);
4918 if (!mem)
4919 return false;
4921 async_upload_sync_shm_id_ = shm_id;
4922 async_upload_sync_shm_offset_ = shm_offset;
4923 async_upload_sync_ = static_cast<AsyncUploadSync*>(mem);
4924 async_upload_sync_->Reset();
4926 return true;
4929 uint32 GLES2Implementation::NextAsyncUploadToken() {
4930 async_upload_token_++;
4931 if (async_upload_token_ == 0)
4932 async_upload_token_++;
4933 return async_upload_token_;
4936 void GLES2Implementation::PollAsyncUploads() {
4937 if (!async_upload_sync_)
4938 return;
4940 if (helper_->IsContextLost()) {
4941 DetachedAsyncUploadMemoryList::iterator it =
4942 detached_async_upload_memory_.begin();
4943 while (it != detached_async_upload_memory_.end()) {
4944 mapped_memory_->Free(it->first);
4945 it = detached_async_upload_memory_.erase(it);
4947 return;
4950 DetachedAsyncUploadMemoryList::iterator it =
4951 detached_async_upload_memory_.begin();
4952 while (it != detached_async_upload_memory_.end()) {
4953 if (HasAsyncUploadTokenPassed(it->second)) {
4954 mapped_memory_->Free(it->first);
4955 it = detached_async_upload_memory_.erase(it);
4956 } else {
4957 break;
4962 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
4963 // Free all completed unmanaged async uploads buffers.
4964 PollAsyncUploads();
4966 // Synchronously free rest of the unmanaged async upload buffers.
4967 if (!detached_async_upload_memory_.empty()) {
4968 WaitAllAsyncTexImage2DCHROMIUM();
4969 WaitForCmd();
4970 PollAsyncUploads();
4974 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
4975 GLenum target, GLint level, GLenum internalformat, GLsizei width,
4976 GLsizei height, GLint border, GLenum format, GLenum type,
4977 const void* pixels) {
4978 GPU_CLIENT_SINGLE_THREAD_CHECK();
4979 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
4980 << GLES2Util::GetStringTextureTarget(target) << ", "
4981 << level << ", "
4982 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
4983 << width << ", " << height << ", " << border << ", "
4984 << GLES2Util::GetStringTextureFormat(format) << ", "
4985 << GLES2Util::GetStringPixelType(type) << ", "
4986 << static_cast<const void*>(pixels) << ")");
4987 if (level < 0 || height < 0 || width < 0) {
4988 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
4989 return;
4991 if (border != 0) {
4992 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
4993 return;
4995 uint32 size;
4996 uint32 unpadded_row_size;
4997 uint32 padded_row_size;
4998 if (!GLES2Util::ComputeImageDataSizes(
4999 width, height, 1, format, type, unpack_alignment_, &size,
5000 &unpadded_row_size, &padded_row_size)) {
5001 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
5002 return;
5005 // If there's no data/buffer just issue the AsyncTexImage2D
5006 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
5007 helper_->AsyncTexImage2DCHROMIUM(
5008 target, level, internalformat, width, height, format, type,
5009 0, 0, 0, 0, 0);
5010 return;
5013 if (!EnsureAsyncUploadSync()) {
5014 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
5015 return;
5018 // Otherwise, async uploads require a transfer buffer to be bound.
5019 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
5020 // the buffer before the transfer is finished. (Currently such
5021 // synchronization has to be handled manually.)
5022 GLuint offset = ToGLuint(pixels);
5023 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
5024 bound_pixel_unpack_transfer_buffer_id_,
5025 "glAsyncTexImage2DCHROMIUM", offset, size);
5026 if (buffer && buffer->shm_id() != -1) {
5027 uint32 async_token = NextAsyncUploadToken();
5028 buffer->set_last_async_upload_token(async_token);
5029 helper_->AsyncTexImage2DCHROMIUM(
5030 target, level, internalformat, width, height, format, type,
5031 buffer->shm_id(), buffer->shm_offset() + offset,
5032 async_token,
5033 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
5037 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
5038 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
5039 GLsizei height, GLenum format, GLenum type, const void* pixels) {
5040 GPU_CLIENT_SINGLE_THREAD_CHECK();
5041 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
5042 << GLES2Util::GetStringTextureTarget(target) << ", "
5043 << level << ", "
5044 << xoffset << ", " << yoffset << ", "
5045 << width << ", " << height << ", "
5046 << GLES2Util::GetStringTextureFormat(format) << ", "
5047 << GLES2Util::GetStringPixelType(type) << ", "
5048 << static_cast<const void*>(pixels) << ")");
5049 if (level < 0 || height < 0 || width < 0) {
5050 SetGLError(
5051 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
5052 return;
5055 uint32 size;
5056 uint32 unpadded_row_size;
5057 uint32 padded_row_size;
5058 if (!GLES2Util::ComputeImageDataSizes(
5059 width, height, 1, format, type, unpack_alignment_, &size,
5060 &unpadded_row_size, &padded_row_size)) {
5061 SetGLError(
5062 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
5063 return;
5066 if (!EnsureAsyncUploadSync()) {
5067 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
5068 return;
5071 // Async uploads require a transfer buffer to be bound.
5072 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
5073 // the buffer before the transfer is finished. (Currently such
5074 // synchronization has to be handled manually.)
5075 GLuint offset = ToGLuint(pixels);
5076 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
5077 bound_pixel_unpack_transfer_buffer_id_,
5078 "glAsyncTexSubImage2DCHROMIUM", offset, size);
5079 if (buffer && buffer->shm_id() != -1) {
5080 uint32 async_token = NextAsyncUploadToken();
5081 buffer->set_last_async_upload_token(async_token);
5082 helper_->AsyncTexSubImage2DCHROMIUM(
5083 target, level, xoffset, yoffset, width, height, format, type,
5084 buffer->shm_id(), buffer->shm_offset() + offset,
5085 async_token,
5086 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
5090 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
5091 GPU_CLIENT_SINGLE_THREAD_CHECK();
5092 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
5093 << GLES2Util::GetStringTextureTarget(target) << ")");
5094 helper_->WaitAsyncTexImage2DCHROMIUM(target);
5095 CheckGLError();
5098 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
5099 GPU_CLIENT_SINGLE_THREAD_CHECK();
5100 GPU_CLIENT_LOG("[" << GetLogPrefix()
5101 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
5102 helper_->WaitAllAsyncTexImage2DCHROMIUM();
5103 CheckGLError();
5106 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
5107 GPU_CLIENT_SINGLE_THREAD_CHECK();
5108 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
5109 helper_->CommandBufferHelper::Flush();
5110 return gpu_control_->InsertSyncPoint();
5113 GLuint GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
5114 GPU_CLIENT_SINGLE_THREAD_CHECK();
5115 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
5116 DCHECK(capabilities_.future_sync_points);
5117 return gpu_control_->InsertFutureSyncPoint();
5120 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point) {
5121 GPU_CLIENT_SINGLE_THREAD_CHECK();
5122 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
5123 << sync_point << ")");
5124 DCHECK(capabilities_.future_sync_points);
5125 helper_->CommandBufferHelper::Flush();
5126 gpu_control_->RetireSyncPoint(sync_point);
5129 namespace {
5131 bool ValidImageFormat(GLenum internalformat) {
5132 switch (internalformat) {
5133 case GL_R8:
5134 case GL_RGB:
5135 case GL_RGBA:
5136 case GL_BGRA_EXT:
5137 return true;
5138 default:
5139 return false;
5143 bool ValidImageUsage(GLenum usage) {
5144 switch (usage) {
5145 case GL_MAP_CHROMIUM:
5146 case GL_SCANOUT_CHROMIUM:
5147 return true;
5148 default:
5149 return false;
5153 } // namespace
5155 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer,
5156 GLsizei width,
5157 GLsizei height,
5158 GLenum internalformat) {
5159 if (width <= 0) {
5160 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
5161 return 0;
5164 if (height <= 0) {
5165 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
5166 return 0;
5169 if (!ValidImageFormat(internalformat)) {
5170 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "invalid format");
5171 return 0;
5174 int32_t image_id =
5175 gpu_control_->CreateImage(buffer, width, height, internalformat);
5176 if (image_id < 0) {
5177 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "image_id < 0");
5178 return 0;
5180 return image_id;
5183 GLuint GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer,
5184 GLsizei width,
5185 GLsizei height,
5186 GLenum internalformat) {
5187 GPU_CLIENT_SINGLE_THREAD_CHECK();
5188 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
5189 << ", " << height << ", "
5190 << GLES2Util::GetStringImageInternalFormat(internalformat)
5191 << ")");
5192 GLuint image_id =
5193 CreateImageCHROMIUMHelper(buffer, width, height, internalformat);
5194 CheckGLError();
5195 return image_id;
5198 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
5199 // Flush the command stream to make sure all pending commands
5200 // that may refer to the image_id are executed on the service side.
5201 helper_->CommandBufferHelper::Flush();
5202 gpu_control_->DestroyImage(image_id);
5205 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
5206 GPU_CLIENT_SINGLE_THREAD_CHECK();
5207 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
5208 << image_id << ")");
5209 DestroyImageCHROMIUMHelper(image_id);
5210 CheckGLError();
5213 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
5214 GLsizei width,
5215 GLsizei height,
5216 GLenum internalformat,
5217 GLenum usage) {
5218 if (width <= 0) {
5219 SetGLError(
5220 GL_INVALID_VALUE, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
5221 return 0;
5224 if (height <= 0) {
5225 SetGLError(GL_INVALID_VALUE,
5226 "glCreateGpuMemoryBufferImageCHROMIUM",
5227 "height <= 0");
5228 return 0;
5231 if (!ValidImageFormat(internalformat)) {
5232 SetGLError(GL_INVALID_VALUE,
5233 "glCreateGpuMemoryBufferImageCHROMIUM",
5234 "invalid format");
5235 return 0;
5238 if (!ValidImageUsage(usage)) {
5239 SetGLError(GL_INVALID_VALUE,
5240 "glCreateGpuMemoryBufferImageCHROMIUM",
5241 "invalid usage");
5242 return 0;
5245 // Flush the command stream to ensure ordering in case the newly
5246 // returned image_id has recently been in use with a different buffer.
5247 helper_->CommandBufferHelper::Flush();
5248 int32_t image_id = gpu_control_->CreateGpuMemoryBufferImage(
5249 width, height, internalformat, usage);
5250 if (image_id < 0) {
5251 SetGLError(GL_OUT_OF_MEMORY,
5252 "glCreateGpuMemoryBufferImageCHROMIUM",
5253 "image_id < 0");
5254 return 0;
5256 return image_id;
5259 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
5260 GLsizei width,
5261 GLsizei height,
5262 GLenum internalformat,
5263 GLenum usage) {
5264 GPU_CLIENT_SINGLE_THREAD_CHECK();
5265 GPU_CLIENT_LOG("[" << GetLogPrefix()
5266 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
5267 << ", " << height << ", "
5268 << GLES2Util::GetStringImageInternalFormat(internalformat)
5269 << ", " << GLES2Util::GetStringImageUsage(usage) << ")");
5270 GLuint image_id = CreateGpuMemoryBufferImageCHROMIUMHelper(
5271 width, height, internalformat, usage);
5272 CheckGLError();
5273 return image_id;
5276 bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
5277 if (size < 0) {
5278 SetGLError(GL_INVALID_VALUE, func, "size < 0");
5279 return false;
5281 if (!base::IsValueInRangeForNumericType<int32_t>(size)) {
5282 SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
5283 return false;
5285 return true;
5288 bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
5289 if (offset < 0) {
5290 SetGLError(GL_INVALID_VALUE, func, "offset < 0");
5291 return false;
5293 if (!base::IsValueInRangeForNumericType<int32_t>(offset)) {
5294 SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
5295 return false;
5297 return true;
5300 bool GLES2Implementation::GetSamplerParameterfvHelper(
5301 GLuint /* sampler */, GLenum /* pname */, GLfloat* /* params */) {
5302 // TODO(zmo): Implement client side caching.
5303 return false;
5306 bool GLES2Implementation::GetSamplerParameterivHelper(
5307 GLuint /* sampler */, GLenum /* pname */, GLint* /* params */) {
5308 // TODO(zmo): Implement client side caching.
5309 return false;
5312 bool GLES2Implementation::PackStringsToBucket(GLsizei count,
5313 const char* const* str,
5314 const GLint* length,
5315 const char* func_name) {
5316 DCHECK_LE(0, count);
5317 // Compute the total size.
5318 base::CheckedNumeric<size_t> total_size = count;
5319 total_size += 1;
5320 total_size *= sizeof(GLint);
5321 if (!total_size.IsValid()) {
5322 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5323 return false;
5325 size_t header_size = total_size.ValueOrDefault(0);
5326 std::vector<GLint> header(count + 1);
5327 header[0] = static_cast<GLint>(count);
5328 for (GLsizei ii = 0; ii < count; ++ii) {
5329 GLint len = 0;
5330 if (str[ii]) {
5331 len = (length && length[ii] >= 0)
5332 ? length[ii]
5333 : base::checked_cast<GLint>(strlen(str[ii]));
5335 total_size += len;
5336 total_size += 1; // NULL at the end of each char array.
5337 if (!total_size.IsValid()) {
5338 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5339 return false;
5341 header[ii + 1] = len;
5343 // Pack data into a bucket on the service.
5344 helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
5345 size_t offset = 0;
5346 for (GLsizei ii = 0; ii <= count; ++ii) {
5347 const char* src =
5348 (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
5349 base::CheckedNumeric<size_t> checked_size =
5350 (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
5351 if (ii > 0) {
5352 checked_size += 1; // NULL in the end.
5354 if (!checked_size.IsValid()) {
5355 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5356 return false;
5358 size_t size = checked_size.ValueOrDefault(0);
5359 while (size) {
5360 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
5361 if (!buffer.valid() || buffer.size() == 0) {
5362 SetGLError(GL_OUT_OF_MEMORY, func_name, "too large");
5363 return false;
5365 size_t copy_size = buffer.size();
5366 if (ii > 0 && buffer.size() == size)
5367 --copy_size;
5368 if (copy_size)
5369 memcpy(buffer.address(), src, copy_size);
5370 if (copy_size < buffer.size()) {
5371 // Append NULL in the end.
5372 DCHECK(copy_size + 1 == buffer.size());
5373 char* str = reinterpret_cast<char*>(buffer.address());
5374 str[copy_size] = 0;
5376 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
5377 buffer.shm_id(), buffer.offset());
5378 offset += buffer.size();
5379 src += buffer.size();
5380 size -= buffer.size();
5383 DCHECK_EQ(total_size.ValueOrDefault(0), offset);
5384 return true;
5387 void GLES2Implementation::UniformBlockBinding(GLuint program,
5388 GLuint index,
5389 GLuint binding) {
5390 GPU_CLIENT_SINGLE_THREAD_CHECK();
5391 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
5392 << ", " << index << ", " << binding << ")");
5393 share_group_->program_info_manager()->UniformBlockBinding(
5394 this, program, index, binding);
5395 helper_->UniformBlockBinding(program, index, binding);
5396 CheckGLError();
5399 GLenum GLES2Implementation::ClientWaitSync(
5400 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5401 GPU_CLIENT_SINGLE_THREAD_CHECK();
5402 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync
5403 << ", " << flags << ", " << timeout << ")");
5404 typedef cmds::ClientWaitSync::Result Result;
5405 Result* result = GetResultAs<Result*>();
5406 if (!result) {
5407 SetGLError(GL_OUT_OF_MEMORY, "ClientWaitSync", "");
5408 return GL_WAIT_FAILED;
5410 *result = GL_WAIT_FAILED;
5411 uint32_t v32_0 = 0, v32_1 = 0;
5412 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5413 helper_->ClientWaitSync(
5414 ToGLuint(sync), flags, v32_0, v32_1,
5415 GetResultShmId(), GetResultShmOffset());
5416 WaitForCmd();
5417 GPU_CLIENT_LOG("returned " << *result);
5418 CheckGLError();
5419 return *result;
5422 void GLES2Implementation::WaitSync(
5423 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5424 GPU_CLIENT_SINGLE_THREAD_CHECK();
5425 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync << ", "
5426 << flags << ", " << timeout << ")");
5427 uint32_t v32_0 = 0, v32_1 = 0;
5428 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5429 helper_->WaitSync(ToGLuint(sync), flags, v32_0, v32_1);
5430 CheckGLError();
5433 // Include the auto-generated part of this file. We split this because it means
5434 // we can easily edit the non-auto generated parts right here in this file
5435 // instead of having to edit some template or the code generator.
5436 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
5438 } // namespace gles2
5439 } // namespace gpu