Revert "Reland c91b178b07b0d - Delete dead signin code (SigninGlobalError)"
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blob52df605bb96d0868d6ddcaca3b1e842c1f51b37c
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/gl2.h>
10 #include <GLES2/gl2ext.h>
11 #include <GLES2/gl2extchromium.h>
12 #include <GLES3/gl3.h>
13 #include <algorithm>
14 #include <map>
15 #include <set>
16 #include <sstream>
17 #include <string>
18 #include "base/compiler_specific.h"
19 #include "gpu/command_buffer/client/buffer_tracker.h"
20 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
21 #include "gpu/command_buffer/client/gpu_control.h"
22 #include "gpu/command_buffer/client/program_info_manager.h"
23 #include "gpu/command_buffer/client/query_tracker.h"
24 #include "gpu/command_buffer/client/transfer_buffer.h"
25 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
26 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
27 #include "gpu/command_buffer/common/id_allocator.h"
28 #include "gpu/command_buffer/common/trace_event.h"
30 #if defined(GPU_CLIENT_DEBUG)
31 #include "base/command_line.h"
32 #include "gpu/command_buffer/client/gpu_switches.h"
33 #endif
35 namespace gpu {
36 namespace gles2 {
38 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
39 static GLuint ToGLuint(const void* ptr) {
40 return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
43 #if !defined(_MSC_VER)
44 const size_t GLES2Implementation::kMaxSizeOfSimpleResult;
45 const unsigned int GLES2Implementation::kStartingOffset;
46 #endif
48 GLES2Implementation::GLStaticState::GLStaticState() {
51 GLES2Implementation::GLStaticState::~GLStaticState() {
54 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
55 GLES2Implementation* gles2_implementation)
56 : gles2_implementation_(gles2_implementation) {
57 CHECK_EQ(0, gles2_implementation_->use_count_);
58 ++gles2_implementation_->use_count_;
61 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
62 --gles2_implementation_->use_count_;
63 CHECK_EQ(0, gles2_implementation_->use_count_);
66 GLES2Implementation::GLES2Implementation(
67 GLES2CmdHelper* helper,
68 ShareGroup* share_group,
69 TransferBufferInterface* transfer_buffer,
70 bool bind_generates_resource,
71 bool lose_context_when_out_of_memory,
72 bool support_client_side_arrays,
73 GpuControl* gpu_control)
74 : helper_(helper),
75 transfer_buffer_(transfer_buffer),
76 angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
77 chromium_framebuffer_multisample_(kUnknownExtensionStatus),
78 pack_alignment_(4),
79 unpack_alignment_(4),
80 unpack_row_length_(0),
81 unpack_image_height_(0),
82 unpack_skip_rows_(0),
83 unpack_skip_pixels_(0),
84 unpack_skip_images_(0),
85 pack_reverse_row_order_(false),
86 active_texture_unit_(0),
87 bound_framebuffer_(0),
88 bound_read_framebuffer_(0),
89 bound_renderbuffer_(0),
90 bound_valuebuffer_(0),
91 current_program_(0),
92 bound_array_buffer_(0),
93 bound_copy_read_buffer_(0),
94 bound_copy_write_buffer_(0),
95 bound_pixel_pack_buffer_(0),
96 bound_pixel_unpack_buffer_(0),
97 bound_transform_feedback_buffer_(0),
98 bound_uniform_buffer_(0),
99 bound_pixel_pack_transfer_buffer_id_(0),
100 bound_pixel_unpack_transfer_buffer_id_(0),
101 async_upload_token_(0),
102 async_upload_sync_(NULL),
103 async_upload_sync_shm_id_(0),
104 async_upload_sync_shm_offset_(0),
105 error_bits_(0),
106 debug_(false),
107 lose_context_when_out_of_memory_(lose_context_when_out_of_memory),
108 support_client_side_arrays_(support_client_side_arrays),
109 use_count_(0),
110 error_message_callback_(NULL),
111 current_trace_stack_(0),
112 gpu_control_(gpu_control),
113 capabilities_(gpu_control->GetCapabilities()),
114 aggressively_free_resources_(false),
115 weak_ptr_factory_(this) {
116 DCHECK(helper);
117 DCHECK(transfer_buffer);
118 DCHECK(gpu_control);
120 std::stringstream ss;
121 ss << std::hex << this;
122 this_in_hex_ = ss.str();
124 GPU_CLIENT_LOG_CODE_BLOCK({
125 debug_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
126 switches::kEnableGPUClientLogging);
129 share_group_ =
130 (share_group ? share_group : new ShareGroup(bind_generates_resource));
131 DCHECK(share_group_->bind_generates_resource() == bind_generates_resource);
133 memset(&reserved_ids_, 0, sizeof(reserved_ids_));
136 bool GLES2Implementation::Initialize(
137 unsigned int starting_transfer_buffer_size,
138 unsigned int min_transfer_buffer_size,
139 unsigned int max_transfer_buffer_size,
140 unsigned int mapped_memory_limit) {
141 TRACE_EVENT0("gpu", "GLES2Implementation::Initialize");
142 DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
143 DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
144 DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
146 if (!transfer_buffer_->Initialize(
147 starting_transfer_buffer_size,
148 kStartingOffset,
149 min_transfer_buffer_size,
150 max_transfer_buffer_size,
151 kAlignment,
152 kSizeToFlush)) {
153 return false;
156 mapped_memory_.reset(
157 new MappedMemoryManager(
158 helper_,
159 base::Bind(&GLES2Implementation::PollAsyncUploads,
160 // The mapped memory manager is owned by |this| here, and
161 // since its destroyed before before we destroy ourselves
162 // we don't need extra safety measures for this closure.
163 base::Unretained(this)),
164 mapped_memory_limit));
166 unsigned chunk_size = 2 * 1024 * 1024;
167 if (mapped_memory_limit != kNoLimit) {
168 // Use smaller chunks if the client is very memory conscientious.
169 chunk_size = std::min(mapped_memory_limit / 4, chunk_size);
171 mapped_memory_->set_chunk_size_multiple(chunk_size);
173 GLStaticState::ShaderPrecisionMap* shader_precisions =
174 &static_state_.shader_precisions;
175 capabilities_.VisitPrecisions([shader_precisions](
176 GLenum shader, GLenum type, Capabilities::ShaderPrecision* result) {
177 const GLStaticState::ShaderPrecisionKey key(shader, type);
178 cmds::GetShaderPrecisionFormat::Result cached_result = {
179 true, result->min_range, result->max_range, result->precision};
180 shader_precisions->insert(std::make_pair(key, cached_result));
183 util_.set_num_compressed_texture_formats(
184 capabilities_.num_compressed_texture_formats);
185 util_.set_num_shader_binary_formats(capabilities_.num_shader_binary_formats);
187 texture_units_.reset(
188 new TextureUnit[capabilities_.max_combined_texture_image_units]);
190 query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
191 buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
193 query_id_allocator_.reset(new IdAllocator());
194 if (support_client_side_arrays_) {
195 GetIdHandler(id_namespaces::kBuffers)->MakeIds(
196 this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
199 vertex_array_object_manager_.reset(new VertexArrayObjectManager(
200 capabilities_.max_vertex_attribs, reserved_ids_[0], reserved_ids_[1],
201 support_client_side_arrays_));
203 // GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
204 // on Client & Service.
205 if (capabilities_.bind_generates_resource_chromium !=
206 (share_group_->bind_generates_resource() ? 1 : 0)) {
207 SetGLError(GL_INVALID_OPERATION,
208 "Initialize",
209 "Service bind_generates_resource mismatch.");
210 return false;
213 return true;
216 GLES2Implementation::~GLES2Implementation() {
217 // Make sure the queries are finished otherwise we'll delete the
218 // shared memory (mapped_memory_) which will free the memory used
219 // by the queries. The GPU process when validating that memory is still
220 // shared will fail and abort (ie, it will stop running).
221 WaitForCmd();
222 query_tracker_.reset();
224 // GLES2Implementation::Initialize() could fail before allocating
225 // reserved_ids_, so we need delete them carefully.
226 if (support_client_side_arrays_ && reserved_ids_[0]) {
227 DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
230 // Release remaining BufferRange mem; This is when a MapBufferRange() is
231 // called but not the UnmapBuffer() pair.
232 ClearMappedBufferRangeMap();
234 // Release any per-context data in share group.
235 share_group_->FreeContext(this);
237 buffer_tracker_.reset();
239 FreeAllAsyncUploadBuffers();
241 if (async_upload_sync_) {
242 mapped_memory_->Free(async_upload_sync_);
243 async_upload_sync_ = NULL;
246 // Make sure the commands make it the service.
247 WaitForCmd();
250 GLES2CmdHelper* GLES2Implementation::helper() const {
251 return helper_;
254 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
255 return share_group_->GetIdHandler(namespace_id);
258 RangeIdHandlerInterface* GLES2Implementation::GetRangeIdHandler(
259 int namespace_id) const {
260 return share_group_->GetRangeIdHandler(namespace_id);
263 IdAllocator* GLES2Implementation::GetIdAllocator(int namespace_id) const {
264 if (namespace_id == id_namespaces::kQueries)
265 return query_id_allocator_.get();
266 NOTREACHED();
267 return NULL;
270 void* GLES2Implementation::GetResultBuffer() {
271 return transfer_buffer_->GetResultBuffer();
274 int32 GLES2Implementation::GetResultShmId() {
275 return transfer_buffer_->GetShmId();
278 uint32 GLES2Implementation::GetResultShmOffset() {
279 return transfer_buffer_->GetResultOffset();
282 void GLES2Implementation::FreeUnusedSharedMemory() {
283 mapped_memory_->FreeUnused();
286 void GLES2Implementation::FreeEverything() {
287 FreeAllAsyncUploadBuffers();
288 WaitForCmd();
289 query_tracker_->Shrink();
290 FreeUnusedSharedMemory();
291 transfer_buffer_->Free();
292 helper_->FreeRingBuffer();
295 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
296 if (!helper_->IsContextLost())
297 callback.Run();
300 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
301 const base::Closure& callback) {
302 gpu_control_->SignalSyncPoint(
303 sync_point,
304 base::Bind(&GLES2Implementation::RunIfContextNotLost,
305 weak_ptr_factory_.GetWeakPtr(),
306 callback));
309 void GLES2Implementation::SignalQuery(uint32 query,
310 const base::Closure& callback) {
311 // Flush previously entered commands to ensure ordering with any
312 // glBeginQueryEXT() calls that may have been put into the context.
313 ShallowFlushCHROMIUM();
314 gpu_control_->SignalQuery(
315 query,
316 base::Bind(&GLES2Implementation::RunIfContextNotLost,
317 weak_ptr_factory_.GetWeakPtr(),
318 callback));
321 void GLES2Implementation::SetSurfaceVisible(bool visible) {
322 TRACE_EVENT1(
323 "gpu", "GLES2Implementation::SetSurfaceVisible", "visible", visible);
324 ShallowFlushCHROMIUM();
325 gpu_control_->SetSurfaceVisible(visible);
328 void GLES2Implementation::SetAggressivelyFreeResources(
329 bool aggressively_free_resources) {
330 TRACE_EVENT1("gpu", "GLES2Implementation::SetAggressivelyFreeResources",
331 "aggressively_free_resources", aggressively_free_resources);
332 aggressively_free_resources_ = aggressively_free_resources;
334 if (aggressively_free_resources_ && helper_->HaveRingBuffer()) {
335 // Ensure that we clean up as much cache memory as possible and fully flush.
336 FlushDriverCachesCHROMIUM();
338 // Flush will delete transfer buffer resources if
339 // |aggressively_free_resources_| is true.
340 Flush();
341 } else {
342 ShallowFlushCHROMIUM();
346 void GLES2Implementation::WaitForCmd() {
347 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
348 helper_->CommandBufferHelper::Finish();
351 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
352 const char* extensions =
353 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
354 if (!extensions)
355 return false;
357 int length = strlen(ext);
358 while (true) {
359 int n = strcspn(extensions, " ");
360 if (n == length && 0 == strncmp(ext, extensions, length)) {
361 return true;
363 if ('\0' == extensions[n]) {
364 return false;
366 extensions += n + 1;
370 bool GLES2Implementation::IsExtensionAvailableHelper(
371 const char* extension, ExtensionStatus* status) {
372 switch (*status) {
373 case kAvailableExtensionStatus:
374 return true;
375 case kUnavailableExtensionStatus:
376 return false;
377 default: {
378 bool available = IsExtensionAvailable(extension);
379 *status = available ? kAvailableExtensionStatus :
380 kUnavailableExtensionStatus;
381 return available;
386 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
387 return IsExtensionAvailableHelper(
388 "GL_ANGLE_pack_reverse_row_order",
389 &angle_pack_reverse_row_order_status_);
392 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
393 return IsExtensionAvailableHelper(
394 "GL_CHROMIUM_framebuffer_multisample",
395 &chromium_framebuffer_multisample_);
398 const std::string& GLES2Implementation::GetLogPrefix() const {
399 const std::string& prefix(debug_marker_manager_.GetMarker());
400 return prefix.empty() ? this_in_hex_ : prefix;
403 GLenum GLES2Implementation::GetError() {
404 GPU_CLIENT_SINGLE_THREAD_CHECK();
405 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
406 GLenum err = GetGLError();
407 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
408 return err;
411 GLenum GLES2Implementation::GetClientSideGLError() {
412 if (error_bits_ == 0) {
413 return GL_NO_ERROR;
416 GLenum error = GL_NO_ERROR;
417 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
418 if ((error_bits_ & mask) != 0) {
419 error = GLES2Util::GLErrorBitToGLError(mask);
420 break;
423 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
424 return error;
427 GLenum GLES2Implementation::GetGLError() {
428 TRACE_EVENT0("gpu", "GLES2::GetGLError");
429 // Check the GL error first, then our wrapped error.
430 typedef cmds::GetError::Result Result;
431 Result* result = GetResultAs<Result*>();
432 // If we couldn't allocate a result the context is lost.
433 if (!result) {
434 return GL_NO_ERROR;
436 *result = GL_NO_ERROR;
437 helper_->GetError(GetResultShmId(), GetResultShmOffset());
438 WaitForCmd();
439 GLenum error = *result;
440 if (error == GL_NO_ERROR) {
441 error = GetClientSideGLError();
442 } else {
443 // There was an error, clear the corresponding wrapped error.
444 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
446 return error;
449 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
450 void GLES2Implementation::FailGLError(GLenum error) {
451 if (error != GL_NO_ERROR) {
452 NOTREACHED() << "Error";
455 // NOTE: Calling GetGLError overwrites data in the result buffer.
456 void GLES2Implementation::CheckGLError() {
457 FailGLError(GetGLError());
459 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
461 void GLES2Implementation::SetGLError(
462 GLenum error, const char* function_name, const char* msg) {
463 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
464 << GLES2Util::GetStringError(error) << ": "
465 << function_name << ": " << msg);
466 FailGLError(error);
467 if (msg) {
468 last_error_ = msg;
470 if (error_message_callback_) {
471 std::string temp(GLES2Util::GetStringError(error) + " : " +
472 function_name + ": " + (msg ? msg : ""));
473 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
475 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
477 if (error == GL_OUT_OF_MEMORY && lose_context_when_out_of_memory_) {
478 helper_->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
479 GL_UNKNOWN_CONTEXT_RESET_ARB);
483 void GLES2Implementation::SetGLErrorInvalidEnum(
484 const char* function_name, GLenum value, const char* label) {
485 SetGLError(GL_INVALID_ENUM, function_name,
486 (std::string(label) + " was " +
487 GLES2Util::GetStringEnum(value)).c_str());
490 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
491 std::vector<int8>* data) {
492 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
493 DCHECK(data);
494 const uint32 kStartSize = 32 * 1024;
495 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
496 if (!buffer.valid()) {
497 return false;
499 typedef cmd::GetBucketStart::Result Result;
500 Result* result = GetResultAs<Result*>();
501 if (!result) {
502 return false;
504 *result = 0;
505 helper_->GetBucketStart(
506 bucket_id, GetResultShmId(), GetResultShmOffset(),
507 buffer.size(), buffer.shm_id(), buffer.offset());
508 WaitForCmd();
509 uint32 size = *result;
510 data->resize(size);
511 if (size > 0u) {
512 uint32 offset = 0;
513 while (size) {
514 if (!buffer.valid()) {
515 buffer.Reset(size);
516 if (!buffer.valid()) {
517 return false;
519 helper_->GetBucketData(
520 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
521 WaitForCmd();
523 uint32 size_to_copy = std::min(size, buffer.size());
524 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
525 offset += size_to_copy;
526 size -= size_to_copy;
527 buffer.Release();
529 // Free the bucket. This is not required but it does free up the memory.
530 // and we don't have to wait for the result so from the client's perspective
531 // it's cheap.
532 helper_->SetBucketSize(bucket_id, 0);
534 return true;
537 void GLES2Implementation::SetBucketContents(
538 uint32 bucket_id, const void* data, size_t size) {
539 DCHECK(data);
540 helper_->SetBucketSize(bucket_id, size);
541 if (size > 0u) {
542 uint32 offset = 0;
543 while (size) {
544 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
545 if (!buffer.valid()) {
546 return;
548 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
549 buffer.size());
550 helper_->SetBucketData(
551 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
552 offset += buffer.size();
553 size -= buffer.size();
558 void GLES2Implementation::SetBucketAsCString(
559 uint32 bucket_id, const char* str) {
560 // NOTE: strings are passed NULL terminated. That means the empty
561 // string will have a size of 1 and no-string will have a size of 0
562 if (str) {
563 SetBucketContents(bucket_id, str, strlen(str) + 1);
564 } else {
565 helper_->SetBucketSize(bucket_id, 0);
569 bool GLES2Implementation::GetBucketAsString(
570 uint32 bucket_id, std::string* str) {
571 DCHECK(str);
572 std::vector<int8> data;
573 // NOTE: strings are passed NULL terminated. That means the empty
574 // string will have a size of 1 and no-string will have a size of 0
575 if (!GetBucketContents(bucket_id, &data)) {
576 return false;
578 if (data.empty()) {
579 return false;
581 str->assign(&data[0], &data[0] + data.size() - 1);
582 return true;
585 void GLES2Implementation::SetBucketAsString(
586 uint32 bucket_id, const std::string& str) {
587 // NOTE: strings are passed NULL terminated. That means the empty
588 // string will have a size of 1 and no-string will have a size of 0
589 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
592 void GLES2Implementation::Disable(GLenum cap) {
593 GPU_CLIENT_SINGLE_THREAD_CHECK();
594 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
595 << GLES2Util::GetStringCapability(cap) << ")");
596 bool changed = false;
597 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
598 helper_->Disable(cap);
600 CheckGLError();
603 void GLES2Implementation::Enable(GLenum cap) {
604 GPU_CLIENT_SINGLE_THREAD_CHECK();
605 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
606 << GLES2Util::GetStringCapability(cap) << ")");
607 bool changed = false;
608 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
609 helper_->Enable(cap);
611 CheckGLError();
614 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
615 GPU_CLIENT_SINGLE_THREAD_CHECK();
616 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
617 << GLES2Util::GetStringCapability(cap) << ")");
618 bool state = false;
619 if (!state_.GetEnabled(cap, &state)) {
620 typedef cmds::IsEnabled::Result Result;
621 Result* result = GetResultAs<Result*>();
622 if (!result) {
623 return GL_FALSE;
625 *result = 0;
626 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
627 WaitForCmd();
628 state = (*result) != 0;
631 GPU_CLIENT_LOG("returned " << state);
632 CheckGLError();
633 return state;
636 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
637 // TODO(zmo): For all the BINDING points, there is a possibility where
638 // resources are shared among multiple contexts, that the cached points
639 // are invalid. It is not a problem for now, but once we allow resource
640 // sharing in WebGL, we need to implement a mechanism to allow correct
641 // client side binding points tracking. crbug.com/465562.
643 // ES2 parameters.
644 switch (pname) {
645 case GL_ACTIVE_TEXTURE:
646 *params = active_texture_unit_ + GL_TEXTURE0;
647 return true;
648 case GL_ARRAY_BUFFER_BINDING:
649 *params = bound_array_buffer_;
650 return true;
651 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
652 *params =
653 vertex_array_object_manager_->bound_element_array_buffer();
654 return true;
655 case GL_FRAMEBUFFER_BINDING:
656 *params = bound_framebuffer_;
657 return true;
658 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
659 *params = capabilities_.max_combined_texture_image_units;
660 return true;
661 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
662 *params = capabilities_.max_cube_map_texture_size;
663 return true;
664 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
665 *params = capabilities_.max_fragment_uniform_vectors;
666 return true;
667 case GL_MAX_RENDERBUFFER_SIZE:
668 *params = capabilities_.max_renderbuffer_size;
669 return true;
670 case GL_MAX_TEXTURE_IMAGE_UNITS:
671 *params = capabilities_.max_texture_image_units;
672 return true;
673 case GL_MAX_TEXTURE_SIZE:
674 *params = capabilities_.max_texture_size;
675 return true;
676 case GL_MAX_VARYING_VECTORS:
677 *params = capabilities_.max_varying_vectors;
678 return true;
679 case GL_MAX_VERTEX_ATTRIBS:
680 *params = capabilities_.max_vertex_attribs;
681 return true;
682 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
683 *params = capabilities_.max_vertex_texture_image_units;
684 return true;
685 case GL_MAX_VERTEX_UNIFORM_VECTORS:
686 *params = capabilities_.max_vertex_uniform_vectors;
687 return true;
688 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
689 *params = capabilities_.num_compressed_texture_formats;
690 return true;
691 case GL_NUM_SHADER_BINARY_FORMATS:
692 *params = capabilities_.num_shader_binary_formats;
693 return true;
694 case GL_RENDERBUFFER_BINDING:
695 *params = bound_renderbuffer_;
696 return true;
697 case GL_TEXTURE_BINDING_2D:
698 *params = texture_units_[active_texture_unit_].bound_texture_2d;
699 return true;
700 case GL_TEXTURE_BINDING_CUBE_MAP:
701 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
702 return true;
704 // Non-standard parameters.
705 case GL_TEXTURE_BINDING_EXTERNAL_OES:
706 *params =
707 texture_units_[active_texture_unit_].bound_texture_external_oes;
708 return true;
709 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
710 *params = bound_pixel_pack_transfer_buffer_id_;
711 return true;
712 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
713 *params = bound_pixel_unpack_transfer_buffer_id_;
714 return true;
715 case GL_READ_FRAMEBUFFER_BINDING:
716 if (IsChromiumFramebufferMultisampleAvailable()) {
717 *params = bound_read_framebuffer_;
718 return true;
720 break;
721 case GL_TIMESTAMP_EXT:
722 // We convert all GPU timestamps to CPU time.
723 *params = base::saturated_cast<GLint>(
724 (base::TraceTicks::Now() - base::TraceTicks()).InMicroseconds()
725 * base::Time::kNanosecondsPerMicrosecond);
726 return true;
727 case GL_GPU_DISJOINT_EXT:
728 *params = static_cast<GLint>(query_tracker_->CheckAndResetDisjoint());
729 return true;
731 // Non-cached parameters.
732 case GL_ALIASED_LINE_WIDTH_RANGE:
733 case GL_ALIASED_POINT_SIZE_RANGE:
734 case GL_ALPHA_BITS:
735 case GL_BLEND:
736 case GL_BLEND_COLOR:
737 case GL_BLEND_DST_ALPHA:
738 case GL_BLEND_DST_RGB:
739 case GL_BLEND_EQUATION_ALPHA:
740 case GL_BLEND_EQUATION_RGB:
741 case GL_BLEND_SRC_ALPHA:
742 case GL_BLEND_SRC_RGB:
743 case GL_BLUE_BITS:
744 case GL_COLOR_CLEAR_VALUE:
745 case GL_COLOR_WRITEMASK:
746 case GL_COMPRESSED_TEXTURE_FORMATS:
747 case GL_CULL_FACE:
748 case GL_CULL_FACE_MODE:
749 case GL_CURRENT_PROGRAM:
750 case GL_DEPTH_BITS:
751 case GL_DEPTH_CLEAR_VALUE:
752 case GL_DEPTH_FUNC:
753 case GL_DEPTH_RANGE:
754 case GL_DEPTH_TEST:
755 case GL_DEPTH_WRITEMASK:
756 case GL_DITHER:
757 case GL_FRONT_FACE:
758 case GL_GENERATE_MIPMAP_HINT:
759 case GL_GREEN_BITS:
760 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
761 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
762 case GL_LINE_WIDTH:
763 case GL_MAX_VIEWPORT_DIMS:
764 case GL_PACK_ALIGNMENT:
765 case GL_POLYGON_OFFSET_FACTOR:
766 case GL_POLYGON_OFFSET_FILL:
767 case GL_POLYGON_OFFSET_UNITS:
768 case GL_RED_BITS:
769 case GL_SAMPLE_ALPHA_TO_COVERAGE:
770 case GL_SAMPLE_BUFFERS:
771 case GL_SAMPLE_COVERAGE:
772 case GL_SAMPLE_COVERAGE_INVERT:
773 case GL_SAMPLE_COVERAGE_VALUE:
774 case GL_SAMPLES:
775 case GL_SCISSOR_BOX:
776 case GL_SCISSOR_TEST:
777 case GL_SHADER_BINARY_FORMATS:
778 case GL_SHADER_COMPILER:
779 case GL_STENCIL_BACK_FAIL:
780 case GL_STENCIL_BACK_FUNC:
781 case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
782 case GL_STENCIL_BACK_PASS_DEPTH_PASS:
783 case GL_STENCIL_BACK_REF:
784 case GL_STENCIL_BACK_VALUE_MASK:
785 case GL_STENCIL_BACK_WRITEMASK:
786 case GL_STENCIL_BITS:
787 case GL_STENCIL_CLEAR_VALUE:
788 case GL_STENCIL_FAIL:
789 case GL_STENCIL_FUNC:
790 case GL_STENCIL_PASS_DEPTH_FAIL:
791 case GL_STENCIL_PASS_DEPTH_PASS:
792 case GL_STENCIL_REF:
793 case GL_STENCIL_TEST:
794 case GL_STENCIL_VALUE_MASK:
795 case GL_STENCIL_WRITEMASK:
796 case GL_SUBPIXEL_BITS:
797 case GL_UNPACK_ALIGNMENT:
798 case GL_VIEWPORT:
799 return false;
800 default:
801 break;
804 if (capabilities_.major_version < 3) {
805 return false;
808 // ES3 parameters.
809 switch (pname) {
810 case GL_COPY_READ_BUFFER_BINDING:
811 *params = bound_copy_read_buffer_;
812 return true;
813 case GL_COPY_WRITE_BUFFER_BINDING:
814 *params = bound_copy_write_buffer_;
815 return true;
816 case GL_MAJOR_VERSION:
817 *params = capabilities_.major_version;
818 return true;
819 case GL_MAX_3D_TEXTURE_SIZE:
820 *params = capabilities_.max_3d_texture_size;
821 return true;
822 case GL_MAX_ARRAY_TEXTURE_LAYERS:
823 *params = capabilities_.max_array_texture_layers;
824 return true;
825 case GL_MAX_COLOR_ATTACHMENTS:
826 *params = capabilities_.max_color_attachments;
827 return true;
828 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
829 *params = static_cast<GLint>(
830 capabilities_.max_combined_fragment_uniform_components);
831 return true;
832 case GL_MAX_COMBINED_UNIFORM_BLOCKS:
833 *params = capabilities_.max_combined_uniform_blocks;
834 return true;
835 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
836 *params = static_cast<GLint>(
837 capabilities_.max_combined_vertex_uniform_components);
838 return true;
839 case GL_MAX_DRAW_BUFFERS:
840 *params = capabilities_.max_draw_buffers;
841 return true;
842 case GL_MAX_ELEMENT_INDEX:
843 *params = static_cast<GLint>(capabilities_.max_element_index);
844 return true;
845 case GL_MAX_ELEMENTS_INDICES:
846 *params = capabilities_.max_elements_indices;
847 return true;
848 case GL_MAX_ELEMENTS_VERTICES:
849 *params = capabilities_.max_elements_vertices;
850 return true;
851 case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
852 *params = capabilities_.max_fragment_input_components;
853 return true;
854 case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
855 *params = capabilities_.max_fragment_uniform_blocks;
856 return true;
857 case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
858 *params = capabilities_.max_fragment_uniform_components;
859 return true;
860 case GL_MAX_PROGRAM_TEXEL_OFFSET:
861 *params = capabilities_.max_program_texel_offset;
862 return true;
863 case GL_MAX_SAMPLES:
864 *params = capabilities_.max_samples;
865 return true;
866 case GL_MAX_SERVER_WAIT_TIMEOUT:
867 *params = static_cast<GLint>(capabilities_.max_server_wait_timeout);
868 return true;
869 case GL_MAX_TEXTURE_LOD_BIAS:
870 *params = static_cast<GLint>(capabilities_.max_texture_lod_bias);
871 return true;
872 case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
873 *params = capabilities_.max_transform_feedback_interleaved_components;
874 return true;
875 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
876 *params = capabilities_.max_transform_feedback_separate_attribs;
877 return true;
878 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
879 *params = capabilities_.max_transform_feedback_separate_components;
880 return true;
881 case GL_MAX_UNIFORM_BLOCK_SIZE:
882 *params = static_cast<GLint>(capabilities_.max_uniform_block_size);
883 return true;
884 case GL_MAX_UNIFORM_BUFFER_BINDINGS:
885 *params = capabilities_.max_uniform_buffer_bindings;
886 return true;
887 case GL_MAX_VARYING_COMPONENTS:
888 *params = capabilities_.max_varying_components;
889 return true;
890 case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
891 *params = capabilities_.max_vertex_output_components;
892 return true;
893 case GL_MAX_VERTEX_UNIFORM_BLOCKS:
894 *params = capabilities_.max_vertex_uniform_blocks;
895 return true;
896 case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
897 *params = capabilities_.max_vertex_uniform_components;
898 return true;
899 case GL_MIN_PROGRAM_TEXEL_OFFSET:
900 *params = capabilities_.min_program_texel_offset;
901 return true;
902 case GL_MINOR_VERSION:
903 *params = capabilities_.minor_version;
904 return true;
905 case GL_NUM_EXTENSIONS:
906 *params = capabilities_.num_extensions;
907 return true;
908 case GL_NUM_PROGRAM_BINARY_FORMATS:
909 *params = capabilities_.num_program_binary_formats;
910 return true;
911 case GL_PIXEL_PACK_BUFFER_BINDING:
912 *params = bound_pixel_pack_buffer_;
913 return true;
914 case GL_PIXEL_UNPACK_BUFFER_BINDING:
915 *params = bound_pixel_unpack_buffer_;
916 return true;
917 case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
918 *params = bound_transform_feedback_buffer_;
919 return true;
920 case GL_UNIFORM_BUFFER_BINDING:
921 *params = bound_uniform_buffer_;
922 return true;
923 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
924 *params = capabilities_.uniform_buffer_offset_alignment;
925 return true;
927 // Non-cached ES3 parameters.
928 case GL_DRAW_BUFFER0:
929 case GL_DRAW_BUFFER1:
930 case GL_DRAW_BUFFER2:
931 case GL_DRAW_BUFFER3:
932 case GL_DRAW_BUFFER4:
933 case GL_DRAW_BUFFER5:
934 case GL_DRAW_BUFFER6:
935 case GL_DRAW_BUFFER7:
936 case GL_DRAW_BUFFER8:
937 case GL_DRAW_BUFFER9:
938 case GL_DRAW_BUFFER10:
939 case GL_DRAW_BUFFER11:
940 case GL_DRAW_BUFFER12:
941 case GL_DRAW_BUFFER13:
942 case GL_DRAW_BUFFER14:
943 case GL_DRAW_BUFFER15:
944 case GL_DRAW_FRAMEBUFFER_BINDING:
945 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
946 case GL_PACK_ROW_LENGTH:
947 case GL_PACK_SKIP_PIXELS:
948 case GL_PACK_SKIP_ROWS:
949 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
950 case GL_PROGRAM_BINARY_FORMATS:
951 case GL_RASTERIZER_DISCARD:
952 case GL_READ_BUFFER:
953 case GL_READ_FRAMEBUFFER_BINDING:
954 case GL_SAMPLER_BINDING:
955 case GL_TEXTURE_BINDING_2D_ARRAY:
956 case GL_TEXTURE_BINDING_3D:
957 case GL_TRANSFORM_FEEDBACK_BINDING:
958 case GL_TRANSFORM_FEEDBACK_ACTIVE:
959 case GL_TRANSFORM_FEEDBACK_PAUSED:
960 case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
961 case GL_TRANSFORM_FEEDBACK_BUFFER_START:
962 case GL_UNIFORM_BUFFER_SIZE:
963 case GL_UNIFORM_BUFFER_START:
964 case GL_UNPACK_IMAGE_HEIGHT:
965 case GL_UNPACK_ROW_LENGTH:
966 case GL_UNPACK_SKIP_IMAGES:
967 case GL_UNPACK_SKIP_PIXELS:
968 case GL_UNPACK_SKIP_ROWS:
969 case GL_VERTEX_ARRAY_BINDING:
970 return false;
971 default:
972 return false;
976 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
977 // TODO(gman): Make this handle pnames that return more than 1 value.
978 GLint value;
979 if (!GetHelper(pname, &value)) {
980 return false;
982 *params = static_cast<GLboolean>(value);
983 return true;
986 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
987 // TODO(gman): Make this handle pnames that return more than 1 value.
988 switch (pname) {
989 case GL_MAX_TEXTURE_LOD_BIAS:
990 *params = capabilities_.max_texture_lod_bias;
991 return true;
992 default:
993 break;
995 GLint value;
996 if (!GetHelper(pname, &value)) {
997 return false;
999 *params = static_cast<GLfloat>(value);
1000 return true;
1003 bool GLES2Implementation::GetInteger64vHelper(GLenum pname, GLint64* params) {
1004 switch (pname) {
1005 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
1006 *params = capabilities_.max_combined_fragment_uniform_components;
1007 return true;
1008 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
1009 *params = capabilities_.max_combined_vertex_uniform_components;
1010 return true;
1011 case GL_MAX_ELEMENT_INDEX:
1012 *params = capabilities_.max_element_index;
1013 return true;
1014 case GL_MAX_SERVER_WAIT_TIMEOUT:
1015 *params = capabilities_.max_server_wait_timeout;
1016 return true;
1017 case GL_MAX_UNIFORM_BLOCK_SIZE:
1018 *params = capabilities_.max_uniform_block_size;
1019 return true;
1020 case GL_TIMESTAMP_EXT:
1021 // We convert all GPU timestamps to CPU time.
1022 *params = (base::TraceTicks::Now() - base::TraceTicks()).InMicroseconds()
1023 * base::Time::kNanosecondsPerMicrosecond;
1024 return true;
1025 default:
1026 break;
1028 GLint value;
1029 if (!GetHelper(pname, &value)) {
1030 return false;
1032 *params = static_cast<GLint64>(value);
1033 return true;
1036 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
1037 return GetHelper(pname, params);
1040 bool GLES2Implementation::GetIntegeri_vHelper(
1041 GLenum pname, GLuint index, GLint* data) {
1042 // TODO(zmo): Implement client side caching.
1043 return false;
1046 bool GLES2Implementation::GetInteger64i_vHelper(
1047 GLenum pname, GLuint index, GLint64* data) {
1048 // TODO(zmo): Implement client side caching.
1049 return false;
1052 bool GLES2Implementation::GetInternalformativHelper(
1053 GLenum target, GLenum format, GLenum pname, GLsizei bufSize,
1054 GLint* params) {
1055 // TODO(zmo): Implement the client side caching.
1056 return false;
1059 bool GLES2Implementation::GetSyncivHelper(
1060 GLsync sync, GLenum pname, GLsizei bufsize, GLsizei* length,
1061 GLint* values) {
1062 GLint value = 0;
1063 switch (pname) {
1064 case GL_OBJECT_TYPE:
1065 value = GL_SYNC_FENCE;
1066 break;
1067 case GL_SYNC_CONDITION:
1068 value = GL_SYNC_GPU_COMMANDS_COMPLETE;
1069 break;
1070 case GL_SYNC_FLAGS:
1071 value = 0;
1072 break;
1073 default:
1074 return false;
1076 if (bufsize > 0) {
1077 DCHECK(values);
1078 *values = value;
1080 if (length) {
1081 *length = 1;
1083 return true;
1086 bool GLES2Implementation::GetQueryObjectValueHelper(
1087 const char* function_name, GLuint id, GLenum pname, GLuint64* params) {
1088 GPU_CLIENT_SINGLE_THREAD_CHECK();
1089 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryObjectValueHelper("
1090 << id << ", "
1091 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
1092 << static_cast<const void*>(params) << ")");
1094 QueryTracker::Query* query = query_tracker_->GetQuery(id);
1095 if (!query) {
1096 SetGLError(GL_INVALID_OPERATION,
1097 function_name, "unknown query id");
1098 return false;
1101 if (query->Active()) {
1102 SetGLError(
1103 GL_INVALID_OPERATION,
1104 function_name,
1105 "query active. Did you to call glEndQueryEXT?");
1106 return false;
1109 if (query->NeverUsed()) {
1110 SetGLError(
1111 GL_INVALID_OPERATION,
1112 function_name, "Never used. Did you call glBeginQueryEXT?");
1113 return false;
1116 bool valid_value = false;
1117 switch (pname) {
1118 case GL_QUERY_RESULT_EXT:
1119 if (!query->CheckResultsAvailable(helper_)) {
1120 helper_->WaitForToken(query->token());
1121 if (!query->CheckResultsAvailable(helper_)) {
1122 FinishHelper();
1123 CHECK(query->CheckResultsAvailable(helper_));
1126 *params = query->GetResult();
1127 valid_value = true;
1128 break;
1129 case GL_QUERY_RESULT_AVAILABLE_EXT:
1130 *params = query->CheckResultsAvailable(helper_);
1131 valid_value = true;
1132 break;
1133 default:
1134 SetGLErrorInvalidEnum(function_name, pname, "pname");
1135 break;
1137 GPU_CLIENT_LOG(" " << *params);
1138 CheckGLError();
1139 return valid_value;
1142 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
1143 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1144 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
1145 Result* result = GetResultAs<Result*>();
1146 if (!result) {
1147 return 0;
1149 *result = 0;
1150 helper_->GetMaxValueInBufferCHROMIUM(
1151 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
1152 WaitForCmd();
1153 return *result;
1156 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
1157 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1158 GPU_CLIENT_SINGLE_THREAD_CHECK();
1159 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
1160 << buffer_id << ", " << count << ", "
1161 << GLES2Util::GetStringGetMaxIndexType(type)
1162 << ", " << offset << ")");
1163 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
1164 buffer_id, count, type, offset);
1165 GPU_CLIENT_LOG("returned " << result);
1166 CheckGLError();
1167 return result;
1170 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
1171 if (restore) {
1172 RestoreArrayBuffer(restore);
1173 // Restore the element array binding.
1174 // We only need to restore it if it wasn't a client side array.
1175 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
1176 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1181 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
1182 if (restore) {
1183 // Restore the user's current binding.
1184 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_);
1188 void GLES2Implementation::DrawElements(
1189 GLenum mode, GLsizei count, GLenum type, const void* indices) {
1190 GPU_CLIENT_SINGLE_THREAD_CHECK();
1191 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
1192 << GLES2Util::GetStringDrawMode(mode) << ", "
1193 << count << ", "
1194 << GLES2Util::GetStringIndexType(type) << ", "
1195 << static_cast<const void*>(indices) << ")");
1196 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1199 void GLES2Implementation::DrawRangeElements(
1200 GLenum mode, GLuint start, GLuint end,
1201 GLsizei count, GLenum type, const void* indices) {
1202 GPU_CLIENT_SINGLE_THREAD_CHECK();
1203 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawRangeElements("
1204 << GLES2Util::GetStringDrawMode(mode) << ", "
1205 << start << ", " << end << ", " << count << ", "
1206 << GLES2Util::GetStringIndexType(type) << ", "
1207 << static_cast<const void*>(indices) << ")");
1208 if (end < start) {
1209 SetGLError(GL_INVALID_VALUE, "glDrawRangeElements", "end < start");
1210 return;
1212 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1215 void GLES2Implementation::DrawElementsImpl(
1216 GLenum mode, GLsizei count, GLenum type, const void* indices,
1217 const char* func_name) {
1218 if (count < 0) {
1219 SetGLError(GL_INVALID_VALUE, func_name, "count < 0");
1220 return;
1222 bool simulated = false;
1223 GLuint offset = ToGLuint(indices);
1224 if (count > 0) {
1225 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
1226 !ValidateOffset(func_name, reinterpret_cast<GLintptr>(indices))) {
1227 return;
1229 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
1230 func_name, this, helper_, count, type, 0, indices,
1231 &offset, &simulated)) {
1232 return;
1235 helper_->DrawElements(mode, count, type, offset);
1236 RestoreElementAndArrayBuffers(simulated);
1237 CheckGLError();
1240 void GLES2Implementation::Flush() {
1241 GPU_CLIENT_SINGLE_THREAD_CHECK();
1242 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
1243 // Insert the cmd to call glFlush
1244 helper_->Flush();
1245 FlushHelper();
1248 void GLES2Implementation::ShallowFlushCHROMIUM() {
1249 GPU_CLIENT_SINGLE_THREAD_CHECK();
1250 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
1251 FlushHelper();
1254 void GLES2Implementation::FlushHelper() {
1255 // Flush our command buffer
1256 // (tell the service to execute up to the flush cmd.)
1257 helper_->CommandBufferHelper::Flush();
1259 if (aggressively_free_resources_)
1260 FreeEverything();
1263 void GLES2Implementation::OrderingBarrierCHROMIUM() {
1264 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOrderingBarrierCHROMIUM");
1265 // Flush command buffer at the GPU channel level. May be implemented as
1266 // Flush().
1267 helper_->CommandBufferHelper::OrderingBarrier();
1270 void GLES2Implementation::Finish() {
1271 GPU_CLIENT_SINGLE_THREAD_CHECK();
1272 FinishHelper();
1275 void GLES2Implementation::ShallowFinishCHROMIUM() {
1276 GPU_CLIENT_SINGLE_THREAD_CHECK();
1277 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
1278 // Flush our command buffer (tell the service to execute up to the flush cmd
1279 // and don't return until it completes).
1280 helper_->CommandBufferHelper::Finish();
1282 if (aggressively_free_resources_)
1283 FreeEverything();
1286 void GLES2Implementation::FinishHelper() {
1287 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
1288 TRACE_EVENT0("gpu", "GLES2::Finish");
1289 // Insert the cmd to call glFinish
1290 helper_->Finish();
1291 // Finish our command buffer
1292 // (tell the service to execute up to the Finish cmd and wait for it to
1293 // execute.)
1294 helper_->CommandBufferHelper::Finish();
1296 if (aggressively_free_resources_)
1297 FreeEverything();
1300 void GLES2Implementation::SwapBuffers() {
1301 GPU_CLIENT_SINGLE_THREAD_CHECK();
1302 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
1303 // TODO(piman): Strictly speaking we'd want to insert the token after the
1304 // swap, but the state update with the updated token might not have happened
1305 // by the time the SwapBuffer callback gets called, forcing us to synchronize
1306 // with the GPU process more than needed. So instead, make it happen before.
1307 // All it means is that we could be slightly looser on the kMaxSwapBuffers
1308 // semantics if the client doesn't use the callback mechanism, and by chance
1309 // the scheduler yields between the InsertToken and the SwapBuffers.
1310 swap_buffers_tokens_.push(helper_->InsertToken());
1311 helper_->SwapBuffers();
1312 helper_->CommandBufferHelper::Flush();
1313 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
1314 // compensate for TODO above.
1315 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
1316 helper_->WaitForToken(swap_buffers_tokens_.front());
1317 swap_buffers_tokens_.pop();
1321 void GLES2Implementation::SwapInterval(int interval) {
1322 GPU_CLIENT_SINGLE_THREAD_CHECK();
1323 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapInterval("
1324 << interval << ")");
1325 helper_->SwapInterval(interval);
1328 void GLES2Implementation::BindAttribLocation(
1329 GLuint program, GLuint index, const char* name) {
1330 GPU_CLIENT_SINGLE_THREAD_CHECK();
1331 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
1332 << program << ", " << index << ", " << name << ")");
1333 SetBucketAsString(kResultBucketId, name);
1334 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
1335 helper_->SetBucketSize(kResultBucketId, 0);
1336 CheckGLError();
1339 void GLES2Implementation::BindUniformLocationCHROMIUM(
1340 GLuint program, GLint location, const char* name) {
1341 GPU_CLIENT_SINGLE_THREAD_CHECK();
1342 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1343 << program << ", " << location << ", " << name << ")");
1344 SetBucketAsString(kResultBucketId, name);
1345 helper_->BindUniformLocationCHROMIUMBucket(
1346 program, location, kResultBucketId);
1347 helper_->SetBucketSize(kResultBucketId, 0);
1348 CheckGLError();
1351 void GLES2Implementation::GetVertexAttribPointerv(
1352 GLuint index, GLenum pname, void** ptr) {
1353 GPU_CLIENT_SINGLE_THREAD_CHECK();
1354 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1355 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1356 << static_cast<void*>(ptr) << ")");
1357 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
1358 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1359 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1360 typedef cmds::GetVertexAttribPointerv::Result Result;
1361 Result* result = GetResultAs<Result*>();
1362 if (!result) {
1363 return;
1365 result->SetNumResults(0);
1366 helper_->GetVertexAttribPointerv(
1367 index, pname, GetResultShmId(), GetResultShmOffset());
1368 WaitForCmd();
1369 result->CopyResult(ptr);
1370 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1372 GPU_CLIENT_LOG_CODE_BLOCK({
1373 for (int32 i = 0; i < num_results; ++i) {
1374 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
1377 CheckGLError();
1380 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1381 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1382 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
1383 SetGLError(
1384 GL_INVALID_VALUE,
1385 "glDeleteProgram", "id not created by this context.");
1386 return false;
1388 if (program == current_program_) {
1389 current_program_ = 0;
1391 return true;
1394 void GLES2Implementation::DeleteProgramStub(
1395 GLsizei n, const GLuint* programs) {
1396 DCHECK_EQ(1, n);
1397 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1398 helper_->DeleteProgram(programs[0]);
1401 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1402 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1403 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1404 SetGLError(
1405 GL_INVALID_VALUE,
1406 "glDeleteShader", "id not created by this context.");
1407 return false;
1409 return true;
1412 void GLES2Implementation::DeleteShaderStub(
1413 GLsizei n, const GLuint* shaders) {
1414 DCHECK_EQ(1, n);
1415 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1416 helper_->DeleteShader(shaders[0]);
1419 void GLES2Implementation::DeleteSyncHelper(GLsync sync) {
1420 GLuint sync_uint = ToGLuint(sync);
1421 if (!GetIdHandler(id_namespaces::kSyncs)->FreeIds(
1422 this, 1, &sync_uint, &GLES2Implementation::DeleteSyncStub)) {
1423 SetGLError(
1424 GL_INVALID_VALUE,
1425 "glDeleteSync", "id not created by this context.");
1429 void GLES2Implementation::DeleteSyncStub(GLsizei n, const GLuint* syncs) {
1430 DCHECK_EQ(1, n);
1431 helper_->DeleteSync(syncs[0]);
1434 GLint GLES2Implementation::GetAttribLocationHelper(
1435 GLuint program, const char* name) {
1436 typedef cmds::GetAttribLocation::Result Result;
1437 Result* result = GetResultAs<Result*>();
1438 if (!result) {
1439 return -1;
1441 *result = -1;
1442 SetBucketAsCString(kResultBucketId, name);
1443 helper_->GetAttribLocation(
1444 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1445 WaitForCmd();
1446 helper_->SetBucketSize(kResultBucketId, 0);
1447 return *result;
1450 GLint GLES2Implementation::GetAttribLocation(
1451 GLuint program, const char* name) {
1452 GPU_CLIENT_SINGLE_THREAD_CHECK();
1453 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1454 << ", " << name << ")");
1455 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1456 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1457 this, program, name);
1458 GPU_CLIENT_LOG("returned " << loc);
1459 CheckGLError();
1460 return loc;
1463 GLint GLES2Implementation::GetUniformLocationHelper(
1464 GLuint program, const char* name) {
1465 typedef cmds::GetUniformLocation::Result Result;
1466 Result* result = GetResultAs<Result*>();
1467 if (!result) {
1468 return -1;
1470 *result = -1;
1471 SetBucketAsCString(kResultBucketId, name);
1472 helper_->GetUniformLocation(program, kResultBucketId,
1473 GetResultShmId(), GetResultShmOffset());
1474 WaitForCmd();
1475 helper_->SetBucketSize(kResultBucketId, 0);
1476 return *result;
1479 GLint GLES2Implementation::GetUniformLocation(
1480 GLuint program, const char* name) {
1481 GPU_CLIENT_SINGLE_THREAD_CHECK();
1482 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1483 << ", " << name << ")");
1484 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1485 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1486 this, program, name);
1487 GPU_CLIENT_LOG("returned " << loc);
1488 CheckGLError();
1489 return loc;
1492 bool GLES2Implementation::GetUniformIndicesHelper(
1493 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1494 typedef cmds::GetUniformIndices::Result Result;
1495 Result* result = GetResultAs<Result*>();
1496 if (!result) {
1497 return false;
1499 result->SetNumResults(0);
1500 if (!PackStringsToBucket(count, names, NULL, "glGetUniformIndices")) {
1501 return false;
1503 helper_->GetUniformIndices(program, kResultBucketId,
1504 GetResultShmId(), GetResultShmOffset());
1505 WaitForCmd();
1506 if (result->GetNumResults() != count) {
1507 return false;
1509 result->CopyResult(indices);
1510 return true;
1513 void GLES2Implementation::GetUniformIndices(
1514 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1515 GPU_CLIENT_SINGLE_THREAD_CHECK();
1516 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
1517 << ", " << count << ", " << names << ", " << indices << ")");
1518 TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
1519 if (count < 0) {
1520 SetGLError(GL_INVALID_VALUE, "glGetUniformIndices", "count < 0");
1521 return;
1523 if (count == 0) {
1524 return;
1526 bool success = share_group_->program_info_manager()->GetUniformIndices(
1527 this, program, count, names, indices);
1528 if (success) {
1529 GPU_CLIENT_LOG_CODE_BLOCK({
1530 for (GLsizei ii = 0; ii < count; ++ii) {
1531 GPU_CLIENT_LOG(" " << ii << ": " << indices[ii]);
1535 CheckGLError();
1538 bool GLES2Implementation::GetProgramivHelper(
1539 GLuint program, GLenum pname, GLint* params) {
1540 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1541 this, program, pname, params);
1542 GPU_CLIENT_LOG_CODE_BLOCK({
1543 if (got_value) {
1544 GPU_CLIENT_LOG(" 0: " << *params);
1547 return got_value;
1550 GLint GLES2Implementation::GetFragDataLocationHelper(
1551 GLuint program, const char* name) {
1552 typedef cmds::GetFragDataLocation::Result Result;
1553 Result* result = GetResultAs<Result*>();
1554 if (!result) {
1555 return -1;
1557 *result = -1;
1558 SetBucketAsCString(kResultBucketId, name);
1559 helper_->GetFragDataLocation(
1560 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1561 WaitForCmd();
1562 helper_->SetBucketSize(kResultBucketId, 0);
1563 return *result;
1566 GLint GLES2Implementation::GetFragDataLocation(
1567 GLuint program, const char* name) {
1568 GPU_CLIENT_SINGLE_THREAD_CHECK();
1569 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataLocation("
1570 << program << ", " << name << ")");
1571 TRACE_EVENT0("gpu", "GLES2::GetFragDataLocation");
1572 GLint loc = share_group_->program_info_manager()->GetFragDataLocation(
1573 this, program, name);
1574 GPU_CLIENT_LOG("returned " << loc);
1575 CheckGLError();
1576 return loc;
1579 GLuint GLES2Implementation::GetUniformBlockIndexHelper(
1580 GLuint program, const char* name) {
1581 typedef cmds::GetUniformBlockIndex::Result Result;
1582 Result* result = GetResultAs<Result*>();
1583 if (!result) {
1584 return GL_INVALID_INDEX;
1586 *result = GL_INVALID_INDEX;
1587 SetBucketAsCString(kResultBucketId, name);
1588 helper_->GetUniformBlockIndex(
1589 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1590 WaitForCmd();
1591 helper_->SetBucketSize(kResultBucketId, 0);
1592 return *result;
1595 GLuint GLES2Implementation::GetUniformBlockIndex(
1596 GLuint program, const char* name) {
1597 GPU_CLIENT_SINGLE_THREAD_CHECK();
1598 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformBlockIndex("
1599 << program << ", " << name << ")");
1600 TRACE_EVENT0("gpu", "GLES2::GetUniformBlockIndex");
1601 GLuint index = share_group_->program_info_manager()->GetUniformBlockIndex(
1602 this, program, name);
1603 GPU_CLIENT_LOG("returned " << index);
1604 CheckGLError();
1605 return index;
1608 void GLES2Implementation::LinkProgram(GLuint program) {
1609 GPU_CLIENT_SINGLE_THREAD_CHECK();
1610 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1611 helper_->LinkProgram(program);
1612 share_group_->program_info_manager()->CreateInfo(program);
1613 CheckGLError();
1616 void GLES2Implementation::ShaderBinary(
1617 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1618 GLsizei length) {
1619 GPU_CLIENT_SINGLE_THREAD_CHECK();
1620 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1621 << static_cast<const void*>(shaders) << ", "
1622 << GLES2Util::GetStringEnum(binaryformat) << ", "
1623 << static_cast<const void*>(binary) << ", "
1624 << length << ")");
1625 if (n < 0) {
1626 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1627 return;
1629 if (length < 0) {
1630 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1631 return;
1633 // TODO(gman): ShaderBinary should use buckets.
1634 unsigned int shader_id_size = n * sizeof(*shaders);
1635 ScopedTransferBufferArray<GLint> buffer(
1636 shader_id_size + length, helper_, transfer_buffer_);
1637 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1638 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1639 return;
1641 void* shader_ids = buffer.elements();
1642 void* shader_data = buffer.elements() + shader_id_size;
1643 memcpy(shader_ids, shaders, shader_id_size);
1644 memcpy(shader_data, binary, length);
1645 helper_->ShaderBinary(
1647 buffer.shm_id(),
1648 buffer.offset(),
1649 binaryformat,
1650 buffer.shm_id(),
1651 buffer.offset() + shader_id_size,
1652 length);
1653 CheckGLError();
1656 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1657 GPU_CLIENT_SINGLE_THREAD_CHECK();
1658 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1659 << GLES2Util::GetStringPixelStore(pname) << ", "
1660 << param << ")");
1661 switch (pname) {
1662 case GL_PACK_ALIGNMENT:
1663 pack_alignment_ = param;
1664 break;
1665 case GL_UNPACK_ALIGNMENT:
1666 unpack_alignment_ = param;
1667 break;
1668 case GL_UNPACK_ROW_LENGTH_EXT:
1669 unpack_row_length_ = param;
1670 return;
1671 case GL_UNPACK_IMAGE_HEIGHT:
1672 unpack_image_height_ = param;
1673 return;
1674 case GL_UNPACK_SKIP_ROWS_EXT:
1675 unpack_skip_rows_ = param;
1676 return;
1677 case GL_UNPACK_SKIP_PIXELS_EXT:
1678 unpack_skip_pixels_ = param;
1679 return;
1680 case GL_UNPACK_SKIP_IMAGES:
1681 unpack_skip_images_ = param;
1682 return;
1683 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1684 pack_reverse_row_order_ =
1685 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1686 break;
1687 default:
1688 break;
1690 helper_->PixelStorei(pname, param);
1691 CheckGLError();
1694 void GLES2Implementation::VertexAttribIPointer(
1695 GLuint index, GLint size, GLenum type, GLsizei stride, const void* ptr) {
1696 GPU_CLIENT_SINGLE_THREAD_CHECK();
1697 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribIPointer("
1698 << index << ", "
1699 << size << ", "
1700 << GLES2Util::GetStringVertexAttribIType(type) << ", "
1701 << stride << ", "
1702 << ptr << ")");
1703 // Record the info on the client side.
1704 if (!vertex_array_object_manager_->SetAttribPointer(bound_array_buffer_,
1705 index,
1706 size,
1707 type,
1708 GL_FALSE,
1709 stride,
1710 ptr,
1711 GL_TRUE)) {
1712 SetGLError(GL_INVALID_OPERATION, "glVertexAttribIPointer",
1713 "client side arrays are not allowed in vertex array objects.");
1714 return;
1716 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
1717 // Only report NON client side buffers to the service.
1718 if (!ValidateOffset("glVertexAttribIPointer",
1719 reinterpret_cast<GLintptr>(ptr))) {
1720 return;
1722 helper_->VertexAttribIPointer(index, size, type, stride, ToGLuint(ptr));
1724 CheckGLError();
1727 void GLES2Implementation::VertexAttribPointer(
1728 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1729 const void* ptr) {
1730 GPU_CLIENT_SINGLE_THREAD_CHECK();
1731 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1732 << index << ", "
1733 << size << ", "
1734 << GLES2Util::GetStringVertexAttribType(type) << ", "
1735 << GLES2Util::GetStringBool(normalized) << ", "
1736 << stride << ", "
1737 << ptr << ")");
1738 // Record the info on the client side.
1739 if (!vertex_array_object_manager_->SetAttribPointer(bound_array_buffer_,
1740 index,
1741 size,
1742 type,
1743 normalized,
1744 stride,
1745 ptr,
1746 GL_FALSE)) {
1747 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1748 "client side arrays are not allowed in vertex array objects.");
1749 return;
1751 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
1752 // Only report NON client side buffers to the service.
1753 if (!ValidateOffset("glVertexAttribPointer",
1754 reinterpret_cast<GLintptr>(ptr))) {
1755 return;
1757 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1758 ToGLuint(ptr));
1760 CheckGLError();
1763 void GLES2Implementation::VertexAttribDivisorANGLE(
1764 GLuint index, GLuint divisor) {
1765 GPU_CLIENT_SINGLE_THREAD_CHECK();
1766 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1767 << index << ", "
1768 << divisor << ") ");
1769 // Record the info on the client side.
1770 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1771 helper_->VertexAttribDivisorANGLE(index, divisor);
1772 CheckGLError();
1775 void GLES2Implementation::BufferDataHelper(
1776 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1777 if (!ValidateSize("glBufferData", size))
1778 return;
1780 #if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
1781 // Do not upload uninitialized data. Even if it's not a bug, it can cause a
1782 // bogus MSan report during a readback later. This is because MSan doesn't
1783 // understand shared memory and would assume we were reading back the same
1784 // unintialized data.
1785 if (data) __msan_check_mem_is_initialized(data, size);
1786 #endif
1788 GLuint buffer_id;
1789 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1790 if (!buffer_id) {
1791 return;
1794 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1795 if (buffer)
1796 RemoveTransferBuffer(buffer);
1798 // Create new buffer.
1799 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1800 DCHECK(buffer);
1801 if (buffer->address() && data)
1802 memcpy(buffer->address(), data, size);
1803 return;
1806 RemoveMappedBufferRangeByTarget(target);
1808 // If there is no data just send BufferData
1809 if (size == 0 || !data) {
1810 helper_->BufferData(target, size, 0, 0, usage);
1811 return;
1814 // See if we can send all at once.
1815 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1816 if (!buffer.valid()) {
1817 return;
1820 if (buffer.size() >= static_cast<unsigned int>(size)) {
1821 memcpy(buffer.address(), data, size);
1822 helper_->BufferData(
1823 target,
1824 size,
1825 buffer.shm_id(),
1826 buffer.offset(),
1827 usage);
1828 return;
1831 // Make the buffer with BufferData then send via BufferSubData
1832 helper_->BufferData(target, size, 0, 0, usage);
1833 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1834 CheckGLError();
1837 void GLES2Implementation::BufferData(
1838 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1839 GPU_CLIENT_SINGLE_THREAD_CHECK();
1840 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1841 << GLES2Util::GetStringBufferTarget(target) << ", "
1842 << size << ", "
1843 << static_cast<const void*>(data) << ", "
1844 << GLES2Util::GetStringBufferUsage(usage) << ")");
1845 BufferDataHelper(target, size, data, usage);
1846 CheckGLError();
1849 void GLES2Implementation::BufferSubDataHelper(
1850 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1851 if (size == 0) {
1852 return;
1855 if (!ValidateSize("glBufferSubData", size) ||
1856 !ValidateOffset("glBufferSubData", offset)) {
1857 return;
1860 GLuint buffer_id;
1861 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1862 if (!buffer_id) {
1863 return;
1865 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1866 if (!buffer) {
1867 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1868 return;
1871 int32 end = 0;
1872 int32 buffer_size = buffer->size();
1873 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1874 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1875 return;
1878 if (buffer->address() && data)
1879 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1880 return;
1883 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1884 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1887 void GLES2Implementation::BufferSubDataHelperImpl(
1888 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1889 ScopedTransferBufferPtr* buffer) {
1890 DCHECK(buffer);
1891 DCHECK_GT(size, 0);
1893 const int8* source = static_cast<const int8*>(data);
1894 while (size) {
1895 if (!buffer->valid() || buffer->size() == 0) {
1896 buffer->Reset(size);
1897 if (!buffer->valid()) {
1898 return;
1901 memcpy(buffer->address(), source, buffer->size());
1902 helper_->BufferSubData(
1903 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1904 offset += buffer->size();
1905 source += buffer->size();
1906 size -= buffer->size();
1907 buffer->Release();
1911 void GLES2Implementation::BufferSubData(
1912 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1913 GPU_CLIENT_SINGLE_THREAD_CHECK();
1914 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1915 << GLES2Util::GetStringBufferTarget(target) << ", "
1916 << offset << ", " << size << ", "
1917 << static_cast<const void*>(data) << ")");
1918 BufferSubDataHelper(target, offset, size, data);
1919 CheckGLError();
1922 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
1923 int32 token = buffer->last_usage_token();
1924 uint32 async_token = buffer->last_async_upload_token();
1926 if (async_token) {
1927 if (HasAsyncUploadTokenPassed(async_token)) {
1928 buffer_tracker_->Free(buffer);
1929 } else {
1930 detached_async_upload_memory_.push_back(
1931 std::make_pair(buffer->address(), async_token));
1932 buffer_tracker_->Unmanage(buffer);
1934 } else if (token) {
1935 if (helper_->HasTokenPassed(token))
1936 buffer_tracker_->Free(buffer);
1937 else
1938 buffer_tracker_->FreePendingToken(buffer, token);
1939 } else {
1940 buffer_tracker_->Free(buffer);
1943 buffer_tracker_->RemoveBuffer(buffer->id());
1946 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1947 GLenum target,
1948 const char* function_name,
1949 GLuint* buffer_id) {
1950 *buffer_id = 0;
1952 switch (target) {
1953 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1954 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1955 break;
1956 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1957 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1958 break;
1959 default:
1960 // Unknown target
1961 return false;
1963 if (!*buffer_id) {
1964 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1966 return true;
1969 BufferTracker::Buffer*
1970 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1971 GLuint buffer_id,
1972 const char* function_name,
1973 GLuint offset, GLsizei size) {
1974 DCHECK(buffer_id);
1975 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1976 if (!buffer) {
1977 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1978 return NULL;
1980 if (buffer->mapped()) {
1981 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1982 return NULL;
1984 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1985 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1986 return NULL;
1988 return buffer;
1991 void GLES2Implementation::CompressedTexImage2D(
1992 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1993 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1994 GPU_CLIENT_SINGLE_THREAD_CHECK();
1995 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1996 << GLES2Util::GetStringTextureTarget(target) << ", "
1997 << level << ", "
1998 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1999 << width << ", " << height << ", " << border << ", "
2000 << image_size << ", "
2001 << static_cast<const void*>(data) << ")");
2002 if (width < 0 || height < 0 || level < 0) {
2003 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
2004 return;
2006 if (border != 0) {
2007 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "border != 0");
2008 return;
2010 if (height == 0 || width == 0) {
2011 return;
2013 // If there's a pixel unpack buffer bound use it when issuing
2014 // CompressedTexImage2D.
2015 if (bound_pixel_unpack_transfer_buffer_id_) {
2016 GLuint offset = ToGLuint(data);
2017 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2018 bound_pixel_unpack_transfer_buffer_id_,
2019 "glCompressedTexImage2D", offset, image_size);
2020 if (buffer && buffer->shm_id() != -1) {
2021 helper_->CompressedTexImage2D(
2022 target, level, internalformat, width, height, image_size,
2023 buffer->shm_id(), buffer->shm_offset() + offset);
2024 buffer->set_last_usage_token(helper_->InsertToken());
2026 return;
2028 SetBucketContents(kResultBucketId, data, image_size);
2029 helper_->CompressedTexImage2DBucket(
2030 target, level, internalformat, width, height, kResultBucketId);
2031 // Free the bucket. This is not required but it does free up the memory.
2032 // and we don't have to wait for the result so from the client's perspective
2033 // it's cheap.
2034 helper_->SetBucketSize(kResultBucketId, 0);
2035 CheckGLError();
2038 void GLES2Implementation::CompressedTexSubImage2D(
2039 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2040 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
2041 GPU_CLIENT_SINGLE_THREAD_CHECK();
2042 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
2043 << GLES2Util::GetStringTextureTarget(target) << ", "
2044 << level << ", "
2045 << xoffset << ", " << yoffset << ", "
2046 << width << ", " << height << ", "
2047 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
2048 << image_size << ", "
2049 << static_cast<const void*>(data) << ")");
2050 if (width < 0 || height < 0 || level < 0) {
2051 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
2052 return;
2054 // If there's a pixel unpack buffer bound use it when issuing
2055 // CompressedTexSubImage2D.
2056 if (bound_pixel_unpack_transfer_buffer_id_) {
2057 GLuint offset = ToGLuint(data);
2058 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2059 bound_pixel_unpack_transfer_buffer_id_,
2060 "glCompressedTexSubImage2D", offset, image_size);
2061 if (buffer && buffer->shm_id() != -1) {
2062 helper_->CompressedTexSubImage2D(
2063 target, level, xoffset, yoffset, width, height, format, image_size,
2064 buffer->shm_id(), buffer->shm_offset() + offset);
2065 buffer->set_last_usage_token(helper_->InsertToken());
2066 CheckGLError();
2068 return;
2070 SetBucketContents(kResultBucketId, data, image_size);
2071 helper_->CompressedTexSubImage2DBucket(
2072 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
2073 // Free the bucket. This is not required but it does free up the memory.
2074 // and we don't have to wait for the result so from the client's perspective
2075 // it's cheap.
2076 helper_->SetBucketSize(kResultBucketId, 0);
2077 CheckGLError();
2080 void GLES2Implementation::CompressedTexImage3D(
2081 GLenum target, GLint level, GLenum internalformat, GLsizei width,
2082 GLsizei height, GLsizei depth, GLint border, GLsizei image_size,
2083 const void* data) {
2084 GPU_CLIENT_SINGLE_THREAD_CHECK();
2085 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage3D("
2086 << GLES2Util::GetStringTexture3DTarget(target) << ", " << level << ", "
2087 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
2088 << width << ", " << height << ", " << depth << ", " << border << ", "
2089 << image_size << ", " << static_cast<const void*>(data) << ")");
2090 if (width < 0 || height < 0 || depth < 0 || level < 0) {
2091 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "dimension < 0");
2092 return;
2094 if (border != 0) {
2095 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "border != 0");
2096 return;
2098 if (height == 0 || width == 0 || depth == 0) {
2099 return;
2101 // If there's a pixel unpack buffer bound use it when issuing
2102 // CompressedTexImage3D.
2103 if (bound_pixel_unpack_transfer_buffer_id_) {
2104 GLuint offset = ToGLuint(data);
2105 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2106 bound_pixel_unpack_transfer_buffer_id_,
2107 "glCompressedTexImage3D", offset, image_size);
2108 if (buffer && buffer->shm_id() != -1) {
2109 helper_->CompressedTexImage3D(
2110 target, level, internalformat, width, height, depth, image_size,
2111 buffer->shm_id(), buffer->shm_offset() + offset);
2112 buffer->set_last_usage_token(helper_->InsertToken());
2114 return;
2116 SetBucketContents(kResultBucketId, data, image_size);
2117 helper_->CompressedTexImage3DBucket(
2118 target, level, internalformat, width, height, depth, kResultBucketId);
2119 // Free the bucket. This is not required but it does free up the memory.
2120 // and we don't have to wait for the result so from the client's perspective
2121 // it's cheap.
2122 helper_->SetBucketSize(kResultBucketId, 0);
2123 CheckGLError();
2126 void GLES2Implementation::CompressedTexSubImage3D(
2127 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2128 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2129 GLsizei image_size, const void* data) {
2130 GPU_CLIENT_SINGLE_THREAD_CHECK();
2131 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage3D("
2132 << GLES2Util::GetStringTextureTarget(target) << ", "
2133 << level << ", "
2134 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2135 << width << ", " << height << ", " << depth << ", "
2136 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
2137 << image_size << ", "
2138 << static_cast<const void*>(data) << ")");
2139 if (width < 0 || height < 0 || depth < 0 || level < 0) {
2140 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage3D", "dimension < 0");
2141 return;
2143 // If there's a pixel unpack buffer bound use it when issuing
2144 // CompressedTexSubImage3D.
2145 if (bound_pixel_unpack_transfer_buffer_id_) {
2146 GLuint offset = ToGLuint(data);
2147 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2148 bound_pixel_unpack_transfer_buffer_id_,
2149 "glCompressedTexSubImage3D", offset, image_size);
2150 if (buffer && buffer->shm_id() != -1) {
2151 helper_->CompressedTexSubImage3D(
2152 target, level, xoffset, yoffset, zoffset,
2153 width, height, depth, format, image_size,
2154 buffer->shm_id(), buffer->shm_offset() + offset);
2155 buffer->set_last_usage_token(helper_->InsertToken());
2156 CheckGLError();
2158 return;
2160 SetBucketContents(kResultBucketId, data, image_size);
2161 helper_->CompressedTexSubImage3DBucket(
2162 target, level, xoffset, yoffset, zoffset, width, height, depth, format,
2163 kResultBucketId);
2164 // Free the bucket. This is not required but it does free up the memory.
2165 // and we don't have to wait for the result so from the client's perspective
2166 // it's cheap.
2167 helper_->SetBucketSize(kResultBucketId, 0);
2168 CheckGLError();
2171 namespace {
2173 void CopyRectToBuffer(
2174 const void* pixels,
2175 uint32 height,
2176 uint32 unpadded_row_size,
2177 uint32 pixels_padded_row_size,
2178 void* buffer,
2179 uint32 buffer_padded_row_size) {
2180 const int8* source = static_cast<const int8*>(pixels);
2181 int8* dest = static_cast<int8*>(buffer);
2182 if (pixels_padded_row_size != buffer_padded_row_size) {
2183 // the last row is copied unpadded at the end
2184 for (; height > 1; --height) {
2185 memcpy(dest, source, buffer_padded_row_size);
2186 dest += buffer_padded_row_size;
2187 source += pixels_padded_row_size;
2189 memcpy(dest, source, unpadded_row_size);
2190 } else {
2191 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
2192 memcpy(dest, source, size);
2196 } // anonymous namespace
2198 void GLES2Implementation::TexImage2D(
2199 GLenum target, GLint level, GLint internalformat, GLsizei width,
2200 GLsizei height, GLint border, GLenum format, GLenum type,
2201 const void* pixels) {
2202 GPU_CLIENT_SINGLE_THREAD_CHECK();
2203 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
2204 << GLES2Util::GetStringTextureTarget(target) << ", "
2205 << level << ", "
2206 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2207 << width << ", " << height << ", " << border << ", "
2208 << GLES2Util::GetStringTextureFormat(format) << ", "
2209 << GLES2Util::GetStringPixelType(type) << ", "
2210 << static_cast<const void*>(pixels) << ")");
2211 if (level < 0 || height < 0 || width < 0) {
2212 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
2213 return;
2215 if (border != 0) {
2216 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
2217 return;
2219 uint32 size;
2220 uint32 unpadded_row_size;
2221 uint32 padded_row_size;
2222 if (!GLES2Util::ComputeImageDataSizes(
2223 width, height, 1, format, type, unpack_alignment_, &size,
2224 &unpadded_row_size, &padded_row_size)) {
2225 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
2226 return;
2229 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
2230 if (bound_pixel_unpack_transfer_buffer_id_) {
2231 GLuint offset = ToGLuint(pixels);
2232 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2233 bound_pixel_unpack_transfer_buffer_id_,
2234 "glTexImage2D", offset, size);
2235 if (buffer && buffer->shm_id() != -1) {
2236 helper_->TexImage2D(
2237 target, level, internalformat, width, height, format, type,
2238 buffer->shm_id(), buffer->shm_offset() + offset);
2239 buffer->set_last_usage_token(helper_->InsertToken());
2240 CheckGLError();
2242 return;
2245 // If there's no data just issue TexImage2D
2246 if (!pixels) {
2247 helper_->TexImage2D(
2248 target, level, internalformat, width, height, format, type,
2249 0, 0);
2250 CheckGLError();
2251 return;
2254 // compute the advance bytes per row for the src pixels
2255 uint32 src_padded_row_size;
2256 if (unpack_row_length_ > 0) {
2257 if (!GLES2Util::ComputeImagePaddedRowSize(
2258 unpack_row_length_, format, type, unpack_alignment_,
2259 &src_padded_row_size)) {
2260 SetGLError(
2261 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2262 return;
2264 } else {
2265 src_padded_row_size = padded_row_size;
2268 // advance pixels pointer past the skip rows and skip pixels
2269 pixels = reinterpret_cast<const int8*>(pixels) +
2270 unpack_skip_rows_ * src_padded_row_size;
2271 if (unpack_skip_pixels_) {
2272 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2273 pixels = reinterpret_cast<const int8*>(pixels) +
2274 unpack_skip_pixels_ * group_size;
2277 // Check if we can send it all at once.
2278 int32_t shm_id = 0;
2279 uint32_t shm_offset = 0;
2280 void* buffer_pointer = nullptr;
2282 ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
2283 ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
2285 if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
2286 shm_id = transfer_alloc.shm_id();
2287 shm_offset = transfer_alloc.offset();
2288 buffer_pointer = transfer_alloc.address();
2289 } else {
2290 mapped_alloc.Reset(size);
2291 if (mapped_alloc.valid()) {
2292 transfer_alloc.Discard();
2294 mapped_alloc.SetFlushAfterRelease(true);
2295 shm_id = mapped_alloc.shm_id();
2296 shm_offset = mapped_alloc.offset();
2297 buffer_pointer = mapped_alloc.address();
2301 if (buffer_pointer) {
2302 CopyRectToBuffer(
2303 pixels, height, unpadded_row_size, src_padded_row_size,
2304 buffer_pointer, padded_row_size);
2305 helper_->TexImage2D(
2306 target, level, internalformat, width, height, format, type,
2307 shm_id, shm_offset);
2308 CheckGLError();
2309 return;
2312 // No, so send it using TexSubImage2D.
2313 helper_->TexImage2D(
2314 target, level, internalformat, width, height, format, type,
2315 0, 0);
2316 TexSubImage2DImpl(
2317 target, level, 0, 0, width, height, format, type, unpadded_row_size,
2318 pixels, src_padded_row_size, GL_TRUE, &transfer_alloc, padded_row_size);
2319 CheckGLError();
2322 void GLES2Implementation::TexImage3D(
2323 GLenum target, GLint level, GLint internalformat, GLsizei width,
2324 GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type,
2325 const void* pixels) {
2326 GPU_CLIENT_SINGLE_THREAD_CHECK();
2327 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D("
2328 << GLES2Util::GetStringTextureTarget(target) << ", "
2329 << level << ", "
2330 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2331 << width << ", " << height << ", " << depth << ", " << border << ", "
2332 << GLES2Util::GetStringTextureFormat(format) << ", "
2333 << GLES2Util::GetStringPixelType(type) << ", "
2334 << static_cast<const void*>(pixels) << ")");
2335 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2336 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "dimension < 0");
2337 return;
2339 if (border != 0) {
2340 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "border != 0");
2341 return;
2343 uint32 size;
2344 uint32 unpadded_row_size;
2345 uint32 padded_row_size;
2346 if (!GLES2Util::ComputeImageDataSizes(
2347 width, height, depth, format, type, unpack_alignment_, &size,
2348 &unpadded_row_size, &padded_row_size)) {
2349 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large");
2350 return;
2353 // If there's a pixel unpack buffer bound use it when issuing TexImage3D.
2354 if (bound_pixel_unpack_transfer_buffer_id_) {
2355 GLuint offset = ToGLuint(pixels);
2356 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2357 bound_pixel_unpack_transfer_buffer_id_,
2358 "glTexImage3D", offset, size);
2359 if (buffer && buffer->shm_id() != -1) {
2360 helper_->TexImage3D(
2361 target, level, internalformat, width, height, depth, format, type,
2362 buffer->shm_id(), buffer->shm_offset() + offset);
2363 buffer->set_last_usage_token(helper_->InsertToken());
2364 CheckGLError();
2366 return;
2369 // If there's no data just issue TexImage3D
2370 if (!pixels) {
2371 helper_->TexImage3D(
2372 target, level, internalformat, width, height, depth, format, type,
2373 0, 0);
2374 CheckGLError();
2375 return;
2378 // compute the advance bytes per row for the src pixels
2379 uint32 src_padded_row_size;
2380 if (unpack_row_length_ > 0) {
2381 if (!GLES2Util::ComputeImagePaddedRowSize(
2382 unpack_row_length_, format, type, unpack_alignment_,
2383 &src_padded_row_size)) {
2384 SetGLError(
2385 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2386 return;
2388 } else {
2389 src_padded_row_size = padded_row_size;
2391 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2393 // advance pixels pointer past the skip images/rows/pixels
2394 pixels = reinterpret_cast<const int8*>(pixels) +
2395 unpack_skip_images_ * src_padded_row_size * src_height +
2396 unpack_skip_rows_ * src_padded_row_size;
2397 if (unpack_skip_pixels_) {
2398 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2399 pixels = reinterpret_cast<const int8*>(pixels) +
2400 unpack_skip_pixels_ * group_size;
2403 // Check if we can send it all at once.
2404 int32_t shm_id = 0;
2405 uint32_t shm_offset = 0;
2406 void* buffer_pointer = nullptr;
2408 ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
2409 ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
2411 if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
2412 shm_id = transfer_alloc.shm_id();
2413 shm_offset = transfer_alloc.offset();
2414 buffer_pointer = transfer_alloc.address();
2415 } else {
2416 mapped_alloc.Reset(size);
2417 if (mapped_alloc.valid()) {
2418 transfer_alloc.Discard();
2420 mapped_alloc.SetFlushAfterRelease(true);
2421 shm_id = mapped_alloc.shm_id();
2422 shm_offset = mapped_alloc.offset();
2423 buffer_pointer = mapped_alloc.address();
2427 if (buffer_pointer) {
2428 for (GLsizei z = 0; z < depth; ++z) {
2429 // Only the last row of the last image is unpadded.
2430 uint32 src_unpadded_row_size =
2431 (z == depth - 1) ? unpadded_row_size : src_padded_row_size;
2432 CopyRectToBuffer(
2433 pixels, height, src_unpadded_row_size, src_padded_row_size,
2434 buffer_pointer, padded_row_size);
2435 pixels = reinterpret_cast<const int8*>(pixels) +
2436 src_padded_row_size * src_height;
2437 buffer_pointer = reinterpret_cast<int8*>(buffer_pointer) +
2438 padded_row_size * height;
2440 helper_->TexImage3D(
2441 target, level, internalformat, width, height, depth, format, type,
2442 shm_id, shm_offset);
2443 CheckGLError();
2444 return;
2447 // No, so send it using TexSubImage3D.
2448 helper_->TexImage3D(
2449 target, level, internalformat, width, height, depth, format, type,
2450 0, 0);
2451 TexSubImage3DImpl(
2452 target, level, 0, 0, 0, width, height, depth, format, type,
2453 unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &transfer_alloc,
2454 padded_row_size);
2455 CheckGLError();
2458 void GLES2Implementation::TexSubImage2D(
2459 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2460 GLsizei height, GLenum format, GLenum type, const void* pixels) {
2461 GPU_CLIENT_SINGLE_THREAD_CHECK();
2462 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
2463 << GLES2Util::GetStringTextureTarget(target) << ", "
2464 << level << ", "
2465 << xoffset << ", " << yoffset << ", "
2466 << width << ", " << height << ", "
2467 << GLES2Util::GetStringTextureFormat(format) << ", "
2468 << GLES2Util::GetStringPixelType(type) << ", "
2469 << static_cast<const void*>(pixels) << ")");
2471 if (level < 0 || height < 0 || width < 0) {
2472 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
2473 return;
2475 if (height == 0 || width == 0) {
2476 return;
2479 uint32 temp_size;
2480 uint32 unpadded_row_size;
2481 uint32 padded_row_size;
2482 if (!GLES2Util::ComputeImageDataSizes(
2483 width, height, 1, format, type, unpack_alignment_, &temp_size,
2484 &unpadded_row_size, &padded_row_size)) {
2485 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
2486 return;
2489 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2490 if (bound_pixel_unpack_transfer_buffer_id_) {
2491 GLuint offset = ToGLuint(pixels);
2492 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2493 bound_pixel_unpack_transfer_buffer_id_,
2494 "glTexSubImage2D", offset, temp_size);
2495 if (buffer && buffer->shm_id() != -1) {
2496 helper_->TexSubImage2D(
2497 target, level, xoffset, yoffset, width, height, format, type,
2498 buffer->shm_id(), buffer->shm_offset() + offset, false);
2499 buffer->set_last_usage_token(helper_->InsertToken());
2500 CheckGLError();
2502 return;
2505 // compute the advance bytes per row for the src pixels
2506 uint32 src_padded_row_size;
2507 if (unpack_row_length_ > 0) {
2508 if (!GLES2Util::ComputeImagePaddedRowSize(
2509 unpack_row_length_, format, type, unpack_alignment_,
2510 &src_padded_row_size)) {
2511 SetGLError(
2512 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2513 return;
2515 } else {
2516 src_padded_row_size = padded_row_size;
2519 // advance pixels pointer past the skip rows and skip pixels
2520 pixels = reinterpret_cast<const int8*>(pixels) +
2521 unpack_skip_rows_ * src_padded_row_size;
2522 if (unpack_skip_pixels_) {
2523 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2524 pixels = reinterpret_cast<const int8*>(pixels) +
2525 unpack_skip_pixels_ * group_size;
2528 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2529 TexSubImage2DImpl(
2530 target, level, xoffset, yoffset, width, height, format, type,
2531 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
2532 padded_row_size);
2533 CheckGLError();
2536 void GLES2Implementation::TexSubImage3D(
2537 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2538 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2539 const void* pixels) {
2540 GPU_CLIENT_SINGLE_THREAD_CHECK();
2541 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D("
2542 << GLES2Util::GetStringTextureTarget(target) << ", "
2543 << level << ", "
2544 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2545 << width << ", " << height << ", " << depth << ", "
2546 << GLES2Util::GetStringTextureFormat(format) << ", "
2547 << GLES2Util::GetStringPixelType(type) << ", "
2548 << static_cast<const void*>(pixels) << ")");
2550 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2551 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "dimension < 0");
2552 return;
2554 if (height == 0 || width == 0 || depth == 0) {
2555 return;
2558 uint32 temp_size;
2559 uint32 unpadded_row_size;
2560 uint32 padded_row_size;
2561 if (!GLES2Util::ComputeImageDataSizes(
2562 width, height, depth, format, type, unpack_alignment_, &temp_size,
2563 &unpadded_row_size, &padded_row_size)) {
2564 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "size to large");
2565 return;
2568 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2569 if (bound_pixel_unpack_transfer_buffer_id_) {
2570 GLuint offset = ToGLuint(pixels);
2571 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2572 bound_pixel_unpack_transfer_buffer_id_,
2573 "glTexSubImage3D", offset, temp_size);
2574 if (buffer && buffer->shm_id() != -1) {
2575 helper_->TexSubImage3D(
2576 target, level, xoffset, yoffset, zoffset, width, height, depth,
2577 format, type, buffer->shm_id(), buffer->shm_offset() + offset, false);
2578 buffer->set_last_usage_token(helper_->InsertToken());
2579 CheckGLError();
2581 return;
2584 // compute the advance bytes per row for the src pixels
2585 uint32 src_padded_row_size;
2586 if (unpack_row_length_ > 0) {
2587 if (!GLES2Util::ComputeImagePaddedRowSize(
2588 unpack_row_length_, format, type, unpack_alignment_,
2589 &src_padded_row_size)) {
2590 SetGLError(
2591 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2592 return;
2594 } else {
2595 src_padded_row_size = padded_row_size;
2597 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2599 // advance pixels pointer past the skip images/rows/pixels
2600 pixels = reinterpret_cast<const int8*>(pixels) +
2601 unpack_skip_images_ * src_padded_row_size * src_height +
2602 unpack_skip_rows_ * src_padded_row_size;
2603 if (unpack_skip_pixels_) {
2604 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2605 pixels = reinterpret_cast<const int8*>(pixels) +
2606 unpack_skip_pixels_ * group_size;
2609 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2610 TexSubImage3DImpl(
2611 target, level, xoffset, yoffset, zoffset, width, height, depth,
2612 format, type, unpadded_row_size, pixels, src_padded_row_size, GL_FALSE,
2613 &buffer, padded_row_size);
2614 CheckGLError();
2617 static GLint ComputeNumRowsThatFitInBuffer(
2618 uint32 padded_row_size, uint32 unpadded_row_size,
2619 unsigned int size, GLsizei remaining_rows) {
2620 DCHECK_GE(unpadded_row_size, 0u);
2621 if (padded_row_size == 0) {
2622 return 1;
2624 GLint num_rows = size / padded_row_size;
2625 if (num_rows + 1 == remaining_rows &&
2626 size - num_rows * padded_row_size >= unpadded_row_size) {
2627 num_rows++;
2629 return num_rows;
2632 void GLES2Implementation::TexSubImage2DImpl(
2633 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2634 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
2635 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
2636 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
2637 DCHECK(buffer);
2638 DCHECK_GE(level, 0);
2639 DCHECK_GT(height, 0);
2640 DCHECK_GT(width, 0);
2642 const int8* source = reinterpret_cast<const int8*>(pixels);
2643 // Transfer by rows.
2644 while (height) {
2645 unsigned int desired_size =
2646 buffer_padded_row_size * (height - 1) + unpadded_row_size;
2647 if (!buffer->valid() || buffer->size() == 0) {
2648 buffer->Reset(desired_size);
2649 if (!buffer->valid()) {
2650 return;
2654 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2655 buffer_padded_row_size, unpadded_row_size, buffer->size(), height);
2656 num_rows = std::min(num_rows, height);
2657 CopyRectToBuffer(
2658 source, num_rows, unpadded_row_size, pixels_padded_row_size,
2659 buffer->address(), buffer_padded_row_size);
2660 helper_->TexSubImage2D(
2661 target, level, xoffset, yoffset, width, num_rows, format, type,
2662 buffer->shm_id(), buffer->offset(), internal);
2663 buffer->Release();
2664 yoffset += num_rows;
2665 source += num_rows * pixels_padded_row_size;
2666 height -= num_rows;
2670 void GLES2Implementation::TexSubImage3DImpl(
2671 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei zoffset,
2672 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2673 uint32 unpadded_row_size, const void* pixels, uint32 pixels_padded_row_size,
2674 GLboolean internal, ScopedTransferBufferPtr* buffer,
2675 uint32 buffer_padded_row_size) {
2676 DCHECK(buffer);
2677 DCHECK_GE(level, 0);
2678 DCHECK_GT(height, 0);
2679 DCHECK_GT(width, 0);
2680 DCHECK_GT(depth, 0);
2681 const int8* source = reinterpret_cast<const int8*>(pixels);
2682 GLsizei total_rows = height * depth;
2683 GLint row_index = 0, depth_index = 0;
2684 while (total_rows) {
2685 // Each time, we either copy one or more images, or copy one or more rows
2686 // within a single image, depending on the buffer size limit.
2687 GLsizei max_rows;
2688 unsigned int desired_size;
2689 if (row_index > 0) {
2690 // We are in the middle of an image. Send the remaining of the image.
2691 max_rows = height - row_index;
2692 if (total_rows <= height) {
2693 // Last image, so last row is unpadded.
2694 desired_size = buffer_padded_row_size * (max_rows - 1) +
2695 unpadded_row_size;
2696 } else {
2697 desired_size = buffer_padded_row_size * max_rows;
2699 } else {
2700 // Send all the remaining data if possible.
2701 max_rows = total_rows;
2702 desired_size =
2703 buffer_padded_row_size * (max_rows - 1) + unpadded_row_size;
2705 if (!buffer->valid() || buffer->size() == 0) {
2706 buffer->Reset(desired_size);
2707 if (!buffer->valid()) {
2708 return;
2711 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2712 buffer_padded_row_size, unpadded_row_size, buffer->size(), total_rows);
2713 num_rows = std::min(num_rows, max_rows);
2714 GLint num_images = num_rows / height;
2715 GLsizei my_height, my_depth;
2716 if (num_images > 0) {
2717 num_rows = num_images * height;
2718 my_height = height;
2719 my_depth = num_images;
2720 } else {
2721 my_height = num_rows;
2722 my_depth = 1;
2725 if (num_images > 0) {
2726 int8* buffer_pointer = reinterpret_cast<int8*>(buffer->address());
2727 uint32 src_height =
2728 unpack_image_height_ > 0 ? unpack_image_height_ : height;
2729 uint32 image_size_dst = buffer_padded_row_size * height;
2730 uint32 image_size_src = pixels_padded_row_size * src_height;
2731 for (GLint ii = 0; ii < num_images; ++ii) {
2732 uint32 my_unpadded_row_size;
2733 if (total_rows == num_rows && ii + 1 == num_images)
2734 my_unpadded_row_size = unpadded_row_size;
2735 else
2736 my_unpadded_row_size = pixels_padded_row_size;
2737 CopyRectToBuffer(
2738 source + ii * image_size_src, my_height, my_unpadded_row_size,
2739 pixels_padded_row_size, buffer_pointer + ii * image_size_dst,
2740 buffer_padded_row_size);
2742 } else {
2743 uint32 my_unpadded_row_size;
2744 if (total_rows == num_rows)
2745 my_unpadded_row_size = unpadded_row_size;
2746 else
2747 my_unpadded_row_size = pixels_padded_row_size;
2748 CopyRectToBuffer(
2749 source, my_height, my_unpadded_row_size, pixels_padded_row_size,
2750 buffer->address(), buffer_padded_row_size);
2752 helper_->TexSubImage3D(
2753 target, level, xoffset, yoffset + row_index, zoffset + depth_index,
2754 width, my_height, my_depth,
2755 format, type, buffer->shm_id(), buffer->offset(), internal);
2756 buffer->Release();
2758 total_rows -= num_rows;
2759 if (total_rows > 0) {
2760 GLint num_image_paddings;
2761 if (num_images > 0) {
2762 DCHECK_EQ(row_index, 0);
2763 depth_index += num_images;
2764 num_image_paddings = num_images;
2765 } else {
2766 row_index = (row_index + my_height) % height;
2767 num_image_paddings = 0;
2768 if (my_height > 0 && row_index == 0) {
2769 depth_index++;
2770 num_image_paddings++;
2773 source += num_rows * pixels_padded_row_size;
2774 if (unpack_image_height_ > height && num_image_paddings > 0) {
2775 source += num_image_paddings * (unpack_image_height_ - height) *
2776 pixels_padded_row_size;
2782 bool GLES2Implementation::GetActiveAttribHelper(
2783 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2784 GLenum* type, char* name) {
2785 // Clear the bucket so if the command fails nothing will be in it.
2786 helper_->SetBucketSize(kResultBucketId, 0);
2787 typedef cmds::GetActiveAttrib::Result Result;
2788 Result* result = GetResultAs<Result*>();
2789 if (!result) {
2790 return false;
2792 // Set as failed so if the command fails we'll recover.
2793 result->success = false;
2794 helper_->GetActiveAttrib(program, index, kResultBucketId,
2795 GetResultShmId(), GetResultShmOffset());
2796 WaitForCmd();
2797 if (result->success) {
2798 if (size) {
2799 *size = result->size;
2801 if (type) {
2802 *type = result->type;
2804 if (length || name) {
2805 std::vector<int8> str;
2806 GetBucketContents(kResultBucketId, &str);
2807 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2808 std::max(static_cast<size_t>(0),
2809 str.size() - 1));
2810 if (length) {
2811 *length = max_size;
2813 if (name && bufsize > 0) {
2814 memcpy(name, &str[0], max_size);
2815 name[max_size] = '\0';
2819 return result->success != 0;
2822 void GLES2Implementation::GetActiveAttrib(
2823 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2824 GLenum* type, char* name) {
2825 GPU_CLIENT_SINGLE_THREAD_CHECK();
2826 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2827 << program << ", " << index << ", " << bufsize << ", "
2828 << static_cast<const void*>(length) << ", "
2829 << static_cast<const void*>(size) << ", "
2830 << static_cast<const void*>(type) << ", "
2831 << static_cast<const void*>(name) << ", ");
2832 if (bufsize < 0) {
2833 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
2834 return;
2836 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2837 bool success = share_group_->program_info_manager()->GetActiveAttrib(
2838 this, program, index, bufsize, length, size, type, name);
2839 if (success) {
2840 if (size) {
2841 GPU_CLIENT_LOG(" size: " << *size);
2843 if (type) {
2844 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2846 if (name) {
2847 GPU_CLIENT_LOG(" name: " << name);
2850 CheckGLError();
2853 bool GLES2Implementation::GetActiveUniformHelper(
2854 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2855 GLenum* type, char* name) {
2856 // Clear the bucket so if the command fails nothing will be in it.
2857 helper_->SetBucketSize(kResultBucketId, 0);
2858 typedef cmds::GetActiveUniform::Result Result;
2859 Result* result = GetResultAs<Result*>();
2860 if (!result) {
2861 return false;
2863 // Set as failed so if the command fails we'll recover.
2864 result->success = false;
2865 helper_->GetActiveUniform(program, index, kResultBucketId,
2866 GetResultShmId(), GetResultShmOffset());
2867 WaitForCmd();
2868 if (result->success) {
2869 if (size) {
2870 *size = result->size;
2872 if (type) {
2873 *type = result->type;
2875 if (length || name) {
2876 std::vector<int8> str;
2877 GetBucketContents(kResultBucketId, &str);
2878 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2879 std::max(static_cast<size_t>(0),
2880 str.size() - 1));
2881 if (length) {
2882 *length = max_size;
2884 if (name && bufsize > 0) {
2885 memcpy(name, &str[0], max_size);
2886 name[max_size] = '\0';
2890 return result->success != 0;
2893 void GLES2Implementation::GetActiveUniform(
2894 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2895 GLenum* type, char* name) {
2896 GPU_CLIENT_SINGLE_THREAD_CHECK();
2897 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2898 << program << ", " << index << ", " << bufsize << ", "
2899 << static_cast<const void*>(length) << ", "
2900 << static_cast<const void*>(size) << ", "
2901 << static_cast<const void*>(type) << ", "
2902 << static_cast<const void*>(name) << ", ");
2903 if (bufsize < 0) {
2904 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2905 return;
2907 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2908 bool success = share_group_->program_info_manager()->GetActiveUniform(
2909 this, program, index, bufsize, length, size, type, name);
2910 if (success) {
2911 if (size) {
2912 GPU_CLIENT_LOG(" size: " << *size);
2914 if (type) {
2915 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2917 if (name) {
2918 GPU_CLIENT_LOG(" name: " << name);
2921 CheckGLError();
2924 bool GLES2Implementation::GetActiveUniformBlockNameHelper(
2925 GLuint program, GLuint index, GLsizei bufsize,
2926 GLsizei* length, char* name) {
2927 DCHECK_LE(0, bufsize);
2928 // Clear the bucket so if the command fails nothing will be in it.
2929 helper_->SetBucketSize(kResultBucketId, 0);
2930 typedef cmds::GetActiveUniformBlockName::Result Result;
2931 Result* result = GetResultAs<Result*>();
2932 if (!result) {
2933 return false;
2935 // Set as failed so if the command fails we'll recover.
2936 *result = 0;
2937 helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
2938 GetResultShmId(), GetResultShmOffset());
2939 WaitForCmd();
2940 if (*result) {
2941 if (bufsize == 0) {
2942 if (length) {
2943 *length = 0;
2945 } else if (length || name) {
2946 std::vector<int8> str;
2947 GetBucketContents(kResultBucketId, &str);
2948 DCHECK_GT(str.size(), 0u);
2949 GLsizei max_size =
2950 std::min(bufsize, static_cast<GLsizei>(str.size())) - 1;
2951 if (length) {
2952 *length = max_size;
2954 if (name) {
2955 memcpy(name, &str[0], max_size);
2956 name[max_size] = '\0';
2960 return *result != 0;
2963 void GLES2Implementation::GetActiveUniformBlockName(
2964 GLuint program, GLuint index, GLsizei bufsize,
2965 GLsizei* length, char* name) {
2966 GPU_CLIENT_SINGLE_THREAD_CHECK();
2967 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
2968 << program << ", " << index << ", " << bufsize << ", "
2969 << static_cast<const void*>(length) << ", "
2970 << static_cast<const void*>(name) << ")");
2971 if (bufsize < 0) {
2972 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformBlockName", "bufsize < 0");
2973 return;
2975 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockName");
2976 bool success =
2977 share_group_->program_info_manager()->GetActiveUniformBlockName(
2978 this, program, index, bufsize, length, name);
2979 if (success) {
2980 if (name) {
2981 GPU_CLIENT_LOG(" name: " << name);
2984 CheckGLError();
2987 bool GLES2Implementation::GetActiveUniformBlockivHelper(
2988 GLuint program, GLuint index, GLenum pname, GLint* params) {
2989 typedef cmds::GetActiveUniformBlockiv::Result Result;
2990 Result* result = GetResultAs<Result*>();
2991 if (!result) {
2992 return false;
2994 result->SetNumResults(0);
2995 helper_->GetActiveUniformBlockiv(
2996 program, index, pname, GetResultShmId(), GetResultShmOffset());
2997 WaitForCmd();
2998 if (result->GetNumResults() > 0) {
2999 if (params) {
3000 result->CopyResult(params);
3002 GPU_CLIENT_LOG_CODE_BLOCK({
3003 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
3004 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3007 return true;
3009 return false;
3012 void GLES2Implementation::GetActiveUniformBlockiv(
3013 GLuint program, GLuint index, GLenum pname, GLint* params) {
3014 GPU_CLIENT_SINGLE_THREAD_CHECK();
3015 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
3016 << program << ", " << index << ", "
3017 << GLES2Util::GetStringUniformBlockParameter(pname) << ", "
3018 << static_cast<const void*>(params) << ")");
3019 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
3020 bool success =
3021 share_group_->program_info_manager()->GetActiveUniformBlockiv(
3022 this, program, index, pname, params);
3023 if (success) {
3024 if (params) {
3025 // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
3026 // be more than one value returned in params.
3027 GPU_CLIENT_LOG(" params: " << params[0]);
3030 CheckGLError();
3033 bool GLES2Implementation::GetActiveUniformsivHelper(
3034 GLuint program, GLsizei count, const GLuint* indices,
3035 GLenum pname, GLint* params) {
3036 typedef cmds::GetActiveUniformsiv::Result Result;
3037 Result* result = GetResultAs<Result*>();
3038 if (!result) {
3039 return false;
3041 result->SetNumResults(0);
3042 base::CheckedNumeric<size_t> bytes = static_cast<size_t>(count);
3043 bytes *= sizeof(GLuint);
3044 if (!bytes.IsValid()) {
3045 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count overflow");
3046 return false;
3048 SetBucketContents(kResultBucketId, indices, bytes.ValueOrDefault(0));
3049 helper_->GetActiveUniformsiv(
3050 program, kResultBucketId, pname, GetResultShmId(), GetResultShmOffset());
3051 WaitForCmd();
3052 bool success = result->GetNumResults() == count;
3053 if (success) {
3054 if (params) {
3055 result->CopyResult(params);
3057 GPU_CLIENT_LOG_CODE_BLOCK({
3058 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
3059 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3063 helper_->SetBucketSize(kResultBucketId, 0);
3064 return success;
3067 void GLES2Implementation::GetActiveUniformsiv(
3068 GLuint program, GLsizei count, const GLuint* indices,
3069 GLenum pname, GLint* params) {
3070 GPU_CLIENT_SINGLE_THREAD_CHECK();
3071 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv("
3072 << program << ", " << count << ", "
3073 << static_cast<const void*>(indices) << ", "
3074 << GLES2Util::GetStringUniformParameter(pname) << ", "
3075 << static_cast<const void*>(params) << ")");
3076 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
3077 if (count < 0) {
3078 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count < 0");
3079 return;
3081 bool success = share_group_->program_info_manager()->GetActiveUniformsiv(
3082 this, program, count, indices, pname, params);
3083 if (success) {
3084 if (params) {
3085 GPU_CLIENT_LOG_CODE_BLOCK({
3086 for (GLsizei ii = 0; ii < count; ++ii) {
3087 GPU_CLIENT_LOG(" " << ii << ": " << params[ii]);
3092 CheckGLError();
3095 void GLES2Implementation::GetAttachedShaders(
3096 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
3097 GPU_CLIENT_SINGLE_THREAD_CHECK();
3098 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
3099 << program << ", " << maxcount << ", "
3100 << static_cast<const void*>(count) << ", "
3101 << static_cast<const void*>(shaders) << ", ");
3102 if (maxcount < 0) {
3103 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
3104 return;
3106 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
3107 typedef cmds::GetAttachedShaders::Result Result;
3108 uint32 size = Result::ComputeSize(maxcount);
3109 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
3110 if (!result) {
3111 return;
3113 result->SetNumResults(0);
3114 helper_->GetAttachedShaders(
3115 program,
3116 transfer_buffer_->GetShmId(),
3117 transfer_buffer_->GetOffset(result),
3118 size);
3119 int32 token = helper_->InsertToken();
3120 WaitForCmd();
3121 if (count) {
3122 *count = result->GetNumResults();
3124 result->CopyResult(shaders);
3125 GPU_CLIENT_LOG_CODE_BLOCK({
3126 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3127 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3130 transfer_buffer_->FreePendingToken(result, token);
3131 CheckGLError();
3134 void GLES2Implementation::GetShaderPrecisionFormat(
3135 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
3136 GPU_CLIENT_SINGLE_THREAD_CHECK();
3137 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
3138 << GLES2Util::GetStringShaderType(shadertype) << ", "
3139 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
3140 << static_cast<const void*>(range) << ", "
3141 << static_cast<const void*>(precision) << ", ");
3142 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
3143 typedef cmds::GetShaderPrecisionFormat::Result Result;
3144 Result* result = GetResultAs<Result*>();
3145 if (!result) {
3146 return;
3149 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
3150 GLStaticState::ShaderPrecisionMap::iterator i =
3151 static_state_.shader_precisions.find(key);
3152 if (i != static_state_.shader_precisions.end()) {
3153 *result = i->second;
3154 } else {
3155 result->success = false;
3156 helper_->GetShaderPrecisionFormat(
3157 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
3158 WaitForCmd();
3159 if (result->success)
3160 static_state_.shader_precisions[key] = *result;
3163 if (result->success) {
3164 if (range) {
3165 range[0] = result->min_range;
3166 range[1] = result->max_range;
3167 GPU_CLIENT_LOG(" min_range: " << range[0]);
3168 GPU_CLIENT_LOG(" min_range: " << range[1]);
3170 if (precision) {
3171 precision[0] = result->precision;
3172 GPU_CLIENT_LOG(" min_range: " << precision[0]);
3175 CheckGLError();
3178 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
3179 const char* result = NULL;
3180 // Clears the bucket so if the command fails nothing will be in it.
3181 helper_->SetBucketSize(kResultBucketId, 0);
3182 helper_->GetString(name, kResultBucketId);
3183 std::string str;
3184 if (GetBucketAsString(kResultBucketId, &str)) {
3185 // Adds extensions implemented on client side only.
3186 switch (name) {
3187 case GL_EXTENSIONS:
3188 str += std::string(str.empty() ? "" : " ") +
3189 "GL_EXT_unpack_subimage "
3190 "GL_CHROMIUM_map_sub";
3191 if (capabilities_.image)
3192 str += " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
3193 if (capabilities_.future_sync_points)
3194 str += " GL_CHROMIUM_future_sync_point";
3195 break;
3196 default:
3197 break;
3200 // Because of WebGL the extensions can change. We have to cache each unique
3201 // result since we don't know when the client will stop referring to a
3202 // previous one it queries.
3203 GLStringMap::iterator it = gl_strings_.find(name);
3204 if (it == gl_strings_.end()) {
3205 std::set<std::string> strings;
3206 std::pair<GLStringMap::iterator, bool> insert_result =
3207 gl_strings_.insert(std::make_pair(name, strings));
3208 DCHECK(insert_result.second);
3209 it = insert_result.first;
3211 std::set<std::string>& string_set = it->second;
3212 std::set<std::string>::const_iterator sit = string_set.find(str);
3213 if (sit != string_set.end()) {
3214 result = sit->c_str();
3215 } else {
3216 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
3217 string_set.insert(str);
3218 DCHECK(insert_result.second);
3219 result = insert_result.first->c_str();
3222 return reinterpret_cast<const GLubyte*>(result);
3225 const GLubyte* GLES2Implementation::GetString(GLenum name) {
3226 GPU_CLIENT_SINGLE_THREAD_CHECK();
3227 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
3228 << GLES2Util::GetStringStringType(name) << ")");
3229 TRACE_EVENT0("gpu", "GLES2::GetString");
3230 const GLubyte* result = GetStringHelper(name);
3231 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
3232 CheckGLError();
3233 return result;
3236 bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
3237 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3238 GLenum* type, char* name) {
3239 // Clear the bucket so if the command fails nothing will be in it.
3240 helper_->SetBucketSize(kResultBucketId, 0);
3241 typedef cmds::GetTransformFeedbackVarying::Result Result;
3242 Result* result = GetResultAs<Result*>();
3243 if (!result) {
3244 return false;
3246 // Set as failed so if the command fails we'll recover.
3247 result->success = false;
3248 helper_->GetTransformFeedbackVarying(
3249 program, index, kResultBucketId, GetResultShmId(), GetResultShmOffset());
3250 WaitForCmd();
3251 if (result->success) {
3252 if (size) {
3253 *size = result->size;
3255 if (type) {
3256 *type = result->type;
3258 if (length || name) {
3259 std::vector<int8> str;
3260 GetBucketContents(kResultBucketId, &str);
3261 GLsizei max_size = std::min(bufsize, static_cast<GLsizei>(str.size()));
3262 if (max_size > 0) {
3263 --max_size;
3265 if (length) {
3266 *length = max_size;
3268 if (name) {
3269 if (max_size > 0) {
3270 memcpy(name, &str[0], max_size);
3271 name[max_size] = '\0';
3272 } else if (bufsize > 0) {
3273 name[0] = '\0';
3278 return result->success != 0;
3281 void GLES2Implementation::GetTransformFeedbackVarying(
3282 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3283 GLenum* type, char* name) {
3284 GPU_CLIENT_SINGLE_THREAD_CHECK();
3285 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
3286 << program << ", " << index << ", " << bufsize << ", "
3287 << static_cast<const void*>(length) << ", "
3288 << static_cast<const void*>(size) << ", "
3289 << static_cast<const void*>(type) << ", "
3290 << static_cast<const void*>(name) << ", ");
3291 if (bufsize < 0) {
3292 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVarying",
3293 "bufsize < 0");
3294 return;
3296 TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
3297 bool success =
3298 share_group_->program_info_manager()->GetTransformFeedbackVarying(
3299 this, program, index, bufsize, length, size, type, name);
3300 if (success) {
3301 if (size) {
3302 GPU_CLIENT_LOG(" size: " << *size);
3304 if (type) {
3305 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
3307 if (name) {
3308 GPU_CLIENT_LOG(" name: " << name);
3311 CheckGLError();
3314 void GLES2Implementation::GetUniformfv(
3315 GLuint program, GLint location, GLfloat* params) {
3316 GPU_CLIENT_SINGLE_THREAD_CHECK();
3317 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
3318 << program << ", " << location << ", "
3319 << static_cast<const void*>(params) << ")");
3320 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
3321 typedef cmds::GetUniformfv::Result Result;
3322 Result* result = GetResultAs<Result*>();
3323 if (!result) {
3324 return;
3326 result->SetNumResults(0);
3327 helper_->GetUniformfv(
3328 program, location, GetResultShmId(), GetResultShmOffset());
3329 WaitForCmd();
3330 result->CopyResult(params);
3331 GPU_CLIENT_LOG_CODE_BLOCK({
3332 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3333 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3336 CheckGLError();
3339 void GLES2Implementation::GetUniformiv(
3340 GLuint program, GLint location, GLint* params) {
3341 GPU_CLIENT_SINGLE_THREAD_CHECK();
3342 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
3343 << program << ", " << location << ", "
3344 << static_cast<const void*>(params) << ")");
3345 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
3346 typedef cmds::GetUniformiv::Result Result;
3347 Result* result = GetResultAs<Result*>();
3348 if (!result) {
3349 return;
3351 result->SetNumResults(0);
3352 helper_->GetUniformiv(
3353 program, location, GetResultShmId(), GetResultShmOffset());
3354 WaitForCmd();
3355 GetResultAs<cmds::GetUniformiv::Result*>()->CopyResult(params);
3356 GPU_CLIENT_LOG_CODE_BLOCK({
3357 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3358 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3361 CheckGLError();
3364 void GLES2Implementation::GetUniformuiv(
3365 GLuint program, GLint location, GLuint* params) {
3366 GPU_CLIENT_SINGLE_THREAD_CHECK();
3367 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformuiv("
3368 << program << ", " << location << ", "
3369 << static_cast<const void*>(params) << ")");
3370 TRACE_EVENT0("gpu", "GLES2::GetUniformuiv");
3371 typedef cmds::GetUniformuiv::Result Result;
3372 Result* result = GetResultAs<Result*>();
3373 if (!result) {
3374 return;
3376 result->SetNumResults(0);
3377 helper_->GetUniformuiv(
3378 program, location, GetResultShmId(), GetResultShmOffset());
3379 WaitForCmd();
3380 GetResultAs<cmds::GetUniformuiv::Result*>()->CopyResult(params);
3381 GPU_CLIENT_LOG_CODE_BLOCK({
3382 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3383 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3386 CheckGLError();
3389 void GLES2Implementation::ReadPixels(
3390 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
3391 GLenum type, void* pixels) {
3392 GPU_CLIENT_SINGLE_THREAD_CHECK();
3393 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
3394 << xoffset << ", " << yoffset << ", "
3395 << width << ", " << height << ", "
3396 << GLES2Util::GetStringReadPixelFormat(format) << ", "
3397 << GLES2Util::GetStringPixelType(type) << ", "
3398 << static_cast<const void*>(pixels) << ")");
3399 if (width < 0 || height < 0) {
3400 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
3401 return;
3403 if (width == 0 || height == 0) {
3404 return;
3407 // glReadPixel pads the size of each row of pixels by an amount specified by
3408 // glPixelStorei. So, we have to take that into account both in the fact that
3409 // the pixels returned from the ReadPixel command will include that padding
3410 // and that when we copy the results to the user's buffer we need to not
3411 // write those padding bytes but leave them as they are.
3413 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
3414 typedef cmds::ReadPixels::Result Result;
3416 int8* dest = reinterpret_cast<int8*>(pixels);
3417 uint32 temp_size;
3418 uint32 unpadded_row_size;
3419 uint32 padded_row_size;
3420 if (!GLES2Util::ComputeImageDataSizes(
3421 width, 2, 1, format, type, pack_alignment_, &temp_size,
3422 &unpadded_row_size, &padded_row_size)) {
3423 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
3424 return;
3427 if (bound_pixel_pack_transfer_buffer_id_) {
3428 GLuint offset = ToGLuint(pixels);
3429 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3430 bound_pixel_pack_transfer_buffer_id_,
3431 "glReadPixels", offset, padded_row_size * height);
3432 if (buffer && buffer->shm_id() != -1) {
3433 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
3434 buffer->shm_id(), buffer->shm_offset(),
3435 0, 0, true);
3436 CheckGLError();
3438 return;
3441 if (!pixels) {
3442 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
3443 return;
3446 // Transfer by rows.
3447 // The max rows we can transfer.
3448 while (height) {
3449 GLsizei desired_size = padded_row_size * (height - 1) + unpadded_row_size;
3450 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
3451 if (!buffer.valid()) {
3452 return;
3454 GLint num_rows = ComputeNumRowsThatFitInBuffer(
3455 padded_row_size, unpadded_row_size, buffer.size(), height);
3456 num_rows = std::min(num_rows, height);
3457 // NOTE: We must look up the address of the result area AFTER allocation
3458 // of the transfer buffer since the transfer buffer may be reallocated.
3459 Result* result = GetResultAs<Result*>();
3460 if (!result) {
3461 return;
3463 *result = 0; // mark as failed.
3464 helper_->ReadPixels(
3465 xoffset, yoffset, width, num_rows, format, type,
3466 buffer.shm_id(), buffer.offset(),
3467 GetResultShmId(), GetResultShmOffset(),
3468 false);
3469 WaitForCmd();
3470 if (*result != 0) {
3471 // when doing a y-flip we have to iterate through top-to-bottom chunks
3472 // of the dst. The service side handles reversing the rows within a
3473 // chunk.
3474 int8* rows_dst;
3475 if (pack_reverse_row_order_) {
3476 rows_dst = dest + (height - num_rows) * padded_row_size;
3477 } else {
3478 rows_dst = dest;
3480 // We have to copy 1 row at a time to avoid writing pad bytes.
3481 const int8* src = static_cast<const int8*>(buffer.address());
3482 for (GLint yy = 0; yy < num_rows; ++yy) {
3483 memcpy(rows_dst, src, unpadded_row_size);
3484 rows_dst += padded_row_size;
3485 src += padded_row_size;
3487 if (!pack_reverse_row_order_) {
3488 dest = rows_dst;
3491 // If it was not marked as successful exit.
3492 if (*result == 0) {
3493 return;
3495 yoffset += num_rows;
3496 height -= num_rows;
3498 CheckGLError();
3501 void GLES2Implementation::ActiveTexture(GLenum texture) {
3502 GPU_CLIENT_SINGLE_THREAD_CHECK();
3503 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
3504 << GLES2Util::GetStringEnum(texture) << ")");
3505 GLuint texture_index = texture - GL_TEXTURE0;
3506 if (texture_index >=
3507 static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
3508 SetGLErrorInvalidEnum(
3509 "glActiveTexture", texture, "texture");
3510 return;
3513 active_texture_unit_ = texture_index;
3514 helper_->ActiveTexture(texture);
3515 CheckGLError();
3518 void GLES2Implementation::GenBuffersHelper(
3519 GLsizei /* n */, const GLuint* /* buffers */) {
3522 void GLES2Implementation::GenFramebuffersHelper(
3523 GLsizei /* n */, const GLuint* /* framebuffers */) {
3526 void GLES2Implementation::GenRenderbuffersHelper(
3527 GLsizei /* n */, const GLuint* /* renderbuffers */) {
3530 void GLES2Implementation::GenTexturesHelper(
3531 GLsizei /* n */, const GLuint* /* textures */) {
3534 void GLES2Implementation::GenVertexArraysOESHelper(
3535 GLsizei n, const GLuint* arrays) {
3536 vertex_array_object_manager_->GenVertexArrays(n, arrays);
3539 void GLES2Implementation::GenQueriesEXTHelper(
3540 GLsizei /* n */, const GLuint* /* queries */) {
3543 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
3544 GLsizei /* n */,
3545 const GLuint* /* valuebuffers */) {
3548 void GLES2Implementation::GenSamplersHelper(
3549 GLsizei /* n */, const GLuint* /* samplers */) {
3552 void GLES2Implementation::GenTransformFeedbacksHelper(
3553 GLsizei /* n */, const GLuint* /* transformfeedbacks */) {
3556 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
3557 // generates a new resource. On newer versions of OpenGL they don't. The code
3558 // related to binding below will need to change if we switch to the new OpenGL
3559 // model. Specifically it assumes a bind will succeed which is always true in
3560 // the old model but possibly not true in the new model if another context has
3561 // deleted the resource.
3563 // NOTE #2: There is a bug in some BindXXXHelpers, that IDs might be marked as
3564 // used even when Bind has failed. However, the bug is minor compared to the
3565 // overhead & duplicated checking in client side.
3567 void GLES2Implementation::BindBufferHelper(
3568 GLenum target, GLuint buffer_id) {
3569 // TODO(gman): See note #1 above.
3570 bool changed = false;
3571 switch (target) {
3572 case GL_ARRAY_BUFFER:
3573 if (bound_array_buffer_ != buffer_id) {
3574 bound_array_buffer_ = buffer_id;
3575 changed = true;
3577 break;
3578 case GL_COPY_READ_BUFFER:
3579 if (bound_copy_read_buffer_ != buffer_id) {
3580 bound_copy_read_buffer_ = buffer_id;
3581 changed = true;
3583 break;
3584 case GL_COPY_WRITE_BUFFER:
3585 if (bound_copy_write_buffer_ != buffer_id) {
3586 bound_copy_write_buffer_ = buffer_id;
3587 changed = true;
3589 break;
3590 case GL_ELEMENT_ARRAY_BUFFER:
3591 changed = vertex_array_object_manager_->BindElementArray(buffer_id);
3592 break;
3593 case GL_PIXEL_PACK_BUFFER:
3594 if (bound_pixel_pack_buffer_ != buffer_id) {
3595 bound_pixel_pack_buffer_ = buffer_id;
3596 changed = true;
3598 break;
3599 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3600 bound_pixel_pack_transfer_buffer_id_ = buffer_id;
3601 break;
3602 case GL_PIXEL_UNPACK_BUFFER:
3603 if (bound_pixel_unpack_buffer_ != buffer_id) {
3604 bound_pixel_unpack_buffer_ = buffer_id;
3605 changed = true;
3607 break;
3608 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3609 bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
3610 break;
3611 case GL_TRANSFORM_FEEDBACK_BUFFER:
3612 if (bound_transform_feedback_buffer_ != buffer_id) {
3613 bound_transform_feedback_buffer_ = buffer_id;
3614 changed = true;
3616 break;
3617 case GL_UNIFORM_BUFFER:
3618 if (bound_uniform_buffer_ != buffer_id) {
3619 bound_uniform_buffer_ = buffer_id;
3620 changed = true;
3622 break;
3623 default:
3624 changed = true;
3625 break;
3627 // TODO(gman): See note #2 above.
3628 if (changed) {
3629 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3630 this, target, buffer_id, &GLES2Implementation::BindBufferStub);
3634 void GLES2Implementation::BindBufferStub(GLenum target, GLuint buffer) {
3635 helper_->BindBuffer(target, buffer);
3636 if (share_group_->bind_generates_resource())
3637 helper_->CommandBufferHelper::OrderingBarrier();
3640 void GLES2Implementation::BindBufferBaseHelper(
3641 GLenum target, GLuint index, GLuint buffer_id) {
3642 // TODO(zmo): See note #1 above.
3643 // TODO(zmo): See note #2 above.
3644 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3645 this, target, index, buffer_id, &GLES2Implementation::BindBufferBaseStub);
3648 void GLES2Implementation::BindBufferBaseStub(
3649 GLenum target, GLuint index, GLuint buffer) {
3650 helper_->BindBufferBase(target, index, buffer);
3651 if (share_group_->bind_generates_resource())
3652 helper_->CommandBufferHelper::Flush();
3655 void GLES2Implementation::BindBufferRangeHelper(
3656 GLenum target, GLuint index, GLuint buffer_id,
3657 GLintptr offset, GLsizeiptr size) {
3658 // TODO(zmo): See note #1 above.
3659 // TODO(zmo): See note #2 above.
3660 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3661 this, target, index, buffer_id, offset, size,
3662 &GLES2Implementation::BindBufferRangeStub);
3665 void GLES2Implementation::BindBufferRangeStub(
3666 GLenum target, GLuint index, GLuint buffer,
3667 GLintptr offset, GLsizeiptr size) {
3668 helper_->BindBufferRange(target, index, buffer, offset, size);
3669 if (share_group_->bind_generates_resource())
3670 helper_->CommandBufferHelper::Flush();
3673 void GLES2Implementation::BindFramebufferHelper(
3674 GLenum target, GLuint framebuffer) {
3675 // TODO(gman): See note #1 above.
3676 bool changed = false;
3677 switch (target) {
3678 case GL_FRAMEBUFFER:
3679 if (bound_framebuffer_ != framebuffer ||
3680 bound_read_framebuffer_ != framebuffer) {
3681 bound_framebuffer_ = framebuffer;
3682 bound_read_framebuffer_ = framebuffer;
3683 changed = true;
3685 break;
3686 case GL_READ_FRAMEBUFFER:
3687 if (!IsChromiumFramebufferMultisampleAvailable()) {
3688 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3689 return;
3691 if (bound_read_framebuffer_ != framebuffer) {
3692 bound_read_framebuffer_ = framebuffer;
3693 changed = true;
3695 break;
3696 case GL_DRAW_FRAMEBUFFER:
3697 if (!IsChromiumFramebufferMultisampleAvailable()) {
3698 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3699 return;
3701 if (bound_framebuffer_ != framebuffer) {
3702 bound_framebuffer_ = framebuffer;
3703 changed = true;
3705 break;
3706 default:
3707 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3708 return;
3711 if (changed) {
3712 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(
3713 this, target, framebuffer, &GLES2Implementation::BindFramebufferStub);
3717 void GLES2Implementation::BindFramebufferStub(GLenum target,
3718 GLuint framebuffer) {
3719 helper_->BindFramebuffer(target, framebuffer);
3720 if (share_group_->bind_generates_resource())
3721 helper_->CommandBufferHelper::OrderingBarrier();
3724 void GLES2Implementation::BindRenderbufferHelper(
3725 GLenum target, GLuint renderbuffer) {
3726 // TODO(gman): See note #1 above.
3727 bool changed = false;
3728 switch (target) {
3729 case GL_RENDERBUFFER:
3730 if (bound_renderbuffer_ != renderbuffer) {
3731 bound_renderbuffer_ = renderbuffer;
3732 changed = true;
3734 break;
3735 default:
3736 changed = true;
3737 break;
3739 // TODO(zmo): See note #2 above.
3740 if (changed) {
3741 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(
3742 this, target, renderbuffer,
3743 &GLES2Implementation::BindRenderbufferStub);
3747 void GLES2Implementation::BindRenderbufferStub(GLenum target,
3748 GLuint renderbuffer) {
3749 helper_->BindRenderbuffer(target, renderbuffer);
3750 if (share_group_->bind_generates_resource())
3751 helper_->CommandBufferHelper::OrderingBarrier();
3754 void GLES2Implementation::BindSamplerHelper(GLuint unit,
3755 GLuint sampler) {
3756 helper_->BindSampler(unit, sampler);
3759 void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
3760 // TODO(gman): See note #1 above.
3761 // TODO(gman): Change this to false once we figure out why it's failing
3762 // on daisy.
3763 bool changed = true;
3764 TextureUnit& unit = texture_units_[active_texture_unit_];
3765 switch (target) {
3766 case GL_TEXTURE_2D:
3767 if (unit.bound_texture_2d != texture) {
3768 unit.bound_texture_2d = texture;
3769 changed = true;
3771 break;
3772 case GL_TEXTURE_CUBE_MAP:
3773 if (unit.bound_texture_cube_map != texture) {
3774 unit.bound_texture_cube_map = texture;
3775 changed = true;
3777 break;
3778 case GL_TEXTURE_EXTERNAL_OES:
3779 if (unit.bound_texture_external_oes != texture) {
3780 unit.bound_texture_external_oes = texture;
3781 changed = true;
3783 break;
3784 default:
3785 changed = true;
3786 break;
3788 // TODO(gman): See note #2 above.
3789 if (changed) {
3790 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(
3791 this, target, texture, &GLES2Implementation::BindTextureStub);
3795 void GLES2Implementation::BindTextureStub(GLenum target, GLuint texture) {
3796 helper_->BindTexture(target, texture);
3797 if (share_group_->bind_generates_resource())
3798 helper_->CommandBufferHelper::OrderingBarrier();
3801 void GLES2Implementation::BindTransformFeedbackHelper(
3802 GLenum target, GLuint transformfeedback) {
3803 helper_->BindTransformFeedback(target, transformfeedback);
3806 void GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
3807 bool changed = false;
3808 if (vertex_array_object_manager_->BindVertexArray(array, &changed)) {
3809 if (changed) {
3810 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
3811 // because unlike other resources VertexArrayObject ids must
3812 // be generated by GenVertexArrays. A random id to Bind will not
3813 // generate a new object.
3814 helper_->BindVertexArrayOES(array);
3816 } else {
3817 SetGLError(
3818 GL_INVALID_OPERATION, "glBindVertexArrayOES",
3819 "id was not generated with glGenVertexArrayOES");
3823 void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
3824 GLuint valuebuffer) {
3825 bool changed = false;
3826 switch (target) {
3827 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
3828 if (bound_valuebuffer_ != valuebuffer) {
3829 bound_valuebuffer_ = valuebuffer;
3830 changed = true;
3832 break;
3833 default:
3834 changed = true;
3835 break;
3837 // TODO(gman): See note #2 above.
3838 if (changed) {
3839 GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(
3840 this, target, valuebuffer,
3841 &GLES2Implementation::BindValuebufferCHROMIUMStub);
3845 void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target,
3846 GLuint valuebuffer) {
3847 helper_->BindValuebufferCHROMIUM(target, valuebuffer);
3848 if (share_group_->bind_generates_resource())
3849 helper_->CommandBufferHelper::OrderingBarrier();
3852 void GLES2Implementation::UseProgramHelper(GLuint program) {
3853 if (current_program_ != program) {
3854 current_program_ = program;
3855 helper_->UseProgram(program);
3859 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
3860 return vertex_array_object_manager_->IsReservedId(id);
3863 void GLES2Implementation::DeleteBuffersHelper(
3864 GLsizei n, const GLuint* buffers) {
3865 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
3866 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
3867 SetGLError(
3868 GL_INVALID_VALUE,
3869 "glDeleteBuffers", "id not created by this context.");
3870 return;
3872 for (GLsizei ii = 0; ii < n; ++ii) {
3873 if (buffers[ii] == bound_array_buffer_) {
3874 bound_array_buffer_ = 0;
3876 if (buffers[ii] == bound_copy_read_buffer_) {
3877 bound_copy_read_buffer_ = 0;
3879 if (buffers[ii] == bound_copy_write_buffer_) {
3880 bound_copy_write_buffer_ = 0;
3882 if (buffers[ii] == bound_pixel_pack_buffer_) {
3883 bound_pixel_pack_buffer_ = 0;
3885 if (buffers[ii] == bound_pixel_unpack_buffer_) {
3886 bound_pixel_unpack_buffer_ = 0;
3888 if (buffers[ii] == bound_transform_feedback_buffer_) {
3889 bound_transform_feedback_buffer_ = 0;
3891 if (buffers[ii] == bound_uniform_buffer_) {
3892 bound_uniform_buffer_ = 0;
3894 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
3896 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
3897 if (buffer)
3898 RemoveTransferBuffer(buffer);
3900 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
3901 bound_pixel_unpack_transfer_buffer_id_ = 0;
3904 RemoveMappedBufferRangeById(buffers[ii]);
3908 void GLES2Implementation::DeleteBuffersStub(
3909 GLsizei n, const GLuint* buffers) {
3910 helper_->DeleteBuffersImmediate(n, buffers);
3914 void GLES2Implementation::DeleteFramebuffersHelper(
3915 GLsizei n, const GLuint* framebuffers) {
3916 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
3917 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
3918 SetGLError(
3919 GL_INVALID_VALUE,
3920 "glDeleteFramebuffers", "id not created by this context.");
3921 return;
3923 for (GLsizei ii = 0; ii < n; ++ii) {
3924 if (framebuffers[ii] == bound_framebuffer_) {
3925 bound_framebuffer_ = 0;
3927 if (framebuffers[ii] == bound_read_framebuffer_) {
3928 bound_read_framebuffer_ = 0;
3933 void GLES2Implementation::DeleteFramebuffersStub(
3934 GLsizei n, const GLuint* framebuffers) {
3935 helper_->DeleteFramebuffersImmediate(n, framebuffers);
3938 void GLES2Implementation::DeleteRenderbuffersHelper(
3939 GLsizei n, const GLuint* renderbuffers) {
3940 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
3941 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
3942 SetGLError(
3943 GL_INVALID_VALUE,
3944 "glDeleteRenderbuffers", "id not created by this context.");
3945 return;
3947 for (GLsizei ii = 0; ii < n; ++ii) {
3948 if (renderbuffers[ii] == bound_renderbuffer_) {
3949 bound_renderbuffer_ = 0;
3954 void GLES2Implementation::DeleteRenderbuffersStub(
3955 GLsizei n, const GLuint* renderbuffers) {
3956 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
3959 void GLES2Implementation::DeleteTexturesHelper(
3960 GLsizei n, const GLuint* textures) {
3961 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
3962 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
3963 SetGLError(
3964 GL_INVALID_VALUE,
3965 "glDeleteTextures", "id not created by this context.");
3966 return;
3968 for (GLsizei ii = 0; ii < n; ++ii) {
3969 for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
3970 ++tt) {
3971 TextureUnit& unit = texture_units_[tt];
3972 if (textures[ii] == unit.bound_texture_2d) {
3973 unit.bound_texture_2d = 0;
3975 if (textures[ii] == unit.bound_texture_cube_map) {
3976 unit.bound_texture_cube_map = 0;
3978 if (textures[ii] == unit.bound_texture_external_oes) {
3979 unit.bound_texture_external_oes = 0;
3985 void GLES2Implementation::DeleteTexturesStub(GLsizei n,
3986 const GLuint* textures) {
3987 helper_->DeleteTexturesImmediate(n, textures);
3990 void GLES2Implementation::DeleteVertexArraysOESHelper(
3991 GLsizei n, const GLuint* arrays) {
3992 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
3993 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
3994 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
3995 SetGLError(
3996 GL_INVALID_VALUE,
3997 "glDeleteVertexArraysOES", "id not created by this context.");
3998 return;
4002 void GLES2Implementation::DeleteVertexArraysOESStub(
4003 GLsizei n, const GLuint* arrays) {
4004 helper_->DeleteVertexArraysOESImmediate(n, arrays);
4007 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
4008 GLsizei n,
4009 const GLuint* valuebuffers) {
4010 if (!GetIdHandler(id_namespaces::kValuebuffers)
4011 ->FreeIds(this, n, valuebuffers,
4012 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
4013 SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
4014 "id not created by this context.");
4015 return;
4017 for (GLsizei ii = 0; ii < n; ++ii) {
4018 if (valuebuffers[ii] == bound_valuebuffer_) {
4019 bound_valuebuffer_ = 0;
4024 void GLES2Implementation::DeleteSamplersStub(
4025 GLsizei n, const GLuint* samplers) {
4026 helper_->DeleteSamplersImmediate(n, samplers);
4029 void GLES2Implementation::DeleteSamplersHelper(
4030 GLsizei n, const GLuint* samplers) {
4031 if (!GetIdHandler(id_namespaces::kSamplers)->FreeIds(
4032 this, n, samplers, &GLES2Implementation::DeleteSamplersStub)) {
4033 SetGLError(
4034 GL_INVALID_VALUE,
4035 "glDeleteSamplers", "id not created by this context.");
4036 return;
4040 void GLES2Implementation::DeleteTransformFeedbacksStub(
4041 GLsizei n, const GLuint* transformfeedbacks) {
4042 helper_->DeleteTransformFeedbacksImmediate(n, transformfeedbacks);
4045 void GLES2Implementation::DeleteTransformFeedbacksHelper(
4046 GLsizei n, const GLuint* transformfeedbacks) {
4047 if (!GetIdHandler(id_namespaces::kTransformFeedbacks)->FreeIds(
4048 this, n, transformfeedbacks,
4049 &GLES2Implementation::DeleteTransformFeedbacksStub)) {
4050 SetGLError(
4051 GL_INVALID_VALUE,
4052 "glDeleteTransformFeedbacks", "id not created by this context.");
4053 return;
4057 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
4058 GLsizei n,
4059 const GLuint* valuebuffers) {
4060 helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
4063 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
4064 GPU_CLIENT_SINGLE_THREAD_CHECK();
4065 GPU_CLIENT_LOG(
4066 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
4067 vertex_array_object_manager_->SetAttribEnable(index, false);
4068 helper_->DisableVertexAttribArray(index);
4069 CheckGLError();
4072 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
4073 GPU_CLIENT_SINGLE_THREAD_CHECK();
4074 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
4075 << index << ")");
4076 vertex_array_object_manager_->SetAttribEnable(index, true);
4077 helper_->EnableVertexAttribArray(index);
4078 CheckGLError();
4081 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
4082 GPU_CLIENT_SINGLE_THREAD_CHECK();
4083 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
4084 << GLES2Util::GetStringDrawMode(mode) << ", "
4085 << first << ", " << count << ")");
4086 if (count < 0) {
4087 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
4088 return;
4090 bool simulated = false;
4091 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
4092 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
4093 return;
4095 helper_->DrawArrays(mode, first, count);
4096 RestoreArrayBuffer(simulated);
4097 CheckGLError();
4100 void GLES2Implementation::GetVertexAttribfv(
4101 GLuint index, GLenum pname, GLfloat* params) {
4102 GPU_CLIENT_SINGLE_THREAD_CHECK();
4103 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
4104 << index << ", "
4105 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4106 << static_cast<const void*>(params) << ")");
4107 uint32 value = 0;
4108 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4109 *params = static_cast<GLfloat>(value);
4110 return;
4112 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
4113 typedef cmds::GetVertexAttribfv::Result Result;
4114 Result* result = GetResultAs<Result*>();
4115 if (!result) {
4116 return;
4118 result->SetNumResults(0);
4119 helper_->GetVertexAttribfv(
4120 index, pname, GetResultShmId(), GetResultShmOffset());
4121 WaitForCmd();
4122 result->CopyResult(params);
4123 GPU_CLIENT_LOG_CODE_BLOCK({
4124 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4125 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4128 CheckGLError();
4131 void GLES2Implementation::GetVertexAttribiv(
4132 GLuint index, GLenum pname, GLint* params) {
4133 GPU_CLIENT_SINGLE_THREAD_CHECK();
4134 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
4135 << index << ", "
4136 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4137 << static_cast<const void*>(params) << ")");
4138 uint32 value = 0;
4139 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4140 *params = static_cast<GLint>(value);
4141 return;
4143 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
4144 typedef cmds::GetVertexAttribiv::Result Result;
4145 Result* result = GetResultAs<Result*>();
4146 if (!result) {
4147 return;
4149 result->SetNumResults(0);
4150 helper_->GetVertexAttribiv(
4151 index, pname, GetResultShmId(), GetResultShmOffset());
4152 WaitForCmd();
4153 result->CopyResult(params);
4154 GPU_CLIENT_LOG_CODE_BLOCK({
4155 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4156 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4159 CheckGLError();
4162 void GLES2Implementation::GetVertexAttribIiv(
4163 GLuint index, GLenum pname, GLint* params) {
4164 GPU_CLIENT_SINGLE_THREAD_CHECK();
4165 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIiv("
4166 << index << ", "
4167 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4168 << static_cast<const void*>(params) << ")");
4169 uint32 value = 0;
4170 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4171 *params = static_cast<GLint>(value);
4172 return;
4174 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIiv");
4175 typedef cmds::GetVertexAttribiv::Result Result;
4176 Result* result = GetResultAs<Result*>();
4177 if (!result) {
4178 return;
4180 result->SetNumResults(0);
4181 helper_->GetVertexAttribIiv(
4182 index, pname, GetResultShmId(), GetResultShmOffset());
4183 WaitForCmd();
4184 result->CopyResult(params);
4185 GPU_CLIENT_LOG_CODE_BLOCK({
4186 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4187 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4190 CheckGLError();
4193 void GLES2Implementation::GetVertexAttribIuiv(
4194 GLuint index, GLenum pname, GLuint* params) {
4195 GPU_CLIENT_SINGLE_THREAD_CHECK();
4196 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIuiv("
4197 << index << ", "
4198 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4199 << static_cast<const void*>(params) << ")");
4200 uint32 value = 0;
4201 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4202 *params = static_cast<GLuint>(value);
4203 return;
4205 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIuiv");
4206 typedef cmds::GetVertexAttribiv::Result Result;
4207 Result* result = GetResultAs<Result*>();
4208 if (!result) {
4209 return;
4211 result->SetNumResults(0);
4212 helper_->GetVertexAttribIuiv(
4213 index, pname, GetResultShmId(), GetResultShmOffset());
4214 WaitForCmd();
4215 result->CopyResult(params);
4216 GPU_CLIENT_LOG_CODE_BLOCK({
4217 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4218 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4221 CheckGLError();
4224 GLenum GLES2Implementation::GetGraphicsResetStatusKHR() {
4225 GPU_CLIENT_SINGLE_THREAD_CHECK();
4226 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetGraphicsResetStatusKHR()");
4227 // If we can't make command buffers then the context is lost.
4228 if (gpu_control_->IsGpuChannelLost())
4229 return GL_UNKNOWN_CONTEXT_RESET_KHR;
4230 // Otherwise, check the command buffer if it is lost.
4231 if (helper_->IsContextLost()) {
4232 // TODO(danakj): We could GetLastState() off the CommandBuffer and return
4233 // the actual reason here if we cared to.
4234 return GL_UNKNOWN_CONTEXT_RESET_KHR;
4236 return GL_NO_ERROR;
4239 void GLES2Implementation::Swap() {
4240 SwapBuffers();
4243 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
4244 PostSubBufferCHROMIUM(
4245 sub_buffer.x(), sub_buffer.y(), sub_buffer.width(), sub_buffer.height());
4248 static GLenum GetGLESOverlayTransform(gfx::OverlayTransform plane_transform) {
4249 switch (plane_transform) {
4250 case gfx::OVERLAY_TRANSFORM_INVALID:
4251 break;
4252 case gfx::OVERLAY_TRANSFORM_NONE:
4253 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
4254 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
4255 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM;
4256 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
4257 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM;
4258 case gfx::OVERLAY_TRANSFORM_ROTATE_90:
4259 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM;
4260 case gfx::OVERLAY_TRANSFORM_ROTATE_180:
4261 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM;
4262 case gfx::OVERLAY_TRANSFORM_ROTATE_270:
4263 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM;
4265 NOTREACHED();
4266 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
4269 void GLES2Implementation::ScheduleOverlayPlane(
4270 int plane_z_order,
4271 gfx::OverlayTransform plane_transform,
4272 unsigned overlay_texture_id,
4273 const gfx::Rect& display_bounds,
4274 const gfx::RectF& uv_rect) {
4275 ScheduleOverlayPlaneCHROMIUM(plane_z_order,
4276 GetGLESOverlayTransform(plane_transform),
4277 overlay_texture_id,
4278 display_bounds.x(),
4279 display_bounds.y(),
4280 display_bounds.width(),
4281 display_bounds.height(),
4282 uv_rect.x(),
4283 uv_rect.y(),
4284 uv_rect.width(),
4285 uv_rect.height());
4288 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
4289 const char* feature) {
4290 GPU_CLIENT_SINGLE_THREAD_CHECK();
4291 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
4292 << feature << ")");
4293 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
4294 typedef cmds::EnableFeatureCHROMIUM::Result Result;
4295 Result* result = GetResultAs<Result*>();
4296 if (!result) {
4297 return false;
4299 *result = 0;
4300 SetBucketAsCString(kResultBucketId, feature);
4301 helper_->EnableFeatureCHROMIUM(
4302 kResultBucketId, GetResultShmId(), GetResultShmOffset());
4303 WaitForCmd();
4304 helper_->SetBucketSize(kResultBucketId, 0);
4305 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
4306 return *result != 0;
4309 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
4310 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
4311 GPU_CLIENT_SINGLE_THREAD_CHECK();
4312 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
4313 << target << ", " << offset << ", " << size << ", "
4314 << GLES2Util::GetStringEnum(access) << ")");
4315 // NOTE: target is NOT checked because the service will check it
4316 // and we don't know what targets are valid.
4317 if (access != GL_WRITE_ONLY) {
4318 SetGLErrorInvalidEnum(
4319 "glMapBufferSubDataCHROMIUM", access, "access");
4320 return NULL;
4322 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
4323 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
4324 return NULL;
4327 int32 shm_id;
4328 unsigned int shm_offset;
4329 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4330 if (!mem) {
4331 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
4332 return NULL;
4335 std::pair<MappedBufferMap::iterator, bool> result =
4336 mapped_buffers_.insert(std::make_pair(
4337 mem,
4338 MappedBuffer(
4339 access, shm_id, mem, shm_offset, target, offset, size)));
4340 DCHECK(result.second);
4341 GPU_CLIENT_LOG(" returned " << mem);
4342 return mem;
4345 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
4346 GPU_CLIENT_SINGLE_THREAD_CHECK();
4347 GPU_CLIENT_LOG(
4348 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
4349 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
4350 if (it == mapped_buffers_.end()) {
4351 SetGLError(
4352 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
4353 return;
4355 const MappedBuffer& mb = it->second;
4356 helper_->BufferSubData(
4357 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
4358 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
4359 mapped_buffers_.erase(it);
4360 CheckGLError();
4363 GLuint GLES2Implementation::GetBoundBufferHelper(GLenum target) {
4364 GLenum binding = GLES2Util::MapBufferTargetToBindingEnum(target);
4365 GLint id = 0;
4366 bool cached = GetHelper(binding, &id);
4367 DCHECK(cached);
4368 return static_cast<GLuint>(id);
4371 void GLES2Implementation::RemoveMappedBufferRangeByTarget(GLenum target) {
4372 GLuint buffer = GetBoundBufferHelper(target);
4373 RemoveMappedBufferRangeById(buffer);
4376 void GLES2Implementation::RemoveMappedBufferRangeById(GLuint buffer) {
4377 if (buffer > 0) {
4378 auto iter = mapped_buffer_range_map_.find(buffer);
4379 if (iter != mapped_buffer_range_map_.end() && iter->second.shm_memory) {
4380 mapped_memory_->FreePendingToken(
4381 iter->second.shm_memory, helper_->InsertToken());
4382 mapped_buffer_range_map_.erase(iter);
4387 void GLES2Implementation::ClearMappedBufferRangeMap() {
4388 for (auto& buffer_range : mapped_buffer_range_map_) {
4389 if (buffer_range.second.shm_memory) {
4390 mapped_memory_->FreePendingToken(
4391 buffer_range.second.shm_memory, helper_->InsertToken());
4394 mapped_buffer_range_map_.clear();
4397 void* GLES2Implementation::MapBufferRange(
4398 GLenum target, GLintptr offset, GLsizeiptr size, GLbitfield access) {
4399 GPU_CLIENT_SINGLE_THREAD_CHECK();
4400 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferRange("
4401 << GLES2Util::GetStringEnum(target) << ", " << offset << ", "
4402 << size << ", " << access << ")");
4403 if (!ValidateSize("glMapBufferRange", size) ||
4404 !ValidateOffset("glMapBufferRange", offset)) {
4405 return nullptr;
4408 int32 shm_id;
4409 unsigned int shm_offset;
4410 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4411 if (!mem) {
4412 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferRange", "out of memory");
4413 return nullptr;
4416 typedef cmds::MapBufferRange::Result Result;
4417 Result* result = GetResultAs<Result*>();
4418 *result = 0;
4419 helper_->MapBufferRange(target, offset, size, access, shm_id, shm_offset,
4420 GetResultShmId(), GetResultShmOffset());
4421 // TODO(zmo): For write only mode with MAP_INVALID_*_BIT, we should
4422 // consider an early return without WaitForCmd(). crbug.com/465804.
4423 WaitForCmd();
4424 if (*result) {
4425 const GLbitfield kInvalidateBits =
4426 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
4427 if ((access & kInvalidateBits) != 0) {
4428 // We do not read back from the buffer, therefore, we set the client
4429 // side memory to zero to avoid uninitialized data.
4430 memset(mem, 0, size);
4432 GLuint buffer = GetBoundBufferHelper(target);
4433 DCHECK_NE(0u, buffer);
4434 // glMapBufferRange fails on an already mapped buffer.
4435 DCHECK(mapped_buffer_range_map_.find(buffer) ==
4436 mapped_buffer_range_map_.end());
4437 auto iter = mapped_buffer_range_map_.insert(std::make_pair(
4438 buffer,
4439 MappedBuffer(access, shm_id, mem, shm_offset, target, offset, size)));
4440 DCHECK(iter.second);
4441 } else {
4442 mapped_memory_->Free(mem);
4443 mem = nullptr;
4446 GPU_CLIENT_LOG(" returned " << mem);
4447 CheckGLError();
4448 return mem;
4451 GLboolean GLES2Implementation::UnmapBuffer(GLenum target) {
4452 GPU_CLIENT_SINGLE_THREAD_CHECK();
4453 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapBuffer("
4454 << GLES2Util::GetStringEnum(target) << ")");
4455 switch (target) {
4456 case GL_ARRAY_BUFFER:
4457 case GL_ELEMENT_ARRAY_BUFFER:
4458 case GL_COPY_READ_BUFFER:
4459 case GL_COPY_WRITE_BUFFER:
4460 case GL_PIXEL_PACK_BUFFER:
4461 case GL_PIXEL_UNPACK_BUFFER:
4462 case GL_TRANSFORM_FEEDBACK_BUFFER:
4463 case GL_UNIFORM_BUFFER:
4464 break;
4465 default:
4466 SetGLError(GL_INVALID_ENUM, "glUnmapBuffer", "invalid target");
4467 return GL_FALSE;
4469 GLuint buffer = GetBoundBufferHelper(target);
4470 if (buffer == 0) {
4471 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "no buffer bound");
4472 return GL_FALSE;
4474 auto iter = mapped_buffer_range_map_.find(buffer);
4475 if (iter == mapped_buffer_range_map_.end()) {
4476 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "buffer is unmapped");
4477 return GL_FALSE;
4480 helper_->UnmapBuffer(target);
4481 RemoveMappedBufferRangeById(buffer);
4482 // TODO(zmo): There is a rare situation that data might be corrupted and
4483 // GL_FALSE should be returned. We lose context on that sitatuon, so we
4484 // don't have to WaitForCmd().
4485 GPU_CLIENT_LOG(" returned " << GL_TRUE);
4486 CheckGLError();
4487 return GL_TRUE;
4490 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
4491 GLenum target,
4492 GLint level,
4493 GLint xoffset,
4494 GLint yoffset,
4495 GLsizei width,
4496 GLsizei height,
4497 GLenum format,
4498 GLenum type,
4499 GLenum access) {
4500 GPU_CLIENT_SINGLE_THREAD_CHECK();
4501 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
4502 << target << ", " << level << ", "
4503 << xoffset << ", " << yoffset << ", "
4504 << width << ", " << height << ", "
4505 << GLES2Util::GetStringTextureFormat(format) << ", "
4506 << GLES2Util::GetStringPixelType(type) << ", "
4507 << GLES2Util::GetStringEnum(access) << ")");
4508 if (access != GL_WRITE_ONLY) {
4509 SetGLErrorInvalidEnum(
4510 "glMapTexSubImage2DCHROMIUM", access, "access");
4511 return NULL;
4513 // NOTE: target is NOT checked because the service will check it
4514 // and we don't know what targets are valid.
4515 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
4516 SetGLError(
4517 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
4518 return NULL;
4520 uint32 size;
4521 if (!GLES2Util::ComputeImageDataSizes(
4522 width, height, 1, format, type, unpack_alignment_, &size, NULL, NULL)) {
4523 SetGLError(
4524 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
4525 return NULL;
4527 int32 shm_id;
4528 unsigned int shm_offset;
4529 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4530 if (!mem) {
4531 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
4532 return NULL;
4535 std::pair<MappedTextureMap::iterator, bool> result =
4536 mapped_textures_.insert(std::make_pair(
4537 mem,
4538 MappedTexture(
4539 access, shm_id, mem, shm_offset,
4540 target, level, xoffset, yoffset, width, height, format, type)));
4541 DCHECK(result.second);
4542 GPU_CLIENT_LOG(" returned " << mem);
4543 return mem;
4546 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
4547 GPU_CLIENT_SINGLE_THREAD_CHECK();
4548 GPU_CLIENT_LOG(
4549 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
4550 MappedTextureMap::iterator it = mapped_textures_.find(mem);
4551 if (it == mapped_textures_.end()) {
4552 SetGLError(
4553 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
4554 return;
4556 const MappedTexture& mt = it->second;
4557 helper_->TexSubImage2D(
4558 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
4559 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
4560 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
4561 mapped_textures_.erase(it);
4562 CheckGLError();
4565 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
4566 float scale_factor) {
4567 GPU_CLIENT_SINGLE_THREAD_CHECK();
4568 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
4569 << width << ", " << height << ", " << scale_factor << ")");
4570 helper_->ResizeCHROMIUM(width, height, scale_factor);
4571 CheckGLError();
4574 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
4575 GPU_CLIENT_SINGLE_THREAD_CHECK();
4576 GPU_CLIENT_LOG("[" << GetLogPrefix()
4577 << "] glGetRequestableExtensionsCHROMIUM()");
4578 TRACE_EVENT0("gpu",
4579 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
4580 const char* result = NULL;
4581 // Clear the bucket so if the command fails nothing will be in it.
4582 helper_->SetBucketSize(kResultBucketId, 0);
4583 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
4584 std::string str;
4585 if (GetBucketAsString(kResultBucketId, &str)) {
4586 // The set of requestable extensions shrinks as we enable
4587 // them. Because we don't know when the client will stop referring
4588 // to a previous one it queries (see GetString) we need to cache
4589 // the unique results.
4590 std::set<std::string>::const_iterator sit =
4591 requestable_extensions_set_.find(str);
4592 if (sit != requestable_extensions_set_.end()) {
4593 result = sit->c_str();
4594 } else {
4595 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
4596 requestable_extensions_set_.insert(str);
4597 DCHECK(insert_result.second);
4598 result = insert_result.first->c_str();
4601 GPU_CLIENT_LOG(" returned " << result);
4602 return reinterpret_cast<const GLchar*>(result);
4605 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
4606 // with VirtualGL contexts.
4607 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
4608 GPU_CLIENT_SINGLE_THREAD_CHECK();
4609 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
4610 << extension << ")");
4611 SetBucketAsCString(kResultBucketId, extension);
4612 helper_->RequestExtensionCHROMIUM(kResultBucketId);
4613 helper_->SetBucketSize(kResultBucketId, 0);
4615 struct ExtensionCheck {
4616 const char* extension;
4617 ExtensionStatus* status;
4619 const ExtensionCheck checks[] = {
4621 "GL_ANGLE_pack_reverse_row_order",
4622 &angle_pack_reverse_row_order_status_,
4625 "GL_CHROMIUM_framebuffer_multisample",
4626 &chromium_framebuffer_multisample_,
4629 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
4630 for (size_t ii = 0; ii < kNumChecks; ++ii) {
4631 const ExtensionCheck& check = checks[ii];
4632 if (*check.status == kUnavailableExtensionStatus &&
4633 !strcmp(extension, check.extension)) {
4634 *check.status = kUnknownExtensionStatus;
4639 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
4640 GPU_CLIENT_SINGLE_THREAD_CHECK();
4641 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
4642 // Wait if this would add too many rate limit tokens.
4643 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
4644 helper_->WaitForToken(rate_limit_tokens_.front());
4645 rate_limit_tokens_.pop();
4647 rate_limit_tokens_.push(helper_->InsertToken());
4650 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
4651 GLuint program, std::vector<int8>* result) {
4652 DCHECK(result);
4653 // Clear the bucket so if the command fails nothing will be in it.
4654 helper_->SetBucketSize(kResultBucketId, 0);
4655 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
4656 GetBucketContents(kResultBucketId, result);
4659 void GLES2Implementation::GetProgramInfoCHROMIUM(
4660 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4661 GPU_CLIENT_SINGLE_THREAD_CHECK();
4662 if (bufsize < 0) {
4663 SetGLError(
4664 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
4665 return;
4667 if (size == NULL) {
4668 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
4669 return;
4671 // Make sure they've set size to 0 else the value will be undefined on
4672 // lost context.
4673 DCHECK_EQ(0, *size);
4674 std::vector<int8> result;
4675 GetProgramInfoCHROMIUMHelper(program, &result);
4676 if (result.empty()) {
4677 return;
4679 *size = result.size();
4680 if (!info) {
4681 return;
4683 if (static_cast<size_t>(bufsize) < result.size()) {
4684 SetGLError(GL_INVALID_OPERATION,
4685 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
4686 return;
4688 memcpy(info, &result[0], result.size());
4691 void GLES2Implementation::GetUniformBlocksCHROMIUMHelper(
4692 GLuint program, std::vector<int8>* result) {
4693 DCHECK(result);
4694 // Clear the bucket so if the command fails nothing will be in it.
4695 helper_->SetBucketSize(kResultBucketId, 0);
4696 helper_->GetUniformBlocksCHROMIUM(program, kResultBucketId);
4697 GetBucketContents(kResultBucketId, result);
4700 void GLES2Implementation::GetUniformBlocksCHROMIUM(
4701 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4702 GPU_CLIENT_SINGLE_THREAD_CHECK();
4703 if (bufsize < 0) {
4704 SetGLError(
4705 GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "bufsize less than 0.");
4706 return;
4708 if (size == NULL) {
4709 SetGLError(GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "size is null.");
4710 return;
4712 // Make sure they've set size to 0 else the value will be undefined on
4713 // lost context.
4714 DCHECK_EQ(0, *size);
4715 std::vector<int8> result;
4716 GetUniformBlocksCHROMIUMHelper(program, &result);
4717 if (result.empty()) {
4718 return;
4720 *size = result.size();
4721 if (!info) {
4722 return;
4724 if (static_cast<size_t>(bufsize) < result.size()) {
4725 SetGLError(GL_INVALID_OPERATION, "glGetUniformBlocksCHROMIUM",
4726 "bufsize is too small for result.");
4727 return;
4729 memcpy(info, &result[0], result.size());
4732 void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
4733 GLuint program, std::vector<int8>* result) {
4734 DCHECK(result);
4735 // Clear the bucket so if the command fails nothing will be in it.
4736 helper_->SetBucketSize(kResultBucketId, 0);
4737 helper_->GetUniformsES3CHROMIUM(program, kResultBucketId);
4738 GetBucketContents(kResultBucketId, result);
4741 void GLES2Implementation::GetUniformsES3CHROMIUM(
4742 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4743 GPU_CLIENT_SINGLE_THREAD_CHECK();
4744 if (bufsize < 0) {
4745 SetGLError(
4746 GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "bufsize less than 0.");
4747 return;
4749 if (size == NULL) {
4750 SetGLError(GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "size is null.");
4751 return;
4753 // Make sure they've set size to 0 else the value will be undefined on
4754 // lost context.
4755 DCHECK_EQ(0, *size);
4756 std::vector<int8> result;
4757 GetUniformsES3CHROMIUMHelper(program, &result);
4758 if (result.empty()) {
4759 return;
4761 *size = result.size();
4762 if (!info) {
4763 return;
4765 if (static_cast<size_t>(bufsize) < result.size()) {
4766 SetGLError(GL_INVALID_OPERATION,
4767 "glGetUniformsES3CHROMIUM", "bufsize is too small for result.");
4768 return;
4770 memcpy(info, &result[0], result.size());
4773 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
4774 GLuint program, std::vector<int8>* result) {
4775 DCHECK(result);
4776 // Clear the bucket so if the command fails nothing will be in it.
4777 helper_->SetBucketSize(kResultBucketId, 0);
4778 helper_->GetTransformFeedbackVaryingsCHROMIUM(program, kResultBucketId);
4779 GetBucketContents(kResultBucketId, result);
4782 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(
4783 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4784 GPU_CLIENT_SINGLE_THREAD_CHECK();
4785 if (bufsize < 0) {
4786 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4787 "bufsize less than 0.");
4788 return;
4790 if (size == NULL) {
4791 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4792 "size is null.");
4793 return;
4795 // Make sure they've set size to 0 else the value will be undefined on
4796 // lost context.
4797 DCHECK_EQ(0, *size);
4798 std::vector<int8> result;
4799 GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
4800 if (result.empty()) {
4801 return;
4803 *size = result.size();
4804 if (!info) {
4805 return;
4807 if (static_cast<size_t>(bufsize) < result.size()) {
4808 SetGLError(GL_INVALID_OPERATION, "glGetTransformFeedbackVaryingsCHROMIUM",
4809 "bufsize is too small for result.");
4810 return;
4812 memcpy(info, &result[0], result.size());
4815 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
4816 GPU_CLIENT_SINGLE_THREAD_CHECK();
4817 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
4818 << texture << ")");
4819 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
4820 helper_->CommandBufferHelper::Flush();
4821 return gpu_control_->CreateStreamTexture(texture);
4824 void GLES2Implementation::PostSubBufferCHROMIUM(
4825 GLint x, GLint y, GLint width, GLint height) {
4826 GPU_CLIENT_SINGLE_THREAD_CHECK();
4827 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
4828 << x << ", " << y << ", " << width << ", " << height << ")");
4829 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
4830 "width", width, "height", height);
4832 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
4833 swap_buffers_tokens_.push(helper_->InsertToken());
4834 helper_->PostSubBufferCHROMIUM(x, y, width, height);
4835 helper_->CommandBufferHelper::Flush();
4836 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
4837 helper_->WaitForToken(swap_buffers_tokens_.front());
4838 swap_buffers_tokens_.pop();
4842 void GLES2Implementation::DeleteQueriesEXTHelper(
4843 GLsizei n, const GLuint* queries) {
4844 for (GLsizei ii = 0; ii < n; ++ii) {
4845 query_tracker_->RemoveQuery(queries[ii]);
4846 query_id_allocator_->FreeID(queries[ii]);
4849 helper_->DeleteQueriesEXTImmediate(n, queries);
4852 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
4853 GPU_CLIENT_SINGLE_THREAD_CHECK();
4854 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
4856 // TODO(gman): To be spec compliant IDs from other contexts sharing
4857 // resources need to return true here even though you can't share
4858 // queries across contexts?
4859 return query_tracker_->GetQuery(id) != NULL;
4862 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
4863 GPU_CLIENT_SINGLE_THREAD_CHECK();
4864 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
4865 << GLES2Util::GetStringQueryTarget(target)
4866 << ", " << id << ")");
4868 switch (target) {
4869 case GL_COMMANDS_ISSUED_CHROMIUM:
4870 case GL_LATENCY_QUERY_CHROMIUM:
4871 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
4872 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
4873 case GL_GET_ERROR_QUERY_CHROMIUM:
4874 break;
4875 case GL_COMMANDS_COMPLETED_CHROMIUM:
4876 if (!capabilities_.sync_query) {
4877 SetGLError(
4878 GL_INVALID_OPERATION, "glBeginQueryEXT",
4879 "not enabled for commands completed queries");
4880 return;
4882 break;
4883 case GL_ANY_SAMPLES_PASSED:
4884 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
4885 if (!capabilities_.occlusion_query_boolean) {
4886 SetGLError(
4887 GL_INVALID_OPERATION, "glBeginQueryEXT",
4888 "not enabled for occlusion queries");
4889 return;
4891 break;
4892 case GL_TIME_ELAPSED_EXT:
4893 if (!capabilities_.timer_queries) {
4894 SetGLError(
4895 GL_INVALID_OPERATION, "glBeginQueryEXT",
4896 "not enabled for timing queries");
4897 return;
4899 break;
4900 default:
4901 SetGLError(
4902 GL_INVALID_ENUM, "glBeginQueryEXT", "unknown query target");
4903 return;
4906 // if any outstanding queries INV_OP
4907 if (query_tracker_->GetCurrentQuery(target)) {
4908 SetGLError(
4909 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
4910 return;
4913 if (id == 0) {
4914 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
4915 return;
4918 if (!query_id_allocator_->InUse(id)) {
4919 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "invalid id");
4920 return;
4923 // Extra setups some targets might need.
4924 switch (target) {
4925 case GL_TIME_ELAPSED_EXT:
4926 if (!query_tracker_->SetDisjointSync(this)) {
4927 SetGLError(GL_OUT_OF_MEMORY,
4928 "glBeginQueryEXT",
4929 "buffer allocation failed");
4930 return;
4932 break;
4933 default:
4934 break;
4937 if (query_tracker_->BeginQuery(id, target, this))
4938 CheckGLError();
4941 void GLES2Implementation::EndQueryEXT(GLenum target) {
4942 GPU_CLIENT_SINGLE_THREAD_CHECK();
4943 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
4944 << GLES2Util::GetStringQueryTarget(target) << ")");
4945 // Don't do anything if the context is lost.
4946 if (helper_->IsContextLost()) {
4947 return;
4950 if (query_tracker_->EndQuery(target, this))
4951 CheckGLError();
4954 void GLES2Implementation::QueryCounterEXT(GLuint id, GLenum target) {
4955 GPU_CLIENT_SINGLE_THREAD_CHECK();
4956 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] QueryCounterEXT("
4957 << id
4958 << ", " << GLES2Util::GetStringQueryTarget(target) << ")");
4960 switch (target) {
4961 case GL_TIMESTAMP_EXT:
4962 if (!capabilities_.timer_queries) {
4963 SetGLError(
4964 GL_INVALID_OPERATION, "glQueryCounterEXT",
4965 "not enabled for timing queries");
4966 return;
4968 break;
4969 default:
4970 SetGLError(
4971 GL_INVALID_ENUM, "glQueryCounterEXT", "unknown query target");
4972 return;
4975 if (id == 0) {
4976 SetGLError(GL_INVALID_OPERATION, "glQueryCounterEXT", "id is 0");
4977 return;
4980 if (!query_id_allocator_->InUse(id)) {
4981 SetGLError(GL_INVALID_OPERATION, "glQueryCounterEXT", "invalid id");
4982 return;
4985 // Extra setups some targets might need.
4986 switch (target) {
4987 case GL_TIMESTAMP_EXT:
4988 if (!query_tracker_->SetDisjointSync(this)) {
4989 SetGLError(GL_OUT_OF_MEMORY,
4990 "glQueryCounterEXT",
4991 "buffer allocation failed");
4992 return;
4994 break;
4995 default:
4996 break;
4999 if (query_tracker_->QueryCounter(id, target, this))
5000 CheckGLError();
5003 void GLES2Implementation::GetQueryivEXT(
5004 GLenum target, GLenum pname, GLint* params) {
5005 GPU_CLIENT_SINGLE_THREAD_CHECK();
5006 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
5007 << GLES2Util::GetStringQueryTarget(target) << ", "
5008 << GLES2Util::GetStringQueryParameter(pname) << ", "
5009 << static_cast<const void*>(params) << ")");
5010 if (pname == GL_QUERY_COUNTER_BITS_EXT) {
5011 // We convert all queries to CPU time so we support 64 bits.
5012 *params = 64;
5013 return;
5014 } else if (pname != GL_CURRENT_QUERY_EXT) {
5015 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
5016 return;
5018 QueryTracker::Query* query = query_tracker_->GetCurrentQuery(target);
5019 *params = query ? query->id() : 0;
5020 GPU_CLIENT_LOG(" " << *params);
5021 CheckGLError();
5024 void GLES2Implementation::GetQueryObjectivEXT(
5025 GLuint id, GLenum pname, GLint* params) {
5026 GLuint64 result = 0;
5027 if (GetQueryObjectValueHelper("glGetQueryObjectivEXT", id, pname, &result))
5028 *params = base::saturated_cast<GLint>(result);
5031 void GLES2Implementation::GetQueryObjectuivEXT(
5032 GLuint id, GLenum pname, GLuint* params) {
5033 GLuint64 result = 0;
5034 if (GetQueryObjectValueHelper("glGetQueryObjectuivEXT", id, pname, &result))
5035 *params = base::saturated_cast<GLuint>(result);
5038 void GLES2Implementation::GetQueryObjecti64vEXT(
5039 GLuint id, GLenum pname, GLint64* params) {
5040 GLuint64 result = 0;
5041 if (GetQueryObjectValueHelper("glGetQueryObjectiv64vEXT", id, pname, &result))
5042 *params = base::saturated_cast<GLint64>(result);
5045 void GLES2Implementation::GetQueryObjectui64vEXT(
5046 GLuint id, GLenum pname, GLuint64* params) {
5047 GLuint64 result = 0;
5048 if (GetQueryObjectValueHelper("glGetQueryObjectui64vEXT", id, pname, &result))
5049 *params = result;
5052 void GLES2Implementation::SetDisjointValueSyncCHROMIUM() {
5053 query_tracker_->SetDisjointSync(this);
5056 void GLES2Implementation::DrawArraysInstancedANGLE(
5057 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
5058 GPU_CLIENT_SINGLE_THREAD_CHECK();
5059 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
5060 << GLES2Util::GetStringDrawMode(mode) << ", "
5061 << first << ", " << count << ", " << primcount << ")");
5062 if (count < 0) {
5063 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
5064 return;
5066 if (primcount < 0) {
5067 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
5068 return;
5070 if (primcount == 0) {
5071 return;
5073 bool simulated = false;
5074 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
5075 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
5076 &simulated)) {
5077 return;
5079 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
5080 RestoreArrayBuffer(simulated);
5081 CheckGLError();
5084 void GLES2Implementation::DrawElementsInstancedANGLE(
5085 GLenum mode, GLsizei count, GLenum type, const void* indices,
5086 GLsizei primcount) {
5087 GPU_CLIENT_SINGLE_THREAD_CHECK();
5088 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
5089 << GLES2Util::GetStringDrawMode(mode) << ", "
5090 << count << ", "
5091 << GLES2Util::GetStringIndexType(type) << ", "
5092 << static_cast<const void*>(indices) << ", "
5093 << primcount << ")");
5094 if (count < 0) {
5095 SetGLError(GL_INVALID_VALUE,
5096 "glDrawElementsInstancedANGLE", "count less than 0.");
5097 return;
5099 if (count == 0) {
5100 return;
5102 if (primcount < 0) {
5103 SetGLError(GL_INVALID_VALUE,
5104 "glDrawElementsInstancedANGLE", "primcount < 0");
5105 return;
5107 if (primcount == 0) {
5108 return;
5110 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
5111 !ValidateOffset("glDrawElementsInstancedANGLE",
5112 reinterpret_cast<GLintptr>(indices))) {
5113 return;
5115 GLuint offset = 0;
5116 bool simulated = false;
5117 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
5118 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
5119 indices, &offset, &simulated)) {
5120 return;
5122 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
5123 RestoreElementAndArrayBuffers(simulated);
5124 CheckGLError();
5127 void GLES2Implementation::GenMailboxCHROMIUM(
5128 GLbyte* mailbox) {
5129 GPU_CLIENT_SINGLE_THREAD_CHECK();
5130 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
5131 << static_cast<const void*>(mailbox) << ")");
5132 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
5134 gpu::Mailbox result = gpu::Mailbox::Generate();
5135 memcpy(mailbox, result.name, sizeof(result.name));
5138 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target,
5139 const GLbyte* data) {
5140 GPU_CLIENT_SINGLE_THREAD_CHECK();
5141 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
5142 << static_cast<const void*>(data) << ")");
5143 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5144 DCHECK(mailbox.Verify()) << "ProduceTextureCHROMIUM was passed a "
5145 "mailbox that was not generated by "
5146 "GenMailboxCHROMIUM.";
5147 helper_->ProduceTextureCHROMIUMImmediate(target, data);
5148 CheckGLError();
5151 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
5152 GLuint texture, GLenum target, const GLbyte* data) {
5153 GPU_CLIENT_SINGLE_THREAD_CHECK();
5154 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
5155 << static_cast<const void*>(data) << ")");
5156 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5157 DCHECK(mailbox.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
5158 "mailbox that was not generated by "
5159 "GenMailboxCHROMIUM.";
5160 helper_->ProduceTextureDirectCHROMIUMImmediate(texture, target, data);
5161 CheckGLError();
5164 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target,
5165 const GLbyte* data) {
5166 GPU_CLIENT_SINGLE_THREAD_CHECK();
5167 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
5168 << static_cast<const void*>(data) << ")");
5169 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5170 DCHECK(mailbox.Verify()) << "ConsumeTextureCHROMIUM was passed a "
5171 "mailbox that was not generated by "
5172 "GenMailboxCHROMIUM.";
5173 helper_->ConsumeTextureCHROMIUMImmediate(target, data);
5174 CheckGLError();
5177 GLuint GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
5178 GLenum target, const GLbyte* data) {
5179 GPU_CLIENT_SINGLE_THREAD_CHECK();
5180 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
5181 << static_cast<const void*>(data) << ")");
5182 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5183 DCHECK(mailbox.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
5184 "mailbox that was not generated by "
5185 "GenMailboxCHROMIUM.";
5186 GLuint client_id;
5187 GetIdHandler(id_namespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
5188 helper_->CreateAndConsumeTextureCHROMIUMImmediate(target,
5189 client_id, data);
5190 if (share_group_->bind_generates_resource())
5191 helper_->CommandBufferHelper::Flush();
5192 CheckGLError();
5193 return client_id;
5196 void GLES2Implementation::PushGroupMarkerEXT(
5197 GLsizei length, const GLchar* marker) {
5198 GPU_CLIENT_SINGLE_THREAD_CHECK();
5199 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
5200 << length << ", " << marker << ")");
5201 if (!marker) {
5202 marker = "";
5204 SetBucketAsString(
5205 kResultBucketId,
5206 (length ? std::string(marker, length) : std::string(marker)));
5207 helper_->PushGroupMarkerEXT(kResultBucketId);
5208 helper_->SetBucketSize(kResultBucketId, 0);
5209 debug_marker_manager_.PushGroup(
5210 length ? std::string(marker, length) : std::string(marker));
5213 void GLES2Implementation::InsertEventMarkerEXT(
5214 GLsizei length, const GLchar* marker) {
5215 GPU_CLIENT_SINGLE_THREAD_CHECK();
5216 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
5217 << length << ", " << marker << ")");
5218 if (!marker) {
5219 marker = "";
5221 SetBucketAsString(
5222 kResultBucketId,
5223 (length ? std::string(marker, length) : std::string(marker)));
5224 helper_->InsertEventMarkerEXT(kResultBucketId);
5225 helper_->SetBucketSize(kResultBucketId, 0);
5226 debug_marker_manager_.SetMarker(
5227 length ? std::string(marker, length) : std::string(marker));
5230 void GLES2Implementation::PopGroupMarkerEXT() {
5231 GPU_CLIENT_SINGLE_THREAD_CHECK();
5232 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
5233 helper_->PopGroupMarkerEXT();
5234 debug_marker_manager_.PopGroup();
5237 void GLES2Implementation::TraceBeginCHROMIUM(
5238 const char* category_name, const char* trace_name) {
5239 GPU_CLIENT_SINGLE_THREAD_CHECK();
5240 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
5241 << category_name << ", " << trace_name << ")");
5242 SetBucketAsCString(kResultBucketId, category_name);
5243 SetBucketAsCString(kResultBucketId + 1, trace_name);
5244 helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1);
5245 helper_->SetBucketSize(kResultBucketId, 0);
5246 helper_->SetBucketSize(kResultBucketId + 1, 0);
5247 current_trace_stack_++;
5250 void GLES2Implementation::TraceEndCHROMIUM() {
5251 GPU_CLIENT_SINGLE_THREAD_CHECK();
5252 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
5253 if (current_trace_stack_ == 0) {
5254 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
5255 "missing begin trace");
5256 return;
5258 helper_->TraceEndCHROMIUM();
5259 current_trace_stack_--;
5262 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
5263 GPU_CLIENT_SINGLE_THREAD_CHECK();
5264 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
5265 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
5266 switch (target) {
5267 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
5268 if (access != GL_READ_ONLY) {
5269 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
5270 return NULL;
5272 break;
5273 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
5274 if (access != GL_WRITE_ONLY) {
5275 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
5276 return NULL;
5278 break;
5279 default:
5280 SetGLError(
5281 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
5282 return NULL;
5284 GLuint buffer_id;
5285 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
5286 if (!buffer_id) {
5287 return NULL;
5289 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
5290 if (!buffer) {
5291 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
5292 return NULL;
5294 if (buffer->mapped()) {
5295 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
5296 return NULL;
5298 // Here we wait for previous transfer operations to be finished.
5299 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
5300 // with this method of synchronization. Until this is fixed,
5301 // MapBufferCHROMIUM will not block even if the transfer is not ready
5302 // for these calls.
5303 if (buffer->last_usage_token()) {
5304 helper_->WaitForToken(buffer->last_usage_token());
5305 buffer->set_last_usage_token(0);
5307 buffer->set_mapped(true);
5309 GPU_CLIENT_LOG(" returned " << buffer->address());
5310 CheckGLError();
5311 return buffer->address();
5314 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
5315 GPU_CLIENT_SINGLE_THREAD_CHECK();
5316 GPU_CLIENT_LOG(
5317 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
5318 GLuint buffer_id;
5319 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
5320 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
5322 if (!buffer_id) {
5323 return false;
5325 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
5326 if (!buffer) {
5327 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
5328 return false;
5330 if (!buffer->mapped()) {
5331 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
5332 return false;
5334 buffer->set_mapped(false);
5335 CheckGLError();
5336 return true;
5339 bool GLES2Implementation::EnsureAsyncUploadSync() {
5340 if (async_upload_sync_)
5341 return true;
5343 int32 shm_id;
5344 unsigned int shm_offset;
5345 void* mem = mapped_memory_->Alloc(sizeof(AsyncUploadSync),
5346 &shm_id,
5347 &shm_offset);
5348 if (!mem)
5349 return false;
5351 async_upload_sync_shm_id_ = shm_id;
5352 async_upload_sync_shm_offset_ = shm_offset;
5353 async_upload_sync_ = static_cast<AsyncUploadSync*>(mem);
5354 async_upload_sync_->Reset();
5356 return true;
5359 uint32 GLES2Implementation::NextAsyncUploadToken() {
5360 async_upload_token_++;
5361 if (async_upload_token_ == 0)
5362 async_upload_token_++;
5363 return async_upload_token_;
5366 void GLES2Implementation::PollAsyncUploads() {
5367 if (!async_upload_sync_)
5368 return;
5370 if (helper_->IsContextLost()) {
5371 DetachedAsyncUploadMemoryList::iterator it =
5372 detached_async_upload_memory_.begin();
5373 while (it != detached_async_upload_memory_.end()) {
5374 mapped_memory_->Free(it->first);
5375 it = detached_async_upload_memory_.erase(it);
5377 return;
5380 DetachedAsyncUploadMemoryList::iterator it =
5381 detached_async_upload_memory_.begin();
5382 while (it != detached_async_upload_memory_.end()) {
5383 if (HasAsyncUploadTokenPassed(it->second)) {
5384 mapped_memory_->Free(it->first);
5385 it = detached_async_upload_memory_.erase(it);
5386 } else {
5387 break;
5392 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
5393 // Free all completed unmanaged async uploads buffers.
5394 PollAsyncUploads();
5396 // Synchronously free rest of the unmanaged async upload buffers.
5397 if (!detached_async_upload_memory_.empty()) {
5398 WaitAllAsyncTexImage2DCHROMIUMHelper();
5399 WaitForCmd();
5400 PollAsyncUploads();
5404 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
5405 GLenum target, GLint level, GLenum internalformat, GLsizei width,
5406 GLsizei height, GLint border, GLenum format, GLenum type,
5407 const void* pixels) {
5408 GPU_CLIENT_SINGLE_THREAD_CHECK();
5409 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
5410 << GLES2Util::GetStringTextureTarget(target) << ", "
5411 << level << ", "
5412 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
5413 << width << ", " << height << ", " << border << ", "
5414 << GLES2Util::GetStringTextureFormat(format) << ", "
5415 << GLES2Util::GetStringPixelType(type) << ", "
5416 << static_cast<const void*>(pixels) << ")");
5417 if (level < 0 || height < 0 || width < 0) {
5418 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
5419 return;
5421 if (border != 0) {
5422 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
5423 return;
5425 uint32 size;
5426 uint32 unpadded_row_size;
5427 uint32 padded_row_size;
5428 if (!GLES2Util::ComputeImageDataSizes(
5429 width, height, 1, format, type, unpack_alignment_, &size,
5430 &unpadded_row_size, &padded_row_size)) {
5431 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
5432 return;
5435 // If there's no data/buffer just issue the AsyncTexImage2D
5436 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
5437 helper_->AsyncTexImage2DCHROMIUM(
5438 target, level, internalformat, width, height, format, type,
5439 0, 0, 0, 0, 0);
5440 return;
5443 if (!EnsureAsyncUploadSync()) {
5444 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
5445 return;
5448 // Otherwise, async uploads require a transfer buffer to be bound.
5449 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
5450 // the buffer before the transfer is finished. (Currently such
5451 // synchronization has to be handled manually.)
5452 GLuint offset = ToGLuint(pixels);
5453 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
5454 bound_pixel_unpack_transfer_buffer_id_,
5455 "glAsyncTexImage2DCHROMIUM", offset, size);
5456 if (buffer && buffer->shm_id() != -1) {
5457 uint32 async_token = NextAsyncUploadToken();
5458 buffer->set_last_async_upload_token(async_token);
5459 helper_->AsyncTexImage2DCHROMIUM(
5460 target, level, internalformat, width, height, format, type,
5461 buffer->shm_id(), buffer->shm_offset() + offset,
5462 async_token,
5463 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
5467 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
5468 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
5469 GLsizei height, GLenum format, GLenum type, const void* pixels) {
5470 GPU_CLIENT_SINGLE_THREAD_CHECK();
5471 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
5472 << GLES2Util::GetStringTextureTarget(target) << ", "
5473 << level << ", "
5474 << xoffset << ", " << yoffset << ", "
5475 << width << ", " << height << ", "
5476 << GLES2Util::GetStringTextureFormat(format) << ", "
5477 << GLES2Util::GetStringPixelType(type) << ", "
5478 << static_cast<const void*>(pixels) << ")");
5479 if (level < 0 || height < 0 || width < 0) {
5480 SetGLError(
5481 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
5482 return;
5485 uint32 size;
5486 uint32 unpadded_row_size;
5487 uint32 padded_row_size;
5488 if (!GLES2Util::ComputeImageDataSizes(
5489 width, height, 1, format, type, unpack_alignment_, &size,
5490 &unpadded_row_size, &padded_row_size)) {
5491 SetGLError(
5492 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
5493 return;
5496 if (!EnsureAsyncUploadSync()) {
5497 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
5498 return;
5501 // Async uploads require a transfer buffer to be bound.
5502 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
5503 // the buffer before the transfer is finished. (Currently such
5504 // synchronization has to be handled manually.)
5505 GLuint offset = ToGLuint(pixels);
5506 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
5507 bound_pixel_unpack_transfer_buffer_id_,
5508 "glAsyncTexSubImage2DCHROMIUM", offset, size);
5509 if (buffer && buffer->shm_id() != -1) {
5510 uint32 async_token = NextAsyncUploadToken();
5511 buffer->set_last_async_upload_token(async_token);
5512 helper_->AsyncTexSubImage2DCHROMIUM(
5513 target, level, xoffset, yoffset, width, height, format, type,
5514 buffer->shm_id(), buffer->shm_offset() + offset,
5515 async_token,
5516 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
5520 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
5521 GPU_CLIENT_SINGLE_THREAD_CHECK();
5522 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
5523 << GLES2Util::GetStringTextureTarget(target) << ")");
5524 helper_->WaitAsyncTexImage2DCHROMIUM(target);
5525 CheckGLError();
5528 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUMHelper() {
5529 helper_->WaitAllAsyncTexImage2DCHROMIUM();
5532 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
5533 GPU_CLIENT_SINGLE_THREAD_CHECK();
5534 GPU_CLIENT_LOG("[" << GetLogPrefix()
5535 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
5536 WaitAllAsyncTexImage2DCHROMIUMHelper();
5537 CheckGLError();
5540 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
5541 GPU_CLIENT_SINGLE_THREAD_CHECK();
5542 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
5543 helper_->CommandBufferHelper::Flush();
5544 return gpu_control_->InsertSyncPoint();
5547 GLuint GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
5548 GPU_CLIENT_SINGLE_THREAD_CHECK();
5549 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
5550 DCHECK(capabilities_.future_sync_points);
5551 return gpu_control_->InsertFutureSyncPoint();
5554 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point) {
5555 GPU_CLIENT_SINGLE_THREAD_CHECK();
5556 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
5557 << sync_point << ")");
5558 DCHECK(capabilities_.future_sync_points);
5559 helper_->CommandBufferHelper::Flush();
5560 gpu_control_->RetireSyncPoint(sync_point);
5563 namespace {
5565 bool ValidImageFormat(GLenum internalformat,
5566 const Capabilities& capabilities) {
5567 switch (internalformat) {
5568 case GL_ATC_RGB_AMD:
5569 case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
5570 return capabilities.texture_format_atc;
5571 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
5572 return capabilities.texture_format_dxt1;
5573 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
5574 return capabilities.texture_format_dxt5;
5575 case GL_ETC1_RGB8_OES:
5576 return capabilities.texture_format_etc1;
5577 case GL_R8:
5578 case GL_RGB:
5579 case GL_RGBA:
5580 case GL_BGRA_EXT:
5581 return true;
5582 default:
5583 return false;
5587 bool ValidImageUsage(GLenum usage) {
5588 switch (usage) {
5589 case GL_MAP_CHROMIUM:
5590 case GL_SCANOUT_CHROMIUM:
5591 return true;
5592 default:
5593 return false;
5597 } // namespace
5599 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer,
5600 GLsizei width,
5601 GLsizei height,
5602 GLenum internalformat) {
5603 if (width <= 0) {
5604 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
5605 return 0;
5608 if (height <= 0) {
5609 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
5610 return 0;
5613 if (!ValidImageFormat(internalformat, capabilities_)) {
5614 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "invalid format");
5615 return 0;
5618 int32_t image_id =
5619 gpu_control_->CreateImage(buffer, width, height, internalformat);
5620 if (image_id < 0) {
5621 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "image_id < 0");
5622 return 0;
5624 return image_id;
5627 GLuint GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer,
5628 GLsizei width,
5629 GLsizei height,
5630 GLenum internalformat) {
5631 GPU_CLIENT_SINGLE_THREAD_CHECK();
5632 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
5633 << ", " << height << ", "
5634 << GLES2Util::GetStringImageInternalFormat(internalformat)
5635 << ")");
5636 GLuint image_id =
5637 CreateImageCHROMIUMHelper(buffer, width, height, internalformat);
5638 CheckGLError();
5639 return image_id;
5642 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
5643 // Flush the command stream to make sure all pending commands
5644 // that may refer to the image_id are executed on the service side.
5645 helper_->CommandBufferHelper::Flush();
5646 gpu_control_->DestroyImage(image_id);
5649 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
5650 GPU_CLIENT_SINGLE_THREAD_CHECK();
5651 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
5652 << image_id << ")");
5653 DestroyImageCHROMIUMHelper(image_id);
5654 CheckGLError();
5657 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
5658 GLsizei width,
5659 GLsizei height,
5660 GLenum internalformat,
5661 GLenum usage) {
5662 if (width <= 0) {
5663 SetGLError(
5664 GL_INVALID_VALUE, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
5665 return 0;
5668 if (height <= 0) {
5669 SetGLError(GL_INVALID_VALUE,
5670 "glCreateGpuMemoryBufferImageCHROMIUM",
5671 "height <= 0");
5672 return 0;
5675 if (!ValidImageFormat(internalformat, capabilities_)) {
5676 SetGLError(GL_INVALID_VALUE,
5677 "glCreateGpuMemoryBufferImageCHROMIUM",
5678 "invalid format");
5679 return 0;
5682 if (!ValidImageUsage(usage)) {
5683 SetGLError(GL_INVALID_VALUE,
5684 "glCreateGpuMemoryBufferImageCHROMIUM",
5685 "invalid usage");
5686 return 0;
5689 // Flush the command stream to ensure ordering in case the newly
5690 // returned image_id has recently been in use with a different buffer.
5691 helper_->CommandBufferHelper::Flush();
5692 int32_t image_id = gpu_control_->CreateGpuMemoryBufferImage(
5693 width, height, internalformat, usage);
5694 if (image_id < 0) {
5695 SetGLError(GL_OUT_OF_MEMORY,
5696 "glCreateGpuMemoryBufferImageCHROMIUM",
5697 "image_id < 0");
5698 return 0;
5700 return image_id;
5703 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
5704 GLsizei width,
5705 GLsizei height,
5706 GLenum internalformat,
5707 GLenum usage) {
5708 GPU_CLIENT_SINGLE_THREAD_CHECK();
5709 GPU_CLIENT_LOG("[" << GetLogPrefix()
5710 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
5711 << ", " << height << ", "
5712 << GLES2Util::GetStringImageInternalFormat(internalformat)
5713 << ", " << GLES2Util::GetStringImageUsage(usage) << ")");
5714 GLuint image_id = CreateGpuMemoryBufferImageCHROMIUMHelper(
5715 width, height, internalformat, usage);
5716 CheckGLError();
5717 return image_id;
5720 bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
5721 if (size < 0) {
5722 SetGLError(GL_INVALID_VALUE, func, "size < 0");
5723 return false;
5725 if (!base::IsValueInRangeForNumericType<int32_t>(size)) {
5726 SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
5727 return false;
5729 return true;
5732 bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
5733 if (offset < 0) {
5734 SetGLError(GL_INVALID_VALUE, func, "offset < 0");
5735 return false;
5737 if (!base::IsValueInRangeForNumericType<int32_t>(offset)) {
5738 SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
5739 return false;
5741 return true;
5744 bool GLES2Implementation::GetSamplerParameterfvHelper(
5745 GLuint /* sampler */, GLenum /* pname */, GLfloat* /* params */) {
5746 // TODO(zmo): Implement client side caching.
5747 return false;
5750 bool GLES2Implementation::GetSamplerParameterivHelper(
5751 GLuint /* sampler */, GLenum /* pname */, GLint* /* params */) {
5752 // TODO(zmo): Implement client side caching.
5753 return false;
5756 bool GLES2Implementation::PackStringsToBucket(GLsizei count,
5757 const char* const* str,
5758 const GLint* length,
5759 const char* func_name) {
5760 DCHECK_LE(0, count);
5761 // Compute the total size.
5762 base::CheckedNumeric<size_t> total_size = count;
5763 total_size += 1;
5764 total_size *= sizeof(GLint);
5765 if (!total_size.IsValid()) {
5766 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5767 return false;
5769 size_t header_size = total_size.ValueOrDefault(0);
5770 std::vector<GLint> header(count + 1);
5771 header[0] = static_cast<GLint>(count);
5772 for (GLsizei ii = 0; ii < count; ++ii) {
5773 GLint len = 0;
5774 if (str[ii]) {
5775 len = (length && length[ii] >= 0)
5776 ? length[ii]
5777 : base::checked_cast<GLint>(strlen(str[ii]));
5779 total_size += len;
5780 total_size += 1; // NULL at the end of each char array.
5781 if (!total_size.IsValid()) {
5782 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5783 return false;
5785 header[ii + 1] = len;
5787 // Pack data into a bucket on the service.
5788 helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
5789 size_t offset = 0;
5790 for (GLsizei ii = 0; ii <= count; ++ii) {
5791 const char* src =
5792 (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
5793 base::CheckedNumeric<size_t> checked_size =
5794 (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
5795 if (ii > 0) {
5796 checked_size += 1; // NULL in the end.
5798 if (!checked_size.IsValid()) {
5799 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5800 return false;
5802 size_t size = checked_size.ValueOrDefault(0);
5803 while (size) {
5804 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
5805 if (!buffer.valid() || buffer.size() == 0) {
5806 SetGLError(GL_OUT_OF_MEMORY, func_name, "too large");
5807 return false;
5809 size_t copy_size = buffer.size();
5810 if (ii > 0 && buffer.size() == size)
5811 --copy_size;
5812 if (copy_size)
5813 memcpy(buffer.address(), src, copy_size);
5814 if (copy_size < buffer.size()) {
5815 // Append NULL in the end.
5816 DCHECK(copy_size + 1 == buffer.size());
5817 char* str = reinterpret_cast<char*>(buffer.address());
5818 str[copy_size] = 0;
5820 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
5821 buffer.shm_id(), buffer.offset());
5822 offset += buffer.size();
5823 src += buffer.size();
5824 size -= buffer.size();
5827 DCHECK_EQ(total_size.ValueOrDefault(0), offset);
5828 return true;
5831 void GLES2Implementation::UniformBlockBinding(GLuint program,
5832 GLuint index,
5833 GLuint binding) {
5834 GPU_CLIENT_SINGLE_THREAD_CHECK();
5835 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
5836 << ", " << index << ", " << binding << ")");
5837 share_group_->program_info_manager()->UniformBlockBinding(
5838 this, program, index, binding);
5839 helper_->UniformBlockBinding(program, index, binding);
5840 CheckGLError();
5843 GLenum GLES2Implementation::ClientWaitSync(
5844 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5845 GPU_CLIENT_SINGLE_THREAD_CHECK();
5846 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync
5847 << ", " << flags << ", " << timeout << ")");
5848 typedef cmds::ClientWaitSync::Result Result;
5849 Result* result = GetResultAs<Result*>();
5850 if (!result) {
5851 SetGLError(GL_OUT_OF_MEMORY, "ClientWaitSync", "");
5852 return GL_WAIT_FAILED;
5854 *result = GL_WAIT_FAILED;
5855 uint32_t v32_0 = 0, v32_1 = 0;
5856 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5857 helper_->ClientWaitSync(
5858 ToGLuint(sync), flags, v32_0, v32_1,
5859 GetResultShmId(), GetResultShmOffset());
5860 WaitForCmd();
5861 GPU_CLIENT_LOG("returned " << *result);
5862 CheckGLError();
5863 return *result;
5866 void GLES2Implementation::WaitSync(
5867 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5868 GPU_CLIENT_SINGLE_THREAD_CHECK();
5869 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync << ", "
5870 << flags << ", " << timeout << ")");
5871 uint32_t v32_0 = 0, v32_1 = 0;
5872 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5873 helper_->WaitSync(ToGLuint(sync), flags, v32_0, v32_1);
5874 CheckGLError();
5877 void GLES2Implementation::GetInternalformativ(
5878 GLenum target, GLenum format, GLenum pname,
5879 GLsizei buf_size, GLint* params) {
5880 GPU_CLIENT_SINGLE_THREAD_CHECK();
5881 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
5882 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetInternalformativ("
5883 << GLES2Util::GetStringRenderBufferTarget(target) << ", "
5884 << GLES2Util::GetStringRenderBufferFormat(format) << ", "
5885 << GLES2Util::GetStringInternalFormatParameter(pname)
5886 << ", " << buf_size << ", "
5887 << static_cast<const void*>(params) << ")");
5888 if (buf_size < 0) {
5889 SetGLError(GL_INVALID_VALUE, "glGetInternalformativ", "bufSize < 0");
5890 return;
5892 TRACE_EVENT0("gpu", "GLES2Implementation::GetInternalformativ");
5893 if (GetInternalformativHelper(target, format, pname, buf_size, params)) {
5894 return;
5896 typedef cmds::GetInternalformativ::Result Result;
5897 Result* result = GetResultAs<Result*>();
5898 if (!result) {
5899 return;
5901 result->SetNumResults(0);
5902 helper_->GetInternalformativ(target, format, pname,
5903 GetResultShmId(), GetResultShmOffset());
5904 WaitForCmd();
5905 GPU_CLIENT_LOG_CODE_BLOCK({
5906 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
5907 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
5910 if (buf_size > 0 && params) {
5911 GLint* data = result->GetData();
5912 if (buf_size >= result->GetNumResults()) {
5913 buf_size = result->GetNumResults();
5915 for (GLsizei ii = 0; ii < buf_size; ++ii) {
5916 params[ii] = data[ii];
5919 CheckGLError();
5922 GLuint GLES2Implementation::GenPathsCHROMIUM(GLsizei range) {
5923 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenPathsCHROMIUM(" << range
5924 << ")");
5925 GPU_CLIENT_SINGLE_THREAD_CHECK();
5926 static const char kFunctionName[] = "glGenPathsCHROMIUM";
5927 if (range < 0) {
5928 SetGLError(GL_INVALID_VALUE, kFunctionName, "range < 0");
5929 return 0;
5931 if (!base::IsValueInRangeForNumericType<int32_t>(range)) {
5932 SetGLError(GL_INVALID_OPERATION, kFunctionName, "range more than 32-bit");
5933 return 0;
5935 if (range == 0)
5936 return 0;
5938 GLuint first_client_id = 0;
5939 GetRangeIdHandler(id_namespaces::kPaths)
5940 ->MakeIdRange(this, range, &first_client_id);
5942 if (first_client_id == 0) {
5943 // Ran out of id space. Is not specified to raise any gl errors.
5944 return 0;
5947 helper_->GenPathsCHROMIUM(first_client_id, range);
5949 GPU_CLIENT_LOG_CODE_BLOCK({
5950 for (GLsizei i = 0; i < range; ++i) {
5951 GPU_CLIENT_LOG(" " << i << ": " << (first_client_id + i));
5954 CheckGLError();
5955 return first_client_id;
5958 void GLES2Implementation::DeletePathsCHROMIUM(GLuint first_client_id,
5959 GLsizei range) {
5960 GPU_CLIENT_SINGLE_THREAD_CHECK();
5961 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeletePathsCHROMIUM("
5962 << first_client_id << ", " << range << ")");
5963 static const char kFunctionName[] = "glDeletePathsCHROMIUM";
5965 if (range < 0) {
5966 SetGLError(GL_INVALID_VALUE, kFunctionName, "range < 0");
5967 return;
5969 if (!base::IsValueInRangeForNumericType<int32_t>(range)) {
5970 SetGLError(GL_INVALID_OPERATION, kFunctionName, "range more than 32-bit");
5971 return;
5973 if (range == 0)
5974 return;
5976 GLuint last_client_id;
5977 if (!SafeAddUint32(first_client_id, range - 1, &last_client_id)) {
5978 SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow");
5979 return;
5982 GetRangeIdHandler(id_namespaces::kPaths)
5983 ->FreeIdRange(this, first_client_id, range,
5984 &GLES2Implementation::DeletePathsCHROMIUMStub);
5985 CheckGLError();
5988 void GLES2Implementation::DeletePathsCHROMIUMStub(GLuint first_client_id,
5989 GLsizei range) {
5990 helper_->DeletePathsCHROMIUM(first_client_id, range);
5993 void GLES2Implementation::PathCommandsCHROMIUM(GLuint path,
5994 GLsizei num_commands,
5995 const GLubyte* commands,
5996 GLsizei num_coords,
5997 GLenum coord_type,
5998 const void* coords) {
5999 GPU_CLIENT_SINGLE_THREAD_CHECK();
6000 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPathCommandsCHROMIUM(" << path
6001 << ", " << num_commands << ", " << commands << ", "
6002 << num_coords << ", " << coords << ")");
6003 static const char kFunctionName[] = "glPathCommandsCHROMIUM";
6004 if (path == 0) {
6005 SetGLError(GL_INVALID_VALUE, kFunctionName, "invalid path object");
6006 return;
6008 if (num_commands < 0) {
6009 SetGLError(GL_INVALID_VALUE, kFunctionName, "numCommands < 0");
6010 return;
6012 if (num_commands != 0 && !commands) {
6013 SetGLError(GL_INVALID_VALUE, kFunctionName, "missing commands");
6014 return;
6016 if (num_coords < 0) {
6017 SetGLError(GL_INVALID_VALUE, kFunctionName, "numCoords < 0");
6018 return;
6020 if (num_coords != 0 && !coords) {
6021 SetGLError(GL_INVALID_VALUE, kFunctionName, "missing coords");
6022 return;
6024 uint32 coord_type_size = GLES2Util::GetGLTypeSizeForPathCoordType(coord_type);
6025 if (coord_type_size == 0) {
6026 SetGLError(GL_INVALID_ENUM, kFunctionName, "invalid coordType");
6027 return;
6029 if (num_commands == 0) {
6030 // No commands must mean no coords, thus nothing to memcpy. Let
6031 // the service validate the call. Validate coord_type above, so
6032 // that the parameters will be checked the in the same order
6033 // regardless of num_commands.
6034 helper_->PathCommandsCHROMIUM(path, num_commands, 0, 0, num_coords,
6035 coord_type, 0, 0);
6036 CheckGLError();
6037 return;
6040 uint32 coords_size;
6041 if (!SafeMultiplyUint32(num_coords, coord_type_size, &coords_size)) {
6042 SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow");
6043 return;
6046 uint32 required_buffer_size;
6047 if (!SafeAddUint32(coords_size, num_commands, &required_buffer_size)) {
6048 SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow");
6049 return;
6052 ScopedTransferBufferPtr buffer(required_buffer_size, helper_,
6053 transfer_buffer_);
6054 if (!buffer.valid() || buffer.size() < required_buffer_size) {
6055 SetGLError(GL_OUT_OF_MEMORY, kFunctionName, "too large");
6056 return;
6059 uint32 coords_shm_id = 0;
6060 uint32 coords_shm_offset = 0;
6061 // Copy coords first because they need more strict alignment.
6062 if (coords_size > 0) {
6063 unsigned char* coords_addr = static_cast<unsigned char*>(buffer.address());
6064 memcpy(coords_addr, coords, coords_size);
6065 coords_shm_id = buffer.shm_id();
6066 coords_shm_offset = buffer.offset();
6069 DCHECK(num_commands > 0);
6070 unsigned char* commands_addr =
6071 static_cast<unsigned char*>(buffer.address()) + coords_size;
6072 memcpy(commands_addr, commands, num_commands);
6074 helper_->PathCommandsCHROMIUM(path, num_commands, buffer.shm_id(),
6075 buffer.offset() + coords_size, num_coords,
6076 coord_type, coords_shm_id, coords_shm_offset);
6077 CheckGLError();
6080 // Include the auto-generated part of this file. We split this because it means
6081 // we can easily edit the non-auto generated parts right here in this file
6082 // instead of having to edit some template or the code generator.
6083 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
6085 } // namespace gles2
6086 } // namespace gpu