Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blobc57abb9414cd9ff7c80108cac96b977a975f5d62
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;
728 // Non-cached parameters.
729 case GL_ALIASED_LINE_WIDTH_RANGE:
730 case GL_ALIASED_POINT_SIZE_RANGE:
731 case GL_ALPHA_BITS:
732 case GL_BLEND:
733 case GL_BLEND_COLOR:
734 case GL_BLEND_DST_ALPHA:
735 case GL_BLEND_DST_RGB:
736 case GL_BLEND_EQUATION_ALPHA:
737 case GL_BLEND_EQUATION_RGB:
738 case GL_BLEND_SRC_ALPHA:
739 case GL_BLEND_SRC_RGB:
740 case GL_BLUE_BITS:
741 case GL_COLOR_CLEAR_VALUE:
742 case GL_COLOR_WRITEMASK:
743 case GL_COMPRESSED_TEXTURE_FORMATS:
744 case GL_CULL_FACE:
745 case GL_CULL_FACE_MODE:
746 case GL_CURRENT_PROGRAM:
747 case GL_DEPTH_BITS:
748 case GL_DEPTH_CLEAR_VALUE:
749 case GL_DEPTH_FUNC:
750 case GL_DEPTH_RANGE:
751 case GL_DEPTH_TEST:
752 case GL_DEPTH_WRITEMASK:
753 case GL_DITHER:
754 case GL_FRONT_FACE:
755 case GL_GENERATE_MIPMAP_HINT:
756 case GL_GREEN_BITS:
757 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
758 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
759 case GL_LINE_WIDTH:
760 case GL_MAX_VIEWPORT_DIMS:
761 case GL_PACK_ALIGNMENT:
762 case GL_POLYGON_OFFSET_FACTOR:
763 case GL_POLYGON_OFFSET_FILL:
764 case GL_POLYGON_OFFSET_UNITS:
765 case GL_RED_BITS:
766 case GL_SAMPLE_ALPHA_TO_COVERAGE:
767 case GL_SAMPLE_BUFFERS:
768 case GL_SAMPLE_COVERAGE:
769 case GL_SAMPLE_COVERAGE_INVERT:
770 case GL_SAMPLE_COVERAGE_VALUE:
771 case GL_SAMPLES:
772 case GL_SCISSOR_BOX:
773 case GL_SCISSOR_TEST:
774 case GL_SHADER_BINARY_FORMATS:
775 case GL_SHADER_COMPILER:
776 case GL_STENCIL_BACK_FAIL:
777 case GL_STENCIL_BACK_FUNC:
778 case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
779 case GL_STENCIL_BACK_PASS_DEPTH_PASS:
780 case GL_STENCIL_BACK_REF:
781 case GL_STENCIL_BACK_VALUE_MASK:
782 case GL_STENCIL_BACK_WRITEMASK:
783 case GL_STENCIL_BITS:
784 case GL_STENCIL_CLEAR_VALUE:
785 case GL_STENCIL_FAIL:
786 case GL_STENCIL_FUNC:
787 case GL_STENCIL_PASS_DEPTH_FAIL:
788 case GL_STENCIL_PASS_DEPTH_PASS:
789 case GL_STENCIL_REF:
790 case GL_STENCIL_TEST:
791 case GL_STENCIL_VALUE_MASK:
792 case GL_STENCIL_WRITEMASK:
793 case GL_SUBPIXEL_BITS:
794 case GL_UNPACK_ALIGNMENT:
795 case GL_VIEWPORT:
796 return false;
797 default:
798 break;
801 if (capabilities_.major_version < 3) {
802 return false;
805 // ES3 parameters.
806 switch (pname) {
807 case GL_COPY_READ_BUFFER_BINDING:
808 *params = bound_copy_read_buffer_;
809 return true;
810 case GL_COPY_WRITE_BUFFER_BINDING:
811 *params = bound_copy_write_buffer_;
812 return true;
813 case GL_MAJOR_VERSION:
814 *params = capabilities_.major_version;
815 return true;
816 case GL_MAX_3D_TEXTURE_SIZE:
817 *params = capabilities_.max_3d_texture_size;
818 return true;
819 case GL_MAX_ARRAY_TEXTURE_LAYERS:
820 *params = capabilities_.max_array_texture_layers;
821 return true;
822 case GL_MAX_COLOR_ATTACHMENTS:
823 *params = capabilities_.max_color_attachments;
824 return true;
825 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
826 *params = static_cast<GLint>(
827 capabilities_.max_combined_fragment_uniform_components);
828 return true;
829 case GL_MAX_COMBINED_UNIFORM_BLOCKS:
830 *params = capabilities_.max_combined_uniform_blocks;
831 return true;
832 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
833 *params = static_cast<GLint>(
834 capabilities_.max_combined_vertex_uniform_components);
835 return true;
836 case GL_MAX_DRAW_BUFFERS:
837 *params = capabilities_.max_draw_buffers;
838 return true;
839 case GL_MAX_ELEMENT_INDEX:
840 *params = static_cast<GLint>(capabilities_.max_element_index);
841 return true;
842 case GL_MAX_ELEMENTS_INDICES:
843 *params = capabilities_.max_elements_indices;
844 return true;
845 case GL_MAX_ELEMENTS_VERTICES:
846 *params = capabilities_.max_elements_vertices;
847 return true;
848 case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
849 *params = capabilities_.max_fragment_input_components;
850 return true;
851 case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
852 *params = capabilities_.max_fragment_uniform_blocks;
853 return true;
854 case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
855 *params = capabilities_.max_fragment_uniform_components;
856 return true;
857 case GL_MAX_PROGRAM_TEXEL_OFFSET:
858 *params = capabilities_.max_program_texel_offset;
859 return true;
860 case GL_MAX_SAMPLES:
861 *params = capabilities_.max_samples;
862 return true;
863 case GL_MAX_SERVER_WAIT_TIMEOUT:
864 *params = static_cast<GLint>(capabilities_.max_server_wait_timeout);
865 return true;
866 case GL_MAX_TEXTURE_LOD_BIAS:
867 *params = static_cast<GLint>(capabilities_.max_texture_lod_bias);
868 return true;
869 case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
870 *params = capabilities_.max_transform_feedback_interleaved_components;
871 return true;
872 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
873 *params = capabilities_.max_transform_feedback_separate_attribs;
874 return true;
875 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
876 *params = capabilities_.max_transform_feedback_separate_components;
877 return true;
878 case GL_MAX_UNIFORM_BLOCK_SIZE:
879 *params = static_cast<GLint>(capabilities_.max_uniform_block_size);
880 return true;
881 case GL_MAX_UNIFORM_BUFFER_BINDINGS:
882 *params = capabilities_.max_uniform_buffer_bindings;
883 return true;
884 case GL_MAX_VARYING_COMPONENTS:
885 *params = capabilities_.max_varying_components;
886 return true;
887 case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
888 *params = capabilities_.max_vertex_output_components;
889 return true;
890 case GL_MAX_VERTEX_UNIFORM_BLOCKS:
891 *params = capabilities_.max_vertex_uniform_blocks;
892 return true;
893 case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
894 *params = capabilities_.max_vertex_uniform_components;
895 return true;
896 case GL_MIN_PROGRAM_TEXEL_OFFSET:
897 *params = capabilities_.min_program_texel_offset;
898 return true;
899 case GL_MINOR_VERSION:
900 *params = capabilities_.minor_version;
901 return true;
902 case GL_NUM_EXTENSIONS:
903 *params = capabilities_.num_extensions;
904 return true;
905 case GL_NUM_PROGRAM_BINARY_FORMATS:
906 *params = capabilities_.num_program_binary_formats;
907 return true;
908 case GL_PIXEL_PACK_BUFFER_BINDING:
909 *params = bound_pixel_pack_buffer_;
910 return true;
911 case GL_PIXEL_UNPACK_BUFFER_BINDING:
912 *params = bound_pixel_unpack_buffer_;
913 return true;
914 case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
915 *params = bound_transform_feedback_buffer_;
916 return true;
917 case GL_UNIFORM_BUFFER_BINDING:
918 *params = bound_uniform_buffer_;
919 return true;
920 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
921 *params = capabilities_.uniform_buffer_offset_alignment;
922 return true;
924 // Non-cached ES3 parameters.
925 case GL_DRAW_BUFFER0:
926 case GL_DRAW_BUFFER1:
927 case GL_DRAW_BUFFER2:
928 case GL_DRAW_BUFFER3:
929 case GL_DRAW_BUFFER4:
930 case GL_DRAW_BUFFER5:
931 case GL_DRAW_BUFFER6:
932 case GL_DRAW_BUFFER7:
933 case GL_DRAW_BUFFER8:
934 case GL_DRAW_BUFFER9:
935 case GL_DRAW_BUFFER10:
936 case GL_DRAW_BUFFER11:
937 case GL_DRAW_BUFFER12:
938 case GL_DRAW_BUFFER13:
939 case GL_DRAW_BUFFER14:
940 case GL_DRAW_BUFFER15:
941 case GL_DRAW_FRAMEBUFFER_BINDING:
942 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
943 case GL_PACK_ROW_LENGTH:
944 case GL_PACK_SKIP_PIXELS:
945 case GL_PACK_SKIP_ROWS:
946 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
947 case GL_PROGRAM_BINARY_FORMATS:
948 case GL_RASTERIZER_DISCARD:
949 case GL_READ_BUFFER:
950 case GL_READ_FRAMEBUFFER_BINDING:
951 case GL_SAMPLER_BINDING:
952 case GL_TEXTURE_BINDING_2D_ARRAY:
953 case GL_TEXTURE_BINDING_3D:
954 case GL_TRANSFORM_FEEDBACK_BINDING:
955 case GL_TRANSFORM_FEEDBACK_ACTIVE:
956 case GL_TRANSFORM_FEEDBACK_PAUSED:
957 case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
958 case GL_TRANSFORM_FEEDBACK_BUFFER_START:
959 case GL_UNIFORM_BUFFER_SIZE:
960 case GL_UNIFORM_BUFFER_START:
961 case GL_UNPACK_IMAGE_HEIGHT:
962 case GL_UNPACK_ROW_LENGTH:
963 case GL_UNPACK_SKIP_IMAGES:
964 case GL_UNPACK_SKIP_PIXELS:
965 case GL_UNPACK_SKIP_ROWS:
966 case GL_VERTEX_ARRAY_BINDING:
967 return false;
968 default:
969 return false;
973 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
974 // TODO(gman): Make this handle pnames that return more than 1 value.
975 GLint value;
976 if (!GetHelper(pname, &value)) {
977 return false;
979 *params = static_cast<GLboolean>(value);
980 return true;
983 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
984 // TODO(gman): Make this handle pnames that return more than 1 value.
985 switch (pname) {
986 case GL_MAX_TEXTURE_LOD_BIAS:
987 *params = capabilities_.max_texture_lod_bias;
988 return true;
989 default:
990 break;
992 GLint value;
993 if (!GetHelper(pname, &value)) {
994 return false;
996 *params = static_cast<GLfloat>(value);
997 return true;
1000 bool GLES2Implementation::GetInteger64vHelper(GLenum pname, GLint64* params) {
1001 switch (pname) {
1002 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
1003 *params = capabilities_.max_combined_fragment_uniform_components;
1004 return true;
1005 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
1006 *params = capabilities_.max_combined_vertex_uniform_components;
1007 return true;
1008 case GL_MAX_ELEMENT_INDEX:
1009 *params = capabilities_.max_element_index;
1010 return true;
1011 case GL_MAX_SERVER_WAIT_TIMEOUT:
1012 *params = capabilities_.max_server_wait_timeout;
1013 return true;
1014 case GL_MAX_UNIFORM_BLOCK_SIZE:
1015 *params = capabilities_.max_uniform_block_size;
1016 return true;
1017 case GL_TIMESTAMP_EXT:
1018 // We convert all GPU timestamps to CPU time.
1019 *params = (base::TraceTicks::Now() - base::TraceTicks()).InMicroseconds()
1020 * base::Time::kNanosecondsPerMicrosecond;
1021 return true;
1022 default:
1023 break;
1025 GLint value;
1026 if (!GetHelper(pname, &value)) {
1027 return false;
1029 *params = static_cast<GLint64>(value);
1030 return true;
1033 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
1034 return GetHelper(pname, params);
1037 bool GLES2Implementation::GetIntegeri_vHelper(
1038 GLenum pname, GLuint index, GLint* data) {
1039 // TODO(zmo): Implement client side caching.
1040 return false;
1043 bool GLES2Implementation::GetInteger64i_vHelper(
1044 GLenum pname, GLuint index, GLint64* data) {
1045 // TODO(zmo): Implement client side caching.
1046 return false;
1049 bool GLES2Implementation::GetInternalformativHelper(
1050 GLenum target, GLenum format, GLenum pname, GLsizei bufSize,
1051 GLint* params) {
1052 // TODO(zmo): Implement the client side caching.
1053 return false;
1056 bool GLES2Implementation::GetSyncivHelper(
1057 GLsync sync, GLenum pname, GLsizei bufsize, GLsizei* length,
1058 GLint* values) {
1059 GLint value = 0;
1060 switch (pname) {
1061 case GL_OBJECT_TYPE:
1062 value = GL_SYNC_FENCE;
1063 break;
1064 case GL_SYNC_CONDITION:
1065 value = GL_SYNC_GPU_COMMANDS_COMPLETE;
1066 break;
1067 case GL_SYNC_FLAGS:
1068 value = 0;
1069 break;
1070 default:
1071 return false;
1073 if (bufsize > 0) {
1074 DCHECK(values);
1075 *values = value;
1077 if (length) {
1078 *length = 1;
1080 return true;
1083 bool GLES2Implementation::GetQueryObjectValueHelper(
1084 const char* function_name, GLuint id, GLenum pname, GLuint64* params) {
1085 GPU_CLIENT_SINGLE_THREAD_CHECK();
1086 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryObjectValueHelper("
1087 << id << ", "
1088 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
1089 << static_cast<const void*>(params) << ")");
1091 QueryTracker::Query* query = query_tracker_->GetQuery(id);
1092 if (!query) {
1093 SetGLError(GL_INVALID_OPERATION,
1094 function_name, "unknown query id");
1095 return false;
1098 if (query->Active()) {
1099 SetGLError(
1100 GL_INVALID_OPERATION,
1101 function_name,
1102 "query active. Did you to call glEndQueryEXT?");
1103 return false;
1106 if (query->NeverUsed()) {
1107 SetGLError(
1108 GL_INVALID_OPERATION,
1109 function_name, "Never used. Did you call glBeginQueryEXT?");
1110 return false;
1113 bool valid_value = false;
1114 switch (pname) {
1115 case GL_QUERY_RESULT_EXT:
1116 if (!query->CheckResultsAvailable(helper_)) {
1117 helper_->WaitForToken(query->token());
1118 if (!query->CheckResultsAvailable(helper_)) {
1119 FinishHelper();
1120 CHECK(query->CheckResultsAvailable(helper_));
1123 *params = query->GetResult();
1124 valid_value = true;
1125 break;
1126 case GL_QUERY_RESULT_AVAILABLE_EXT:
1127 *params = query->CheckResultsAvailable(helper_);
1128 valid_value = true;
1129 break;
1130 default:
1131 SetGLErrorInvalidEnum(function_name, pname, "pname");
1132 break;
1134 GPU_CLIENT_LOG(" " << *params);
1135 CheckGLError();
1136 return valid_value;
1139 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
1140 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1141 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
1142 Result* result = GetResultAs<Result*>();
1143 if (!result) {
1144 return 0;
1146 *result = 0;
1147 helper_->GetMaxValueInBufferCHROMIUM(
1148 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
1149 WaitForCmd();
1150 return *result;
1153 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
1154 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1155 GPU_CLIENT_SINGLE_THREAD_CHECK();
1156 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
1157 << buffer_id << ", " << count << ", "
1158 << GLES2Util::GetStringGetMaxIndexType(type)
1159 << ", " << offset << ")");
1160 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
1161 buffer_id, count, type, offset);
1162 GPU_CLIENT_LOG("returned " << result);
1163 CheckGLError();
1164 return result;
1167 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
1168 if (restore) {
1169 RestoreArrayBuffer(restore);
1170 // Restore the element array binding.
1171 // We only need to restore it if it wasn't a client side array.
1172 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
1173 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1178 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
1179 if (restore) {
1180 // Restore the user's current binding.
1181 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_);
1185 void GLES2Implementation::DrawElements(
1186 GLenum mode, GLsizei count, GLenum type, const void* indices) {
1187 GPU_CLIENT_SINGLE_THREAD_CHECK();
1188 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
1189 << GLES2Util::GetStringDrawMode(mode) << ", "
1190 << count << ", "
1191 << GLES2Util::GetStringIndexType(type) << ", "
1192 << static_cast<const void*>(indices) << ")");
1193 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1196 void GLES2Implementation::DrawRangeElements(
1197 GLenum mode, GLuint start, GLuint end,
1198 GLsizei count, GLenum type, const void* indices) {
1199 GPU_CLIENT_SINGLE_THREAD_CHECK();
1200 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawRangeElements("
1201 << GLES2Util::GetStringDrawMode(mode) << ", "
1202 << start << ", " << end << ", " << count << ", "
1203 << GLES2Util::GetStringIndexType(type) << ", "
1204 << static_cast<const void*>(indices) << ")");
1205 if (end < start) {
1206 SetGLError(GL_INVALID_VALUE, "glDrawRangeElements", "end < start");
1207 return;
1209 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1212 void GLES2Implementation::DrawElementsImpl(
1213 GLenum mode, GLsizei count, GLenum type, const void* indices,
1214 const char* func_name) {
1215 if (count < 0) {
1216 SetGLError(GL_INVALID_VALUE, func_name, "count < 0");
1217 return;
1219 bool simulated = false;
1220 GLuint offset = ToGLuint(indices);
1221 if (count > 0) {
1222 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
1223 !ValidateOffset(func_name, reinterpret_cast<GLintptr>(indices))) {
1224 return;
1226 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
1227 func_name, this, helper_, count, type, 0, indices,
1228 &offset, &simulated)) {
1229 return;
1232 helper_->DrawElements(mode, count, type, offset);
1233 RestoreElementAndArrayBuffers(simulated);
1234 CheckGLError();
1237 void GLES2Implementation::Flush() {
1238 GPU_CLIENT_SINGLE_THREAD_CHECK();
1239 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
1240 // Insert the cmd to call glFlush
1241 helper_->Flush();
1242 FlushHelper();
1245 void GLES2Implementation::ShallowFlushCHROMIUM() {
1246 GPU_CLIENT_SINGLE_THREAD_CHECK();
1247 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
1248 FlushHelper();
1251 void GLES2Implementation::FlushHelper() {
1252 // Flush our command buffer
1253 // (tell the service to execute up to the flush cmd.)
1254 helper_->CommandBufferHelper::Flush();
1256 if (aggressively_free_resources_)
1257 FreeEverything();
1260 void GLES2Implementation::OrderingBarrierCHROMIUM() {
1261 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOrderingBarrierCHROMIUM");
1262 // Flush command buffer at the GPU channel level. May be implemented as
1263 // Flush().
1264 helper_->CommandBufferHelper::OrderingBarrier();
1267 void GLES2Implementation::Finish() {
1268 GPU_CLIENT_SINGLE_THREAD_CHECK();
1269 FinishHelper();
1272 void GLES2Implementation::ShallowFinishCHROMIUM() {
1273 GPU_CLIENT_SINGLE_THREAD_CHECK();
1274 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
1275 // Flush our command buffer (tell the service to execute up to the flush cmd
1276 // and don't return until it completes).
1277 helper_->CommandBufferHelper::Finish();
1279 if (aggressively_free_resources_)
1280 FreeEverything();
1283 void GLES2Implementation::FinishHelper() {
1284 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
1285 TRACE_EVENT0("gpu", "GLES2::Finish");
1286 // Insert the cmd to call glFinish
1287 helper_->Finish();
1288 // Finish our command buffer
1289 // (tell the service to execute up to the Finish cmd and wait for it to
1290 // execute.)
1291 helper_->CommandBufferHelper::Finish();
1293 if (aggressively_free_resources_)
1294 FreeEverything();
1297 void GLES2Implementation::SwapBuffers() {
1298 GPU_CLIENT_SINGLE_THREAD_CHECK();
1299 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
1300 // TODO(piman): Strictly speaking we'd want to insert the token after the
1301 // swap, but the state update with the updated token might not have happened
1302 // by the time the SwapBuffer callback gets called, forcing us to synchronize
1303 // with the GPU process more than needed. So instead, make it happen before.
1304 // All it means is that we could be slightly looser on the kMaxSwapBuffers
1305 // semantics if the client doesn't use the callback mechanism, and by chance
1306 // the scheduler yields between the InsertToken and the SwapBuffers.
1307 swap_buffers_tokens_.push(helper_->InsertToken());
1308 helper_->SwapBuffers();
1309 helper_->CommandBufferHelper::Flush();
1310 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
1311 // compensate for TODO above.
1312 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
1313 helper_->WaitForToken(swap_buffers_tokens_.front());
1314 swap_buffers_tokens_.pop();
1318 void GLES2Implementation::SwapInterval(int interval) {
1319 GPU_CLIENT_SINGLE_THREAD_CHECK();
1320 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapInterval("
1321 << interval << ")");
1322 helper_->SwapInterval(interval);
1325 void GLES2Implementation::BindAttribLocation(
1326 GLuint program, GLuint index, const char* name) {
1327 GPU_CLIENT_SINGLE_THREAD_CHECK();
1328 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
1329 << program << ", " << index << ", " << name << ")");
1330 SetBucketAsString(kResultBucketId, name);
1331 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
1332 helper_->SetBucketSize(kResultBucketId, 0);
1333 CheckGLError();
1336 void GLES2Implementation::BindUniformLocationCHROMIUM(
1337 GLuint program, GLint location, const char* name) {
1338 GPU_CLIENT_SINGLE_THREAD_CHECK();
1339 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1340 << program << ", " << location << ", " << name << ")");
1341 SetBucketAsString(kResultBucketId, name);
1342 helper_->BindUniformLocationCHROMIUMBucket(
1343 program, location, kResultBucketId);
1344 helper_->SetBucketSize(kResultBucketId, 0);
1345 CheckGLError();
1348 void GLES2Implementation::GetVertexAttribPointerv(
1349 GLuint index, GLenum pname, void** ptr) {
1350 GPU_CLIENT_SINGLE_THREAD_CHECK();
1351 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1352 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1353 << static_cast<void*>(ptr) << ")");
1354 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
1355 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1356 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1357 typedef cmds::GetVertexAttribPointerv::Result Result;
1358 Result* result = GetResultAs<Result*>();
1359 if (!result) {
1360 return;
1362 result->SetNumResults(0);
1363 helper_->GetVertexAttribPointerv(
1364 index, pname, GetResultShmId(), GetResultShmOffset());
1365 WaitForCmd();
1366 result->CopyResult(ptr);
1367 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1369 GPU_CLIENT_LOG_CODE_BLOCK({
1370 for (int32 i = 0; i < num_results; ++i) {
1371 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
1374 CheckGLError();
1377 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1378 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1379 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
1380 SetGLError(
1381 GL_INVALID_VALUE,
1382 "glDeleteProgram", "id not created by this context.");
1383 return false;
1385 if (program == current_program_) {
1386 current_program_ = 0;
1388 return true;
1391 void GLES2Implementation::DeleteProgramStub(
1392 GLsizei n, const GLuint* programs) {
1393 DCHECK_EQ(1, n);
1394 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1395 helper_->DeleteProgram(programs[0]);
1398 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1399 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1400 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1401 SetGLError(
1402 GL_INVALID_VALUE,
1403 "glDeleteShader", "id not created by this context.");
1404 return false;
1406 return true;
1409 void GLES2Implementation::DeleteShaderStub(
1410 GLsizei n, const GLuint* shaders) {
1411 DCHECK_EQ(1, n);
1412 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1413 helper_->DeleteShader(shaders[0]);
1416 void GLES2Implementation::DeleteSyncHelper(GLsync sync) {
1417 GLuint sync_uint = ToGLuint(sync);
1418 if (!GetIdHandler(id_namespaces::kSyncs)->FreeIds(
1419 this, 1, &sync_uint, &GLES2Implementation::DeleteSyncStub)) {
1420 SetGLError(
1421 GL_INVALID_VALUE,
1422 "glDeleteSync", "id not created by this context.");
1426 void GLES2Implementation::DeleteSyncStub(GLsizei n, const GLuint* syncs) {
1427 DCHECK_EQ(1, n);
1428 helper_->DeleteSync(syncs[0]);
1431 GLint GLES2Implementation::GetAttribLocationHelper(
1432 GLuint program, const char* name) {
1433 typedef cmds::GetAttribLocation::Result Result;
1434 Result* result = GetResultAs<Result*>();
1435 if (!result) {
1436 return -1;
1438 *result = -1;
1439 SetBucketAsCString(kResultBucketId, name);
1440 helper_->GetAttribLocation(
1441 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1442 WaitForCmd();
1443 helper_->SetBucketSize(kResultBucketId, 0);
1444 return *result;
1447 GLint GLES2Implementation::GetAttribLocation(
1448 GLuint program, const char* name) {
1449 GPU_CLIENT_SINGLE_THREAD_CHECK();
1450 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1451 << ", " << name << ")");
1452 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1453 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1454 this, program, name);
1455 GPU_CLIENT_LOG("returned " << loc);
1456 CheckGLError();
1457 return loc;
1460 GLint GLES2Implementation::GetUniformLocationHelper(
1461 GLuint program, const char* name) {
1462 typedef cmds::GetUniformLocation::Result Result;
1463 Result* result = GetResultAs<Result*>();
1464 if (!result) {
1465 return -1;
1467 *result = -1;
1468 SetBucketAsCString(kResultBucketId, name);
1469 helper_->GetUniformLocation(program, kResultBucketId,
1470 GetResultShmId(), GetResultShmOffset());
1471 WaitForCmd();
1472 helper_->SetBucketSize(kResultBucketId, 0);
1473 return *result;
1476 GLint GLES2Implementation::GetUniformLocation(
1477 GLuint program, const char* name) {
1478 GPU_CLIENT_SINGLE_THREAD_CHECK();
1479 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1480 << ", " << name << ")");
1481 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1482 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1483 this, program, name);
1484 GPU_CLIENT_LOG("returned " << loc);
1485 CheckGLError();
1486 return loc;
1489 bool GLES2Implementation::GetUniformIndicesHelper(
1490 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1491 typedef cmds::GetUniformIndices::Result Result;
1492 Result* result = GetResultAs<Result*>();
1493 if (!result) {
1494 return false;
1496 result->SetNumResults(0);
1497 if (!PackStringsToBucket(count, names, NULL, "glGetUniformIndices")) {
1498 return false;
1500 helper_->GetUniformIndices(program, kResultBucketId,
1501 GetResultShmId(), GetResultShmOffset());
1502 WaitForCmd();
1503 if (result->GetNumResults() != count) {
1504 return false;
1506 result->CopyResult(indices);
1507 return true;
1510 void GLES2Implementation::GetUniformIndices(
1511 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1512 GPU_CLIENT_SINGLE_THREAD_CHECK();
1513 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
1514 << ", " << count << ", " << names << ", " << indices << ")");
1515 TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
1516 if (count < 0) {
1517 SetGLError(GL_INVALID_VALUE, "glGetUniformIndices", "count < 0");
1518 return;
1520 if (count == 0) {
1521 return;
1523 bool success = share_group_->program_info_manager()->GetUniformIndices(
1524 this, program, count, names, indices);
1525 if (success) {
1526 GPU_CLIENT_LOG_CODE_BLOCK({
1527 for (GLsizei ii = 0; ii < count; ++ii) {
1528 GPU_CLIENT_LOG(" " << ii << ": " << indices[ii]);
1532 CheckGLError();
1535 bool GLES2Implementation::GetProgramivHelper(
1536 GLuint program, GLenum pname, GLint* params) {
1537 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1538 this, program, pname, params);
1539 GPU_CLIENT_LOG_CODE_BLOCK({
1540 if (got_value) {
1541 GPU_CLIENT_LOG(" 0: " << *params);
1544 return got_value;
1547 GLint GLES2Implementation::GetFragDataLocationHelper(
1548 GLuint program, const char* name) {
1549 typedef cmds::GetFragDataLocation::Result Result;
1550 Result* result = GetResultAs<Result*>();
1551 if (!result) {
1552 return -1;
1554 *result = -1;
1555 SetBucketAsCString(kResultBucketId, name);
1556 helper_->GetFragDataLocation(
1557 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1558 WaitForCmd();
1559 helper_->SetBucketSize(kResultBucketId, 0);
1560 return *result;
1563 GLint GLES2Implementation::GetFragDataLocation(
1564 GLuint program, const char* name) {
1565 GPU_CLIENT_SINGLE_THREAD_CHECK();
1566 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataLocation("
1567 << program << ", " << name << ")");
1568 TRACE_EVENT0("gpu", "GLES2::GetFragDataLocation");
1569 GLint loc = share_group_->program_info_manager()->GetFragDataLocation(
1570 this, program, name);
1571 GPU_CLIENT_LOG("returned " << loc);
1572 CheckGLError();
1573 return loc;
1576 GLuint GLES2Implementation::GetUniformBlockIndexHelper(
1577 GLuint program, const char* name) {
1578 typedef cmds::GetUniformBlockIndex::Result Result;
1579 Result* result = GetResultAs<Result*>();
1580 if (!result) {
1581 return GL_INVALID_INDEX;
1583 *result = GL_INVALID_INDEX;
1584 SetBucketAsCString(kResultBucketId, name);
1585 helper_->GetUniformBlockIndex(
1586 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1587 WaitForCmd();
1588 helper_->SetBucketSize(kResultBucketId, 0);
1589 return *result;
1592 GLuint GLES2Implementation::GetUniformBlockIndex(
1593 GLuint program, const char* name) {
1594 GPU_CLIENT_SINGLE_THREAD_CHECK();
1595 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformBlockIndex("
1596 << program << ", " << name << ")");
1597 TRACE_EVENT0("gpu", "GLES2::GetUniformBlockIndex");
1598 GLuint index = share_group_->program_info_manager()->GetUniformBlockIndex(
1599 this, program, name);
1600 GPU_CLIENT_LOG("returned " << index);
1601 CheckGLError();
1602 return index;
1605 void GLES2Implementation::LinkProgram(GLuint program) {
1606 GPU_CLIENT_SINGLE_THREAD_CHECK();
1607 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1608 helper_->LinkProgram(program);
1609 share_group_->program_info_manager()->CreateInfo(program);
1610 CheckGLError();
1613 void GLES2Implementation::ShaderBinary(
1614 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1615 GLsizei length) {
1616 GPU_CLIENT_SINGLE_THREAD_CHECK();
1617 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1618 << static_cast<const void*>(shaders) << ", "
1619 << GLES2Util::GetStringEnum(binaryformat) << ", "
1620 << static_cast<const void*>(binary) << ", "
1621 << length << ")");
1622 if (n < 0) {
1623 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1624 return;
1626 if (length < 0) {
1627 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1628 return;
1630 // TODO(gman): ShaderBinary should use buckets.
1631 unsigned int shader_id_size = n * sizeof(*shaders);
1632 ScopedTransferBufferArray<GLint> buffer(
1633 shader_id_size + length, helper_, transfer_buffer_);
1634 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1635 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1636 return;
1638 void* shader_ids = buffer.elements();
1639 void* shader_data = buffer.elements() + shader_id_size;
1640 memcpy(shader_ids, shaders, shader_id_size);
1641 memcpy(shader_data, binary, length);
1642 helper_->ShaderBinary(
1644 buffer.shm_id(),
1645 buffer.offset(),
1646 binaryformat,
1647 buffer.shm_id(),
1648 buffer.offset() + shader_id_size,
1649 length);
1650 CheckGLError();
1653 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1654 GPU_CLIENT_SINGLE_THREAD_CHECK();
1655 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1656 << GLES2Util::GetStringPixelStore(pname) << ", "
1657 << param << ")");
1658 switch (pname) {
1659 case GL_PACK_ALIGNMENT:
1660 pack_alignment_ = param;
1661 break;
1662 case GL_UNPACK_ALIGNMENT:
1663 unpack_alignment_ = param;
1664 break;
1665 case GL_UNPACK_ROW_LENGTH_EXT:
1666 unpack_row_length_ = param;
1667 return;
1668 case GL_UNPACK_IMAGE_HEIGHT:
1669 unpack_image_height_ = param;
1670 return;
1671 case GL_UNPACK_SKIP_ROWS_EXT:
1672 unpack_skip_rows_ = param;
1673 return;
1674 case GL_UNPACK_SKIP_PIXELS_EXT:
1675 unpack_skip_pixels_ = param;
1676 return;
1677 case GL_UNPACK_SKIP_IMAGES:
1678 unpack_skip_images_ = param;
1679 return;
1680 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1681 pack_reverse_row_order_ =
1682 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1683 break;
1684 default:
1685 break;
1687 helper_->PixelStorei(pname, param);
1688 CheckGLError();
1691 void GLES2Implementation::VertexAttribIPointer(
1692 GLuint index, GLint size, GLenum type, GLsizei stride, const void* ptr) {
1693 GPU_CLIENT_SINGLE_THREAD_CHECK();
1694 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribIPointer("
1695 << index << ", "
1696 << size << ", "
1697 << GLES2Util::GetStringVertexAttribIType(type) << ", "
1698 << stride << ", "
1699 << ptr << ")");
1700 // Record the info on the client side.
1701 if (!vertex_array_object_manager_->SetAttribPointer(bound_array_buffer_,
1702 index,
1703 size,
1704 type,
1705 GL_FALSE,
1706 stride,
1707 ptr,
1708 GL_TRUE)) {
1709 SetGLError(GL_INVALID_OPERATION, "glVertexAttribIPointer",
1710 "client side arrays are not allowed in vertex array objects.");
1711 return;
1713 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
1714 // Only report NON client side buffers to the service.
1715 if (!ValidateOffset("glVertexAttribIPointer",
1716 reinterpret_cast<GLintptr>(ptr))) {
1717 return;
1719 helper_->VertexAttribIPointer(index, size, type, stride, ToGLuint(ptr));
1721 CheckGLError();
1724 void GLES2Implementation::VertexAttribPointer(
1725 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1726 const void* ptr) {
1727 GPU_CLIENT_SINGLE_THREAD_CHECK();
1728 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1729 << index << ", "
1730 << size << ", "
1731 << GLES2Util::GetStringVertexAttribType(type) << ", "
1732 << GLES2Util::GetStringBool(normalized) << ", "
1733 << stride << ", "
1734 << ptr << ")");
1735 // Record the info on the client side.
1736 if (!vertex_array_object_manager_->SetAttribPointer(bound_array_buffer_,
1737 index,
1738 size,
1739 type,
1740 normalized,
1741 stride,
1742 ptr,
1743 GL_FALSE)) {
1744 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1745 "client side arrays are not allowed in vertex array objects.");
1746 return;
1748 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
1749 // Only report NON client side buffers to the service.
1750 if (!ValidateOffset("glVertexAttribPointer",
1751 reinterpret_cast<GLintptr>(ptr))) {
1752 return;
1754 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1755 ToGLuint(ptr));
1757 CheckGLError();
1760 void GLES2Implementation::VertexAttribDivisorANGLE(
1761 GLuint index, GLuint divisor) {
1762 GPU_CLIENT_SINGLE_THREAD_CHECK();
1763 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1764 << index << ", "
1765 << divisor << ") ");
1766 // Record the info on the client side.
1767 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1768 helper_->VertexAttribDivisorANGLE(index, divisor);
1769 CheckGLError();
1772 void GLES2Implementation::BufferDataHelper(
1773 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1774 if (!ValidateSize("glBufferData", size))
1775 return;
1777 #if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
1778 // Do not upload uninitialized data. Even if it's not a bug, it can cause a
1779 // bogus MSan report during a readback later. This is because MSan doesn't
1780 // understand shared memory and would assume we were reading back the same
1781 // unintialized data.
1782 if (data) __msan_check_mem_is_initialized(data, size);
1783 #endif
1785 GLuint buffer_id;
1786 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1787 if (!buffer_id) {
1788 return;
1791 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1792 if (buffer)
1793 RemoveTransferBuffer(buffer);
1795 // Create new buffer.
1796 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1797 DCHECK(buffer);
1798 if (buffer->address() && data)
1799 memcpy(buffer->address(), data, size);
1800 return;
1803 RemoveMappedBufferRangeByTarget(target);
1805 // If there is no data just send BufferData
1806 if (size == 0 || !data) {
1807 helper_->BufferData(target, size, 0, 0, usage);
1808 return;
1811 // See if we can send all at once.
1812 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1813 if (!buffer.valid()) {
1814 return;
1817 if (buffer.size() >= static_cast<unsigned int>(size)) {
1818 memcpy(buffer.address(), data, size);
1819 helper_->BufferData(
1820 target,
1821 size,
1822 buffer.shm_id(),
1823 buffer.offset(),
1824 usage);
1825 return;
1828 // Make the buffer with BufferData then send via BufferSubData
1829 helper_->BufferData(target, size, 0, 0, usage);
1830 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1831 CheckGLError();
1834 void GLES2Implementation::BufferData(
1835 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1836 GPU_CLIENT_SINGLE_THREAD_CHECK();
1837 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1838 << GLES2Util::GetStringBufferTarget(target) << ", "
1839 << size << ", "
1840 << static_cast<const void*>(data) << ", "
1841 << GLES2Util::GetStringBufferUsage(usage) << ")");
1842 BufferDataHelper(target, size, data, usage);
1843 CheckGLError();
1846 void GLES2Implementation::BufferSubDataHelper(
1847 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1848 if (size == 0) {
1849 return;
1852 if (!ValidateSize("glBufferSubData", size) ||
1853 !ValidateOffset("glBufferSubData", offset)) {
1854 return;
1857 GLuint buffer_id;
1858 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1859 if (!buffer_id) {
1860 return;
1862 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1863 if (!buffer) {
1864 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1865 return;
1868 int32 end = 0;
1869 int32 buffer_size = buffer->size();
1870 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1871 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1872 return;
1875 if (buffer->address() && data)
1876 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1877 return;
1880 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1881 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1884 void GLES2Implementation::BufferSubDataHelperImpl(
1885 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1886 ScopedTransferBufferPtr* buffer) {
1887 DCHECK(buffer);
1888 DCHECK_GT(size, 0);
1890 const int8* source = static_cast<const int8*>(data);
1891 while (size) {
1892 if (!buffer->valid() || buffer->size() == 0) {
1893 buffer->Reset(size);
1894 if (!buffer->valid()) {
1895 return;
1898 memcpy(buffer->address(), source, buffer->size());
1899 helper_->BufferSubData(
1900 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1901 offset += buffer->size();
1902 source += buffer->size();
1903 size -= buffer->size();
1904 buffer->Release();
1908 void GLES2Implementation::BufferSubData(
1909 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1910 GPU_CLIENT_SINGLE_THREAD_CHECK();
1911 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1912 << GLES2Util::GetStringBufferTarget(target) << ", "
1913 << offset << ", " << size << ", "
1914 << static_cast<const void*>(data) << ")");
1915 BufferSubDataHelper(target, offset, size, data);
1916 CheckGLError();
1919 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
1920 int32 token = buffer->last_usage_token();
1921 uint32 async_token = buffer->last_async_upload_token();
1923 if (async_token) {
1924 if (HasAsyncUploadTokenPassed(async_token)) {
1925 buffer_tracker_->Free(buffer);
1926 } else {
1927 detached_async_upload_memory_.push_back(
1928 std::make_pair(buffer->address(), async_token));
1929 buffer_tracker_->Unmanage(buffer);
1931 } else if (token) {
1932 if (helper_->HasTokenPassed(token))
1933 buffer_tracker_->Free(buffer);
1934 else
1935 buffer_tracker_->FreePendingToken(buffer, token);
1936 } else {
1937 buffer_tracker_->Free(buffer);
1940 buffer_tracker_->RemoveBuffer(buffer->id());
1943 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1944 GLenum target,
1945 const char* function_name,
1946 GLuint* buffer_id) {
1947 *buffer_id = 0;
1949 switch (target) {
1950 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1951 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1952 break;
1953 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1954 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1955 break;
1956 default:
1957 // Unknown target
1958 return false;
1960 if (!*buffer_id) {
1961 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1963 return true;
1966 BufferTracker::Buffer*
1967 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1968 GLuint buffer_id,
1969 const char* function_name,
1970 GLuint offset, GLsizei size) {
1971 DCHECK(buffer_id);
1972 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1973 if (!buffer) {
1974 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1975 return NULL;
1977 if (buffer->mapped()) {
1978 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1979 return NULL;
1981 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1982 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1983 return NULL;
1985 return buffer;
1988 void GLES2Implementation::CompressedTexImage2D(
1989 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1990 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1991 GPU_CLIENT_SINGLE_THREAD_CHECK();
1992 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1993 << GLES2Util::GetStringTextureTarget(target) << ", "
1994 << level << ", "
1995 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1996 << width << ", " << height << ", " << border << ", "
1997 << image_size << ", "
1998 << static_cast<const void*>(data) << ")");
1999 if (width < 0 || height < 0 || level < 0) {
2000 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
2001 return;
2003 if (border != 0) {
2004 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "border != 0");
2005 return;
2007 if (height == 0 || width == 0) {
2008 return;
2010 // If there's a pixel unpack buffer bound use it when issuing
2011 // CompressedTexImage2D.
2012 if (bound_pixel_unpack_transfer_buffer_id_) {
2013 GLuint offset = ToGLuint(data);
2014 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2015 bound_pixel_unpack_transfer_buffer_id_,
2016 "glCompressedTexImage2D", offset, image_size);
2017 if (buffer && buffer->shm_id() != -1) {
2018 helper_->CompressedTexImage2D(
2019 target, level, internalformat, width, height, image_size,
2020 buffer->shm_id(), buffer->shm_offset() + offset);
2021 buffer->set_last_usage_token(helper_->InsertToken());
2023 return;
2025 SetBucketContents(kResultBucketId, data, image_size);
2026 helper_->CompressedTexImage2DBucket(
2027 target, level, internalformat, width, height, kResultBucketId);
2028 // Free the bucket. This is not required but it does free up the memory.
2029 // and we don't have to wait for the result so from the client's perspective
2030 // it's cheap.
2031 helper_->SetBucketSize(kResultBucketId, 0);
2032 CheckGLError();
2035 void GLES2Implementation::CompressedTexSubImage2D(
2036 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2037 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
2038 GPU_CLIENT_SINGLE_THREAD_CHECK();
2039 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
2040 << GLES2Util::GetStringTextureTarget(target) << ", "
2041 << level << ", "
2042 << xoffset << ", " << yoffset << ", "
2043 << width << ", " << height << ", "
2044 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
2045 << image_size << ", "
2046 << static_cast<const void*>(data) << ")");
2047 if (width < 0 || height < 0 || level < 0) {
2048 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
2049 return;
2051 // If there's a pixel unpack buffer bound use it when issuing
2052 // CompressedTexSubImage2D.
2053 if (bound_pixel_unpack_transfer_buffer_id_) {
2054 GLuint offset = ToGLuint(data);
2055 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2056 bound_pixel_unpack_transfer_buffer_id_,
2057 "glCompressedTexSubImage2D", offset, image_size);
2058 if (buffer && buffer->shm_id() != -1) {
2059 helper_->CompressedTexSubImage2D(
2060 target, level, xoffset, yoffset, width, height, format, image_size,
2061 buffer->shm_id(), buffer->shm_offset() + offset);
2062 buffer->set_last_usage_token(helper_->InsertToken());
2063 CheckGLError();
2065 return;
2067 SetBucketContents(kResultBucketId, data, image_size);
2068 helper_->CompressedTexSubImage2DBucket(
2069 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
2070 // Free the bucket. This is not required but it does free up the memory.
2071 // and we don't have to wait for the result so from the client's perspective
2072 // it's cheap.
2073 helper_->SetBucketSize(kResultBucketId, 0);
2074 CheckGLError();
2077 void GLES2Implementation::CompressedTexImage3D(
2078 GLenum target, GLint level, GLenum internalformat, GLsizei width,
2079 GLsizei height, GLsizei depth, GLint border, GLsizei image_size,
2080 const void* data) {
2081 GPU_CLIENT_SINGLE_THREAD_CHECK();
2082 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage3D("
2083 << GLES2Util::GetStringTexture3DTarget(target) << ", " << level << ", "
2084 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
2085 << width << ", " << height << ", " << depth << ", " << border << ", "
2086 << image_size << ", " << static_cast<const void*>(data) << ")");
2087 if (width < 0 || height < 0 || depth < 0 || level < 0) {
2088 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "dimension < 0");
2089 return;
2091 if (border != 0) {
2092 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "border != 0");
2093 return;
2095 if (height == 0 || width == 0 || depth == 0) {
2096 return;
2098 // If there's a pixel unpack buffer bound use it when issuing
2099 // CompressedTexImage3D.
2100 if (bound_pixel_unpack_transfer_buffer_id_) {
2101 GLuint offset = ToGLuint(data);
2102 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2103 bound_pixel_unpack_transfer_buffer_id_,
2104 "glCompressedTexImage3D", offset, image_size);
2105 if (buffer && buffer->shm_id() != -1) {
2106 helper_->CompressedTexImage3D(
2107 target, level, internalformat, width, height, depth, image_size,
2108 buffer->shm_id(), buffer->shm_offset() + offset);
2109 buffer->set_last_usage_token(helper_->InsertToken());
2111 return;
2113 SetBucketContents(kResultBucketId, data, image_size);
2114 helper_->CompressedTexImage3DBucket(
2115 target, level, internalformat, width, height, depth, kResultBucketId);
2116 // Free the bucket. This is not required but it does free up the memory.
2117 // and we don't have to wait for the result so from the client's perspective
2118 // it's cheap.
2119 helper_->SetBucketSize(kResultBucketId, 0);
2120 CheckGLError();
2123 void GLES2Implementation::CompressedTexSubImage3D(
2124 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2125 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2126 GLsizei image_size, const void* data) {
2127 GPU_CLIENT_SINGLE_THREAD_CHECK();
2128 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage3D("
2129 << GLES2Util::GetStringTextureTarget(target) << ", "
2130 << level << ", "
2131 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2132 << width << ", " << height << ", " << depth << ", "
2133 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
2134 << image_size << ", "
2135 << static_cast<const void*>(data) << ")");
2136 if (width < 0 || height < 0 || depth < 0 || level < 0) {
2137 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage3D", "dimension < 0");
2138 return;
2140 // If there's a pixel unpack buffer bound use it when issuing
2141 // CompressedTexSubImage3D.
2142 if (bound_pixel_unpack_transfer_buffer_id_) {
2143 GLuint offset = ToGLuint(data);
2144 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2145 bound_pixel_unpack_transfer_buffer_id_,
2146 "glCompressedTexSubImage3D", offset, image_size);
2147 if (buffer && buffer->shm_id() != -1) {
2148 helper_->CompressedTexSubImage3D(
2149 target, level, xoffset, yoffset, zoffset,
2150 width, height, depth, format, image_size,
2151 buffer->shm_id(), buffer->shm_offset() + offset);
2152 buffer->set_last_usage_token(helper_->InsertToken());
2153 CheckGLError();
2155 return;
2157 SetBucketContents(kResultBucketId, data, image_size);
2158 helper_->CompressedTexSubImage3DBucket(
2159 target, level, xoffset, yoffset, zoffset, width, height, depth, format,
2160 kResultBucketId);
2161 // Free the bucket. This is not required but it does free up the memory.
2162 // and we don't have to wait for the result so from the client's perspective
2163 // it's cheap.
2164 helper_->SetBucketSize(kResultBucketId, 0);
2165 CheckGLError();
2168 namespace {
2170 void CopyRectToBuffer(
2171 const void* pixels,
2172 uint32 height,
2173 uint32 unpadded_row_size,
2174 uint32 pixels_padded_row_size,
2175 void* buffer,
2176 uint32 buffer_padded_row_size) {
2177 const int8* source = static_cast<const int8*>(pixels);
2178 int8* dest = static_cast<int8*>(buffer);
2179 if (pixels_padded_row_size != buffer_padded_row_size) {
2180 // the last row is copied unpadded at the end
2181 for (; height > 1; --height) {
2182 memcpy(dest, source, buffer_padded_row_size);
2183 dest += buffer_padded_row_size;
2184 source += pixels_padded_row_size;
2186 memcpy(dest, source, unpadded_row_size);
2187 } else {
2188 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
2189 memcpy(dest, source, size);
2193 } // anonymous namespace
2195 void GLES2Implementation::TexImage2D(
2196 GLenum target, GLint level, GLint internalformat, GLsizei width,
2197 GLsizei height, GLint border, GLenum format, GLenum type,
2198 const void* pixels) {
2199 GPU_CLIENT_SINGLE_THREAD_CHECK();
2200 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
2201 << GLES2Util::GetStringTextureTarget(target) << ", "
2202 << level << ", "
2203 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2204 << width << ", " << height << ", " << border << ", "
2205 << GLES2Util::GetStringTextureFormat(format) << ", "
2206 << GLES2Util::GetStringPixelType(type) << ", "
2207 << static_cast<const void*>(pixels) << ")");
2208 if (level < 0 || height < 0 || width < 0) {
2209 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
2210 return;
2212 if (border != 0) {
2213 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
2214 return;
2216 uint32 size;
2217 uint32 unpadded_row_size;
2218 uint32 padded_row_size;
2219 if (!GLES2Util::ComputeImageDataSizes(
2220 width, height, 1, format, type, unpack_alignment_, &size,
2221 &unpadded_row_size, &padded_row_size)) {
2222 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
2223 return;
2226 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
2227 if (bound_pixel_unpack_transfer_buffer_id_) {
2228 GLuint offset = ToGLuint(pixels);
2229 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2230 bound_pixel_unpack_transfer_buffer_id_,
2231 "glTexImage2D", offset, size);
2232 if (buffer && buffer->shm_id() != -1) {
2233 helper_->TexImage2D(
2234 target, level, internalformat, width, height, format, type,
2235 buffer->shm_id(), buffer->shm_offset() + offset);
2236 buffer->set_last_usage_token(helper_->InsertToken());
2237 CheckGLError();
2239 return;
2242 // If there's no data just issue TexImage2D
2243 if (!pixels) {
2244 helper_->TexImage2D(
2245 target, level, internalformat, width, height, format, type,
2246 0, 0);
2247 CheckGLError();
2248 return;
2251 // compute the advance bytes per row for the src pixels
2252 uint32 src_padded_row_size;
2253 if (unpack_row_length_ > 0) {
2254 if (!GLES2Util::ComputeImagePaddedRowSize(
2255 unpack_row_length_, format, type, unpack_alignment_,
2256 &src_padded_row_size)) {
2257 SetGLError(
2258 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2259 return;
2261 } else {
2262 src_padded_row_size = padded_row_size;
2265 // advance pixels pointer past the skip rows and skip pixels
2266 pixels = reinterpret_cast<const int8*>(pixels) +
2267 unpack_skip_rows_ * src_padded_row_size;
2268 if (unpack_skip_pixels_) {
2269 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2270 pixels = reinterpret_cast<const int8*>(pixels) +
2271 unpack_skip_pixels_ * group_size;
2274 // Check if we can send it all at once.
2275 int32_t shm_id = 0;
2276 uint32_t shm_offset = 0;
2277 void* buffer_pointer = nullptr;
2279 ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
2280 ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
2282 if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
2283 shm_id = transfer_alloc.shm_id();
2284 shm_offset = transfer_alloc.offset();
2285 buffer_pointer = transfer_alloc.address();
2286 } else {
2287 mapped_alloc.Reset(size);
2288 if (mapped_alloc.valid()) {
2289 transfer_alloc.Discard();
2291 mapped_alloc.SetFlushAfterRelease(true);
2292 shm_id = mapped_alloc.shm_id();
2293 shm_offset = mapped_alloc.offset();
2294 buffer_pointer = mapped_alloc.address();
2298 if (buffer_pointer) {
2299 CopyRectToBuffer(
2300 pixels, height, unpadded_row_size, src_padded_row_size,
2301 buffer_pointer, padded_row_size);
2302 helper_->TexImage2D(
2303 target, level, internalformat, width, height, format, type,
2304 shm_id, shm_offset);
2305 CheckGLError();
2306 return;
2309 // No, so send it using TexSubImage2D.
2310 helper_->TexImage2D(
2311 target, level, internalformat, width, height, format, type,
2312 0, 0);
2313 TexSubImage2DImpl(
2314 target, level, 0, 0, width, height, format, type, unpadded_row_size,
2315 pixels, src_padded_row_size, GL_TRUE, &transfer_alloc, padded_row_size);
2316 CheckGLError();
2319 void GLES2Implementation::TexImage3D(
2320 GLenum target, GLint level, GLint internalformat, GLsizei width,
2321 GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type,
2322 const void* pixels) {
2323 GPU_CLIENT_SINGLE_THREAD_CHECK();
2324 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D("
2325 << GLES2Util::GetStringTextureTarget(target) << ", "
2326 << level << ", "
2327 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2328 << width << ", " << height << ", " << depth << ", " << border << ", "
2329 << GLES2Util::GetStringTextureFormat(format) << ", "
2330 << GLES2Util::GetStringPixelType(type) << ", "
2331 << static_cast<const void*>(pixels) << ")");
2332 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2333 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "dimension < 0");
2334 return;
2336 if (border != 0) {
2337 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "border != 0");
2338 return;
2340 uint32 size;
2341 uint32 unpadded_row_size;
2342 uint32 padded_row_size;
2343 if (!GLES2Util::ComputeImageDataSizes(
2344 width, height, depth, format, type, unpack_alignment_, &size,
2345 &unpadded_row_size, &padded_row_size)) {
2346 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large");
2347 return;
2350 // If there's a pixel unpack buffer bound use it when issuing TexImage3D.
2351 if (bound_pixel_unpack_transfer_buffer_id_) {
2352 GLuint offset = ToGLuint(pixels);
2353 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2354 bound_pixel_unpack_transfer_buffer_id_,
2355 "glTexImage3D", offset, size);
2356 if (buffer && buffer->shm_id() != -1) {
2357 helper_->TexImage3D(
2358 target, level, internalformat, width, height, depth, format, type,
2359 buffer->shm_id(), buffer->shm_offset() + offset);
2360 buffer->set_last_usage_token(helper_->InsertToken());
2361 CheckGLError();
2363 return;
2366 // If there's no data just issue TexImage3D
2367 if (!pixels) {
2368 helper_->TexImage3D(
2369 target, level, internalformat, width, height, depth, format, type,
2370 0, 0);
2371 CheckGLError();
2372 return;
2375 // compute the advance bytes per row for the src pixels
2376 uint32 src_padded_row_size;
2377 if (unpack_row_length_ > 0) {
2378 if (!GLES2Util::ComputeImagePaddedRowSize(
2379 unpack_row_length_, format, type, unpack_alignment_,
2380 &src_padded_row_size)) {
2381 SetGLError(
2382 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2383 return;
2385 } else {
2386 src_padded_row_size = padded_row_size;
2388 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2390 // advance pixels pointer past the skip images/rows/pixels
2391 pixels = reinterpret_cast<const int8*>(pixels) +
2392 unpack_skip_images_ * src_padded_row_size * src_height +
2393 unpack_skip_rows_ * src_padded_row_size;
2394 if (unpack_skip_pixels_) {
2395 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2396 pixels = reinterpret_cast<const int8*>(pixels) +
2397 unpack_skip_pixels_ * group_size;
2400 // Check if we can send it all at once.
2401 int32_t shm_id = 0;
2402 uint32_t shm_offset = 0;
2403 void* buffer_pointer = nullptr;
2405 ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
2406 ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
2408 if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
2409 shm_id = transfer_alloc.shm_id();
2410 shm_offset = transfer_alloc.offset();
2411 buffer_pointer = transfer_alloc.address();
2412 } else {
2413 mapped_alloc.Reset(size);
2414 if (mapped_alloc.valid()) {
2415 transfer_alloc.Discard();
2417 mapped_alloc.SetFlushAfterRelease(true);
2418 shm_id = mapped_alloc.shm_id();
2419 shm_offset = mapped_alloc.offset();
2420 buffer_pointer = mapped_alloc.address();
2424 if (buffer_pointer) {
2425 for (GLsizei z = 0; z < depth; ++z) {
2426 // Only the last row of the last image is unpadded.
2427 uint32 src_unpadded_row_size =
2428 (z == depth - 1) ? unpadded_row_size : src_padded_row_size;
2429 CopyRectToBuffer(
2430 pixels, height, src_unpadded_row_size, src_padded_row_size,
2431 buffer_pointer, padded_row_size);
2432 pixels = reinterpret_cast<const int8*>(pixels) +
2433 src_padded_row_size * src_height;
2434 buffer_pointer = reinterpret_cast<int8*>(buffer_pointer) +
2435 padded_row_size * height;
2437 helper_->TexImage3D(
2438 target, level, internalformat, width, height, depth, format, type,
2439 shm_id, shm_offset);
2440 CheckGLError();
2441 return;
2444 // No, so send it using TexSubImage3D.
2445 helper_->TexImage3D(
2446 target, level, internalformat, width, height, depth, format, type,
2447 0, 0);
2448 TexSubImage3DImpl(
2449 target, level, 0, 0, 0, width, height, depth, format, type,
2450 unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &transfer_alloc,
2451 padded_row_size);
2452 CheckGLError();
2455 void GLES2Implementation::TexSubImage2D(
2456 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2457 GLsizei height, GLenum format, GLenum type, const void* pixels) {
2458 GPU_CLIENT_SINGLE_THREAD_CHECK();
2459 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
2460 << GLES2Util::GetStringTextureTarget(target) << ", "
2461 << level << ", "
2462 << xoffset << ", " << yoffset << ", "
2463 << width << ", " << height << ", "
2464 << GLES2Util::GetStringTextureFormat(format) << ", "
2465 << GLES2Util::GetStringPixelType(type) << ", "
2466 << static_cast<const void*>(pixels) << ")");
2468 if (level < 0 || height < 0 || width < 0) {
2469 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
2470 return;
2472 if (height == 0 || width == 0) {
2473 return;
2476 uint32 temp_size;
2477 uint32 unpadded_row_size;
2478 uint32 padded_row_size;
2479 if (!GLES2Util::ComputeImageDataSizes(
2480 width, height, 1, format, type, unpack_alignment_, &temp_size,
2481 &unpadded_row_size, &padded_row_size)) {
2482 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
2483 return;
2486 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2487 if (bound_pixel_unpack_transfer_buffer_id_) {
2488 GLuint offset = ToGLuint(pixels);
2489 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2490 bound_pixel_unpack_transfer_buffer_id_,
2491 "glTexSubImage2D", offset, temp_size);
2492 if (buffer && buffer->shm_id() != -1) {
2493 helper_->TexSubImage2D(
2494 target, level, xoffset, yoffset, width, height, format, type,
2495 buffer->shm_id(), buffer->shm_offset() + offset, false);
2496 buffer->set_last_usage_token(helper_->InsertToken());
2497 CheckGLError();
2499 return;
2502 // compute the advance bytes per row for the src pixels
2503 uint32 src_padded_row_size;
2504 if (unpack_row_length_ > 0) {
2505 if (!GLES2Util::ComputeImagePaddedRowSize(
2506 unpack_row_length_, format, type, unpack_alignment_,
2507 &src_padded_row_size)) {
2508 SetGLError(
2509 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2510 return;
2512 } else {
2513 src_padded_row_size = padded_row_size;
2516 // advance pixels pointer past the skip rows and skip pixels
2517 pixels = reinterpret_cast<const int8*>(pixels) +
2518 unpack_skip_rows_ * src_padded_row_size;
2519 if (unpack_skip_pixels_) {
2520 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2521 pixels = reinterpret_cast<const int8*>(pixels) +
2522 unpack_skip_pixels_ * group_size;
2525 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2526 TexSubImage2DImpl(
2527 target, level, xoffset, yoffset, width, height, format, type,
2528 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
2529 padded_row_size);
2530 CheckGLError();
2533 void GLES2Implementation::TexSubImage3D(
2534 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2535 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2536 const void* pixels) {
2537 GPU_CLIENT_SINGLE_THREAD_CHECK();
2538 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D("
2539 << GLES2Util::GetStringTextureTarget(target) << ", "
2540 << level << ", "
2541 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2542 << width << ", " << height << ", " << depth << ", "
2543 << GLES2Util::GetStringTextureFormat(format) << ", "
2544 << GLES2Util::GetStringPixelType(type) << ", "
2545 << static_cast<const void*>(pixels) << ")");
2547 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2548 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "dimension < 0");
2549 return;
2551 if (height == 0 || width == 0 || depth == 0) {
2552 return;
2555 uint32 temp_size;
2556 uint32 unpadded_row_size;
2557 uint32 padded_row_size;
2558 if (!GLES2Util::ComputeImageDataSizes(
2559 width, height, depth, format, type, unpack_alignment_, &temp_size,
2560 &unpadded_row_size, &padded_row_size)) {
2561 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "size to large");
2562 return;
2565 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2566 if (bound_pixel_unpack_transfer_buffer_id_) {
2567 GLuint offset = ToGLuint(pixels);
2568 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2569 bound_pixel_unpack_transfer_buffer_id_,
2570 "glTexSubImage3D", offset, temp_size);
2571 if (buffer && buffer->shm_id() != -1) {
2572 helper_->TexSubImage3D(
2573 target, level, xoffset, yoffset, zoffset, width, height, depth,
2574 format, type, buffer->shm_id(), buffer->shm_offset() + offset, false);
2575 buffer->set_last_usage_token(helper_->InsertToken());
2576 CheckGLError();
2578 return;
2581 // compute the advance bytes per row for the src pixels
2582 uint32 src_padded_row_size;
2583 if (unpack_row_length_ > 0) {
2584 if (!GLES2Util::ComputeImagePaddedRowSize(
2585 unpack_row_length_, format, type, unpack_alignment_,
2586 &src_padded_row_size)) {
2587 SetGLError(
2588 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2589 return;
2591 } else {
2592 src_padded_row_size = padded_row_size;
2594 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2596 // advance pixels pointer past the skip images/rows/pixels
2597 pixels = reinterpret_cast<const int8*>(pixels) +
2598 unpack_skip_images_ * src_padded_row_size * src_height +
2599 unpack_skip_rows_ * src_padded_row_size;
2600 if (unpack_skip_pixels_) {
2601 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2602 pixels = reinterpret_cast<const int8*>(pixels) +
2603 unpack_skip_pixels_ * group_size;
2606 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2607 TexSubImage3DImpl(
2608 target, level, xoffset, yoffset, zoffset, width, height, depth,
2609 format, type, unpadded_row_size, pixels, src_padded_row_size, GL_FALSE,
2610 &buffer, padded_row_size);
2611 CheckGLError();
2614 static GLint ComputeNumRowsThatFitInBuffer(
2615 uint32 padded_row_size, uint32 unpadded_row_size,
2616 unsigned int size, GLsizei remaining_rows) {
2617 DCHECK_GE(unpadded_row_size, 0u);
2618 if (padded_row_size == 0) {
2619 return 1;
2621 GLint num_rows = size / padded_row_size;
2622 if (num_rows + 1 == remaining_rows &&
2623 size - num_rows * padded_row_size >= unpadded_row_size) {
2624 num_rows++;
2626 return num_rows;
2629 void GLES2Implementation::TexSubImage2DImpl(
2630 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2631 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
2632 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
2633 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
2634 DCHECK(buffer);
2635 DCHECK_GE(level, 0);
2636 DCHECK_GT(height, 0);
2637 DCHECK_GT(width, 0);
2639 const int8* source = reinterpret_cast<const int8*>(pixels);
2640 // Transfer by rows.
2641 while (height) {
2642 unsigned int desired_size =
2643 buffer_padded_row_size * (height - 1) + unpadded_row_size;
2644 if (!buffer->valid() || buffer->size() == 0) {
2645 buffer->Reset(desired_size);
2646 if (!buffer->valid()) {
2647 return;
2651 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2652 buffer_padded_row_size, unpadded_row_size, buffer->size(), height);
2653 num_rows = std::min(num_rows, height);
2654 CopyRectToBuffer(
2655 source, num_rows, unpadded_row_size, pixels_padded_row_size,
2656 buffer->address(), buffer_padded_row_size);
2657 helper_->TexSubImage2D(
2658 target, level, xoffset, yoffset, width, num_rows, format, type,
2659 buffer->shm_id(), buffer->offset(), internal);
2660 buffer->Release();
2661 yoffset += num_rows;
2662 source += num_rows * pixels_padded_row_size;
2663 height -= num_rows;
2667 void GLES2Implementation::TexSubImage3DImpl(
2668 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei zoffset,
2669 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2670 uint32 unpadded_row_size, const void* pixels, uint32 pixels_padded_row_size,
2671 GLboolean internal, ScopedTransferBufferPtr* buffer,
2672 uint32 buffer_padded_row_size) {
2673 DCHECK(buffer);
2674 DCHECK_GE(level, 0);
2675 DCHECK_GT(height, 0);
2676 DCHECK_GT(width, 0);
2677 DCHECK_GT(depth, 0);
2678 const int8* source = reinterpret_cast<const int8*>(pixels);
2679 GLsizei total_rows = height * depth;
2680 GLint row_index = 0, depth_index = 0;
2681 while (total_rows) {
2682 // Each time, we either copy one or more images, or copy one or more rows
2683 // within a single image, depending on the buffer size limit.
2684 GLsizei max_rows;
2685 unsigned int desired_size;
2686 if (row_index > 0) {
2687 // We are in the middle of an image. Send the remaining of the image.
2688 max_rows = height - row_index;
2689 if (total_rows <= height) {
2690 // Last image, so last row is unpadded.
2691 desired_size = buffer_padded_row_size * (max_rows - 1) +
2692 unpadded_row_size;
2693 } else {
2694 desired_size = buffer_padded_row_size * max_rows;
2696 } else {
2697 // Send all the remaining data if possible.
2698 max_rows = total_rows;
2699 desired_size =
2700 buffer_padded_row_size * (max_rows - 1) + unpadded_row_size;
2702 if (!buffer->valid() || buffer->size() == 0) {
2703 buffer->Reset(desired_size);
2704 if (!buffer->valid()) {
2705 return;
2708 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2709 buffer_padded_row_size, unpadded_row_size, buffer->size(), total_rows);
2710 num_rows = std::min(num_rows, max_rows);
2711 GLint num_images = num_rows / height;
2712 GLsizei my_height, my_depth;
2713 if (num_images > 0) {
2714 num_rows = num_images * height;
2715 my_height = height;
2716 my_depth = num_images;
2717 } else {
2718 my_height = num_rows;
2719 my_depth = 1;
2722 if (num_images > 0) {
2723 int8* buffer_pointer = reinterpret_cast<int8*>(buffer->address());
2724 uint32 src_height =
2725 unpack_image_height_ > 0 ? unpack_image_height_ : height;
2726 uint32 image_size_dst = buffer_padded_row_size * height;
2727 uint32 image_size_src = pixels_padded_row_size * src_height;
2728 for (GLint ii = 0; ii < num_images; ++ii) {
2729 uint32 my_unpadded_row_size;
2730 if (total_rows == num_rows && ii + 1 == num_images)
2731 my_unpadded_row_size = unpadded_row_size;
2732 else
2733 my_unpadded_row_size = pixels_padded_row_size;
2734 CopyRectToBuffer(
2735 source + ii * image_size_src, my_height, my_unpadded_row_size,
2736 pixels_padded_row_size, buffer_pointer + ii * image_size_dst,
2737 buffer_padded_row_size);
2739 } else {
2740 uint32 my_unpadded_row_size;
2741 if (total_rows == num_rows)
2742 my_unpadded_row_size = unpadded_row_size;
2743 else
2744 my_unpadded_row_size = pixels_padded_row_size;
2745 CopyRectToBuffer(
2746 source, my_height, my_unpadded_row_size, pixels_padded_row_size,
2747 buffer->address(), buffer_padded_row_size);
2749 helper_->TexSubImage3D(
2750 target, level, xoffset, yoffset + row_index, zoffset + depth_index,
2751 width, my_height, my_depth,
2752 format, type, buffer->shm_id(), buffer->offset(), internal);
2753 buffer->Release();
2755 total_rows -= num_rows;
2756 if (total_rows > 0) {
2757 GLint num_image_paddings;
2758 if (num_images > 0) {
2759 DCHECK_EQ(row_index, 0);
2760 depth_index += num_images;
2761 num_image_paddings = num_images;
2762 } else {
2763 row_index = (row_index + my_height) % height;
2764 num_image_paddings = 0;
2765 if (my_height > 0 && row_index == 0) {
2766 depth_index++;
2767 num_image_paddings++;
2770 source += num_rows * pixels_padded_row_size;
2771 if (unpack_image_height_ > height && num_image_paddings > 0) {
2772 source += num_image_paddings * (unpack_image_height_ - height) *
2773 pixels_padded_row_size;
2779 bool GLES2Implementation::GetActiveAttribHelper(
2780 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2781 GLenum* type, char* name) {
2782 // Clear the bucket so if the command fails nothing will be in it.
2783 helper_->SetBucketSize(kResultBucketId, 0);
2784 typedef cmds::GetActiveAttrib::Result Result;
2785 Result* result = GetResultAs<Result*>();
2786 if (!result) {
2787 return false;
2789 // Set as failed so if the command fails we'll recover.
2790 result->success = false;
2791 helper_->GetActiveAttrib(program, index, kResultBucketId,
2792 GetResultShmId(), GetResultShmOffset());
2793 WaitForCmd();
2794 if (result->success) {
2795 if (size) {
2796 *size = result->size;
2798 if (type) {
2799 *type = result->type;
2801 if (length || name) {
2802 std::vector<int8> str;
2803 GetBucketContents(kResultBucketId, &str);
2804 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2805 std::max(static_cast<size_t>(0),
2806 str.size() - 1));
2807 if (length) {
2808 *length = max_size;
2810 if (name && bufsize > 0) {
2811 memcpy(name, &str[0], max_size);
2812 name[max_size] = '\0';
2816 return result->success != 0;
2819 void GLES2Implementation::GetActiveAttrib(
2820 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2821 GLenum* type, char* name) {
2822 GPU_CLIENT_SINGLE_THREAD_CHECK();
2823 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2824 << program << ", " << index << ", " << bufsize << ", "
2825 << static_cast<const void*>(length) << ", "
2826 << static_cast<const void*>(size) << ", "
2827 << static_cast<const void*>(type) << ", "
2828 << static_cast<const void*>(name) << ", ");
2829 if (bufsize < 0) {
2830 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
2831 return;
2833 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2834 bool success = share_group_->program_info_manager()->GetActiveAttrib(
2835 this, program, index, bufsize, length, size, type, name);
2836 if (success) {
2837 if (size) {
2838 GPU_CLIENT_LOG(" size: " << *size);
2840 if (type) {
2841 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2843 if (name) {
2844 GPU_CLIENT_LOG(" name: " << name);
2847 CheckGLError();
2850 bool GLES2Implementation::GetActiveUniformHelper(
2851 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2852 GLenum* type, char* name) {
2853 // Clear the bucket so if the command fails nothing will be in it.
2854 helper_->SetBucketSize(kResultBucketId, 0);
2855 typedef cmds::GetActiveUniform::Result Result;
2856 Result* result = GetResultAs<Result*>();
2857 if (!result) {
2858 return false;
2860 // Set as failed so if the command fails we'll recover.
2861 result->success = false;
2862 helper_->GetActiveUniform(program, index, kResultBucketId,
2863 GetResultShmId(), GetResultShmOffset());
2864 WaitForCmd();
2865 if (result->success) {
2866 if (size) {
2867 *size = result->size;
2869 if (type) {
2870 *type = result->type;
2872 if (length || name) {
2873 std::vector<int8> str;
2874 GetBucketContents(kResultBucketId, &str);
2875 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2876 std::max(static_cast<size_t>(0),
2877 str.size() - 1));
2878 if (length) {
2879 *length = max_size;
2881 if (name && bufsize > 0) {
2882 memcpy(name, &str[0], max_size);
2883 name[max_size] = '\0';
2887 return result->success != 0;
2890 void GLES2Implementation::GetActiveUniform(
2891 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2892 GLenum* type, char* name) {
2893 GPU_CLIENT_SINGLE_THREAD_CHECK();
2894 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2895 << program << ", " << index << ", " << bufsize << ", "
2896 << static_cast<const void*>(length) << ", "
2897 << static_cast<const void*>(size) << ", "
2898 << static_cast<const void*>(type) << ", "
2899 << static_cast<const void*>(name) << ", ");
2900 if (bufsize < 0) {
2901 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2902 return;
2904 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2905 bool success = share_group_->program_info_manager()->GetActiveUniform(
2906 this, program, index, bufsize, length, size, type, name);
2907 if (success) {
2908 if (size) {
2909 GPU_CLIENT_LOG(" size: " << *size);
2911 if (type) {
2912 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2914 if (name) {
2915 GPU_CLIENT_LOG(" name: " << name);
2918 CheckGLError();
2921 bool GLES2Implementation::GetActiveUniformBlockNameHelper(
2922 GLuint program, GLuint index, GLsizei bufsize,
2923 GLsizei* length, char* name) {
2924 DCHECK_LE(0, bufsize);
2925 // Clear the bucket so if the command fails nothing will be in it.
2926 helper_->SetBucketSize(kResultBucketId, 0);
2927 typedef cmds::GetActiveUniformBlockName::Result Result;
2928 Result* result = GetResultAs<Result*>();
2929 if (!result) {
2930 return false;
2932 // Set as failed so if the command fails we'll recover.
2933 *result = 0;
2934 helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
2935 GetResultShmId(), GetResultShmOffset());
2936 WaitForCmd();
2937 if (*result) {
2938 if (bufsize == 0) {
2939 if (length) {
2940 *length = 0;
2942 } else if (length || name) {
2943 std::vector<int8> str;
2944 GetBucketContents(kResultBucketId, &str);
2945 DCHECK_GT(str.size(), 0u);
2946 GLsizei max_size =
2947 std::min(bufsize, static_cast<GLsizei>(str.size())) - 1;
2948 if (length) {
2949 *length = max_size;
2951 if (name) {
2952 memcpy(name, &str[0], max_size);
2953 name[max_size] = '\0';
2957 return *result != 0;
2960 void GLES2Implementation::GetActiveUniformBlockName(
2961 GLuint program, GLuint index, GLsizei bufsize,
2962 GLsizei* length, char* name) {
2963 GPU_CLIENT_SINGLE_THREAD_CHECK();
2964 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
2965 << program << ", " << index << ", " << bufsize << ", "
2966 << static_cast<const void*>(length) << ", "
2967 << static_cast<const void*>(name) << ")");
2968 if (bufsize < 0) {
2969 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformBlockName", "bufsize < 0");
2970 return;
2972 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockName");
2973 bool success =
2974 share_group_->program_info_manager()->GetActiveUniformBlockName(
2975 this, program, index, bufsize, length, name);
2976 if (success) {
2977 if (name) {
2978 GPU_CLIENT_LOG(" name: " << name);
2981 CheckGLError();
2984 bool GLES2Implementation::GetActiveUniformBlockivHelper(
2985 GLuint program, GLuint index, GLenum pname, GLint* params) {
2986 typedef cmds::GetActiveUniformBlockiv::Result Result;
2987 Result* result = GetResultAs<Result*>();
2988 if (!result) {
2989 return false;
2991 result->SetNumResults(0);
2992 helper_->GetActiveUniformBlockiv(
2993 program, index, pname, GetResultShmId(), GetResultShmOffset());
2994 WaitForCmd();
2995 if (result->GetNumResults() > 0) {
2996 if (params) {
2997 result->CopyResult(params);
2999 GPU_CLIENT_LOG_CODE_BLOCK({
3000 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
3001 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3004 return true;
3006 return false;
3009 void GLES2Implementation::GetActiveUniformBlockiv(
3010 GLuint program, GLuint index, GLenum pname, GLint* params) {
3011 GPU_CLIENT_SINGLE_THREAD_CHECK();
3012 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
3013 << program << ", " << index << ", "
3014 << GLES2Util::GetStringUniformBlockParameter(pname) << ", "
3015 << static_cast<const void*>(params) << ")");
3016 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
3017 bool success =
3018 share_group_->program_info_manager()->GetActiveUniformBlockiv(
3019 this, program, index, pname, params);
3020 if (success) {
3021 if (params) {
3022 // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
3023 // be more than one value returned in params.
3024 GPU_CLIENT_LOG(" params: " << params[0]);
3027 CheckGLError();
3030 bool GLES2Implementation::GetActiveUniformsivHelper(
3031 GLuint program, GLsizei count, const GLuint* indices,
3032 GLenum pname, GLint* params) {
3033 typedef cmds::GetActiveUniformsiv::Result Result;
3034 Result* result = GetResultAs<Result*>();
3035 if (!result) {
3036 return false;
3038 result->SetNumResults(0);
3039 base::CheckedNumeric<size_t> bytes = static_cast<size_t>(count);
3040 bytes *= sizeof(GLuint);
3041 if (!bytes.IsValid()) {
3042 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count overflow");
3043 return false;
3045 SetBucketContents(kResultBucketId, indices, bytes.ValueOrDefault(0));
3046 helper_->GetActiveUniformsiv(
3047 program, kResultBucketId, pname, GetResultShmId(), GetResultShmOffset());
3048 WaitForCmd();
3049 bool success = result->GetNumResults() == count;
3050 if (success) {
3051 if (params) {
3052 result->CopyResult(params);
3054 GPU_CLIENT_LOG_CODE_BLOCK({
3055 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
3056 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3060 helper_->SetBucketSize(kResultBucketId, 0);
3061 return success;
3064 void GLES2Implementation::GetActiveUniformsiv(
3065 GLuint program, GLsizei count, const GLuint* indices,
3066 GLenum pname, GLint* params) {
3067 GPU_CLIENT_SINGLE_THREAD_CHECK();
3068 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv("
3069 << program << ", " << count << ", "
3070 << static_cast<const void*>(indices) << ", "
3071 << GLES2Util::GetStringUniformParameter(pname) << ", "
3072 << static_cast<const void*>(params) << ")");
3073 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
3074 if (count < 0) {
3075 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count < 0");
3076 return;
3078 bool success = share_group_->program_info_manager()->GetActiveUniformsiv(
3079 this, program, count, indices, pname, params);
3080 if (success) {
3081 if (params) {
3082 GPU_CLIENT_LOG_CODE_BLOCK({
3083 for (GLsizei ii = 0; ii < count; ++ii) {
3084 GPU_CLIENT_LOG(" " << ii << ": " << params[ii]);
3089 CheckGLError();
3092 void GLES2Implementation::GetAttachedShaders(
3093 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
3094 GPU_CLIENT_SINGLE_THREAD_CHECK();
3095 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
3096 << program << ", " << maxcount << ", "
3097 << static_cast<const void*>(count) << ", "
3098 << static_cast<const void*>(shaders) << ", ");
3099 if (maxcount < 0) {
3100 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
3101 return;
3103 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
3104 typedef cmds::GetAttachedShaders::Result Result;
3105 uint32 size = Result::ComputeSize(maxcount);
3106 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
3107 if (!result) {
3108 return;
3110 result->SetNumResults(0);
3111 helper_->GetAttachedShaders(
3112 program,
3113 transfer_buffer_->GetShmId(),
3114 transfer_buffer_->GetOffset(result),
3115 size);
3116 int32 token = helper_->InsertToken();
3117 WaitForCmd();
3118 if (count) {
3119 *count = result->GetNumResults();
3121 result->CopyResult(shaders);
3122 GPU_CLIENT_LOG_CODE_BLOCK({
3123 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3124 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3127 transfer_buffer_->FreePendingToken(result, token);
3128 CheckGLError();
3131 void GLES2Implementation::GetShaderPrecisionFormat(
3132 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
3133 GPU_CLIENT_SINGLE_THREAD_CHECK();
3134 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
3135 << GLES2Util::GetStringShaderType(shadertype) << ", "
3136 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
3137 << static_cast<const void*>(range) << ", "
3138 << static_cast<const void*>(precision) << ", ");
3139 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
3140 typedef cmds::GetShaderPrecisionFormat::Result Result;
3141 Result* result = GetResultAs<Result*>();
3142 if (!result) {
3143 return;
3146 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
3147 GLStaticState::ShaderPrecisionMap::iterator i =
3148 static_state_.shader_precisions.find(key);
3149 if (i != static_state_.shader_precisions.end()) {
3150 *result = i->second;
3151 } else {
3152 result->success = false;
3153 helper_->GetShaderPrecisionFormat(
3154 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
3155 WaitForCmd();
3156 if (result->success)
3157 static_state_.shader_precisions[key] = *result;
3160 if (result->success) {
3161 if (range) {
3162 range[0] = result->min_range;
3163 range[1] = result->max_range;
3164 GPU_CLIENT_LOG(" min_range: " << range[0]);
3165 GPU_CLIENT_LOG(" min_range: " << range[1]);
3167 if (precision) {
3168 precision[0] = result->precision;
3169 GPU_CLIENT_LOG(" min_range: " << precision[0]);
3172 CheckGLError();
3175 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
3176 const char* result = NULL;
3177 // Clears the bucket so if the command fails nothing will be in it.
3178 helper_->SetBucketSize(kResultBucketId, 0);
3179 helper_->GetString(name, kResultBucketId);
3180 std::string str;
3181 if (GetBucketAsString(kResultBucketId, &str)) {
3182 // Adds extensions implemented on client side only.
3183 switch (name) {
3184 case GL_EXTENSIONS:
3185 str += std::string(str.empty() ? "" : " ") +
3186 "GL_EXT_unpack_subimage "
3187 "GL_CHROMIUM_map_sub";
3188 if (capabilities_.image)
3189 str += " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
3190 if (capabilities_.future_sync_points)
3191 str += " GL_CHROMIUM_future_sync_point";
3192 break;
3193 default:
3194 break;
3197 // Because of WebGL the extensions can change. We have to cache each unique
3198 // result since we don't know when the client will stop referring to a
3199 // previous one it queries.
3200 GLStringMap::iterator it = gl_strings_.find(name);
3201 if (it == gl_strings_.end()) {
3202 std::set<std::string> strings;
3203 std::pair<GLStringMap::iterator, bool> insert_result =
3204 gl_strings_.insert(std::make_pair(name, strings));
3205 DCHECK(insert_result.second);
3206 it = insert_result.first;
3208 std::set<std::string>& string_set = it->second;
3209 std::set<std::string>::const_iterator sit = string_set.find(str);
3210 if (sit != string_set.end()) {
3211 result = sit->c_str();
3212 } else {
3213 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
3214 string_set.insert(str);
3215 DCHECK(insert_result.second);
3216 result = insert_result.first->c_str();
3219 return reinterpret_cast<const GLubyte*>(result);
3222 const GLubyte* GLES2Implementation::GetString(GLenum name) {
3223 GPU_CLIENT_SINGLE_THREAD_CHECK();
3224 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
3225 << GLES2Util::GetStringStringType(name) << ")");
3226 TRACE_EVENT0("gpu", "GLES2::GetString");
3227 const GLubyte* result = GetStringHelper(name);
3228 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
3229 CheckGLError();
3230 return result;
3233 bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
3234 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3235 GLenum* type, char* name) {
3236 // Clear the bucket so if the command fails nothing will be in it.
3237 helper_->SetBucketSize(kResultBucketId, 0);
3238 typedef cmds::GetTransformFeedbackVarying::Result Result;
3239 Result* result = GetResultAs<Result*>();
3240 if (!result) {
3241 return false;
3243 // Set as failed so if the command fails we'll recover.
3244 result->success = false;
3245 helper_->GetTransformFeedbackVarying(
3246 program, index, kResultBucketId, GetResultShmId(), GetResultShmOffset());
3247 WaitForCmd();
3248 if (result->success) {
3249 if (size) {
3250 *size = result->size;
3252 if (type) {
3253 *type = result->type;
3255 if (length || name) {
3256 std::vector<int8> str;
3257 GetBucketContents(kResultBucketId, &str);
3258 GLsizei max_size = std::min(bufsize, static_cast<GLsizei>(str.size()));
3259 if (max_size > 0) {
3260 --max_size;
3262 if (length) {
3263 *length = max_size;
3265 if (name) {
3266 if (max_size > 0) {
3267 memcpy(name, &str[0], max_size);
3268 name[max_size] = '\0';
3269 } else if (bufsize > 0) {
3270 name[0] = '\0';
3275 return result->success != 0;
3278 void GLES2Implementation::GetTransformFeedbackVarying(
3279 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3280 GLenum* type, char* name) {
3281 GPU_CLIENT_SINGLE_THREAD_CHECK();
3282 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
3283 << program << ", " << index << ", " << bufsize << ", "
3284 << static_cast<const void*>(length) << ", "
3285 << static_cast<const void*>(size) << ", "
3286 << static_cast<const void*>(type) << ", "
3287 << static_cast<const void*>(name) << ", ");
3288 if (bufsize < 0) {
3289 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVarying",
3290 "bufsize < 0");
3291 return;
3293 TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
3294 bool success =
3295 share_group_->program_info_manager()->GetTransformFeedbackVarying(
3296 this, program, index, bufsize, length, size, type, name);
3297 if (success) {
3298 if (size) {
3299 GPU_CLIENT_LOG(" size: " << *size);
3301 if (type) {
3302 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
3304 if (name) {
3305 GPU_CLIENT_LOG(" name: " << name);
3308 CheckGLError();
3311 void GLES2Implementation::GetUniformfv(
3312 GLuint program, GLint location, GLfloat* params) {
3313 GPU_CLIENT_SINGLE_THREAD_CHECK();
3314 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
3315 << program << ", " << location << ", "
3316 << static_cast<const void*>(params) << ")");
3317 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
3318 typedef cmds::GetUniformfv::Result Result;
3319 Result* result = GetResultAs<Result*>();
3320 if (!result) {
3321 return;
3323 result->SetNumResults(0);
3324 helper_->GetUniformfv(
3325 program, location, GetResultShmId(), GetResultShmOffset());
3326 WaitForCmd();
3327 result->CopyResult(params);
3328 GPU_CLIENT_LOG_CODE_BLOCK({
3329 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3330 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3333 CheckGLError();
3336 void GLES2Implementation::GetUniformiv(
3337 GLuint program, GLint location, GLint* params) {
3338 GPU_CLIENT_SINGLE_THREAD_CHECK();
3339 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
3340 << program << ", " << location << ", "
3341 << static_cast<const void*>(params) << ")");
3342 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
3343 typedef cmds::GetUniformiv::Result Result;
3344 Result* result = GetResultAs<Result*>();
3345 if (!result) {
3346 return;
3348 result->SetNumResults(0);
3349 helper_->GetUniformiv(
3350 program, location, GetResultShmId(), GetResultShmOffset());
3351 WaitForCmd();
3352 GetResultAs<cmds::GetUniformiv::Result*>()->CopyResult(params);
3353 GPU_CLIENT_LOG_CODE_BLOCK({
3354 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3355 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3358 CheckGLError();
3361 void GLES2Implementation::GetUniformuiv(
3362 GLuint program, GLint location, GLuint* params) {
3363 GPU_CLIENT_SINGLE_THREAD_CHECK();
3364 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformuiv("
3365 << program << ", " << location << ", "
3366 << static_cast<const void*>(params) << ")");
3367 TRACE_EVENT0("gpu", "GLES2::GetUniformuiv");
3368 typedef cmds::GetUniformuiv::Result Result;
3369 Result* result = GetResultAs<Result*>();
3370 if (!result) {
3371 return;
3373 result->SetNumResults(0);
3374 helper_->GetUniformuiv(
3375 program, location, GetResultShmId(), GetResultShmOffset());
3376 WaitForCmd();
3377 GetResultAs<cmds::GetUniformuiv::Result*>()->CopyResult(params);
3378 GPU_CLIENT_LOG_CODE_BLOCK({
3379 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3380 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3383 CheckGLError();
3386 void GLES2Implementation::ReadPixels(
3387 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
3388 GLenum type, void* pixels) {
3389 GPU_CLIENT_SINGLE_THREAD_CHECK();
3390 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
3391 << xoffset << ", " << yoffset << ", "
3392 << width << ", " << height << ", "
3393 << GLES2Util::GetStringReadPixelFormat(format) << ", "
3394 << GLES2Util::GetStringPixelType(type) << ", "
3395 << static_cast<const void*>(pixels) << ")");
3396 if (width < 0 || height < 0) {
3397 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
3398 return;
3400 if (width == 0 || height == 0) {
3401 return;
3404 // glReadPixel pads the size of each row of pixels by an amount specified by
3405 // glPixelStorei. So, we have to take that into account both in the fact that
3406 // the pixels returned from the ReadPixel command will include that padding
3407 // and that when we copy the results to the user's buffer we need to not
3408 // write those padding bytes but leave them as they are.
3410 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
3411 typedef cmds::ReadPixels::Result Result;
3413 int8* dest = reinterpret_cast<int8*>(pixels);
3414 uint32 temp_size;
3415 uint32 unpadded_row_size;
3416 uint32 padded_row_size;
3417 if (!GLES2Util::ComputeImageDataSizes(
3418 width, 2, 1, format, type, pack_alignment_, &temp_size,
3419 &unpadded_row_size, &padded_row_size)) {
3420 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
3421 return;
3424 if (bound_pixel_pack_transfer_buffer_id_) {
3425 GLuint offset = ToGLuint(pixels);
3426 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3427 bound_pixel_pack_transfer_buffer_id_,
3428 "glReadPixels", offset, padded_row_size * height);
3429 if (buffer && buffer->shm_id() != -1) {
3430 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
3431 buffer->shm_id(), buffer->shm_offset(),
3432 0, 0, true);
3433 CheckGLError();
3435 return;
3438 if (!pixels) {
3439 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
3440 return;
3443 // Transfer by rows.
3444 // The max rows we can transfer.
3445 while (height) {
3446 GLsizei desired_size = padded_row_size * (height - 1) + unpadded_row_size;
3447 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
3448 if (!buffer.valid()) {
3449 return;
3451 GLint num_rows = ComputeNumRowsThatFitInBuffer(
3452 padded_row_size, unpadded_row_size, buffer.size(), height);
3453 num_rows = std::min(num_rows, height);
3454 // NOTE: We must look up the address of the result area AFTER allocation
3455 // of the transfer buffer since the transfer buffer may be reallocated.
3456 Result* result = GetResultAs<Result*>();
3457 if (!result) {
3458 return;
3460 *result = 0; // mark as failed.
3461 helper_->ReadPixels(
3462 xoffset, yoffset, width, num_rows, format, type,
3463 buffer.shm_id(), buffer.offset(),
3464 GetResultShmId(), GetResultShmOffset(),
3465 false);
3466 WaitForCmd();
3467 if (*result != 0) {
3468 // when doing a y-flip we have to iterate through top-to-bottom chunks
3469 // of the dst. The service side handles reversing the rows within a
3470 // chunk.
3471 int8* rows_dst;
3472 if (pack_reverse_row_order_) {
3473 rows_dst = dest + (height - num_rows) * padded_row_size;
3474 } else {
3475 rows_dst = dest;
3477 // We have to copy 1 row at a time to avoid writing pad bytes.
3478 const int8* src = static_cast<const int8*>(buffer.address());
3479 for (GLint yy = 0; yy < num_rows; ++yy) {
3480 memcpy(rows_dst, src, unpadded_row_size);
3481 rows_dst += padded_row_size;
3482 src += padded_row_size;
3484 if (!pack_reverse_row_order_) {
3485 dest = rows_dst;
3488 // If it was not marked as successful exit.
3489 if (*result == 0) {
3490 return;
3492 yoffset += num_rows;
3493 height -= num_rows;
3495 CheckGLError();
3498 void GLES2Implementation::ActiveTexture(GLenum texture) {
3499 GPU_CLIENT_SINGLE_THREAD_CHECK();
3500 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
3501 << GLES2Util::GetStringEnum(texture) << ")");
3502 GLuint texture_index = texture - GL_TEXTURE0;
3503 if (texture_index >=
3504 static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
3505 SetGLErrorInvalidEnum(
3506 "glActiveTexture", texture, "texture");
3507 return;
3510 active_texture_unit_ = texture_index;
3511 helper_->ActiveTexture(texture);
3512 CheckGLError();
3515 void GLES2Implementation::GenBuffersHelper(
3516 GLsizei /* n */, const GLuint* /* buffers */) {
3519 void GLES2Implementation::GenFramebuffersHelper(
3520 GLsizei /* n */, const GLuint* /* framebuffers */) {
3523 void GLES2Implementation::GenRenderbuffersHelper(
3524 GLsizei /* n */, const GLuint* /* renderbuffers */) {
3527 void GLES2Implementation::GenTexturesHelper(
3528 GLsizei /* n */, const GLuint* /* textures */) {
3531 void GLES2Implementation::GenVertexArraysOESHelper(
3532 GLsizei n, const GLuint* arrays) {
3533 vertex_array_object_manager_->GenVertexArrays(n, arrays);
3536 void GLES2Implementation::GenQueriesEXTHelper(
3537 GLsizei /* n */, const GLuint* /* queries */) {
3540 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
3541 GLsizei /* n */,
3542 const GLuint* /* valuebuffers */) {
3545 void GLES2Implementation::GenSamplersHelper(
3546 GLsizei /* n */, const GLuint* /* samplers */) {
3549 void GLES2Implementation::GenTransformFeedbacksHelper(
3550 GLsizei /* n */, const GLuint* /* transformfeedbacks */) {
3553 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
3554 // generates a new resource. On newer versions of OpenGL they don't. The code
3555 // related to binding below will need to change if we switch to the new OpenGL
3556 // model. Specifically it assumes a bind will succeed which is always true in
3557 // the old model but possibly not true in the new model if another context has
3558 // deleted the resource.
3560 // NOTE #2: There is a bug in some BindXXXHelpers, that IDs might be marked as
3561 // used even when Bind has failed. However, the bug is minor compared to the
3562 // overhead & duplicated checking in client side.
3564 void GLES2Implementation::BindBufferHelper(
3565 GLenum target, GLuint buffer_id) {
3566 // TODO(gman): See note #1 above.
3567 bool changed = false;
3568 switch (target) {
3569 case GL_ARRAY_BUFFER:
3570 if (bound_array_buffer_ != buffer_id) {
3571 bound_array_buffer_ = buffer_id;
3572 changed = true;
3574 break;
3575 case GL_COPY_READ_BUFFER:
3576 if (bound_copy_read_buffer_ != buffer_id) {
3577 bound_copy_read_buffer_ = buffer_id;
3578 changed = true;
3580 break;
3581 case GL_COPY_WRITE_BUFFER:
3582 if (bound_copy_write_buffer_ != buffer_id) {
3583 bound_copy_write_buffer_ = buffer_id;
3584 changed = true;
3586 break;
3587 case GL_ELEMENT_ARRAY_BUFFER:
3588 changed = vertex_array_object_manager_->BindElementArray(buffer_id);
3589 break;
3590 case GL_PIXEL_PACK_BUFFER:
3591 if (bound_pixel_pack_buffer_ != buffer_id) {
3592 bound_pixel_pack_buffer_ = buffer_id;
3593 changed = true;
3595 break;
3596 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3597 bound_pixel_pack_transfer_buffer_id_ = buffer_id;
3598 break;
3599 case GL_PIXEL_UNPACK_BUFFER:
3600 if (bound_pixel_unpack_buffer_ != buffer_id) {
3601 bound_pixel_unpack_buffer_ = buffer_id;
3602 changed = true;
3604 break;
3605 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3606 bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
3607 break;
3608 case GL_TRANSFORM_FEEDBACK_BUFFER:
3609 if (bound_transform_feedback_buffer_ != buffer_id) {
3610 bound_transform_feedback_buffer_ = buffer_id;
3611 changed = true;
3613 break;
3614 case GL_UNIFORM_BUFFER:
3615 if (bound_uniform_buffer_ != buffer_id) {
3616 bound_uniform_buffer_ = buffer_id;
3617 changed = true;
3619 break;
3620 default:
3621 changed = true;
3622 break;
3624 // TODO(gman): See note #2 above.
3625 if (changed) {
3626 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3627 this, target, buffer_id, &GLES2Implementation::BindBufferStub);
3631 void GLES2Implementation::BindBufferStub(GLenum target, GLuint buffer) {
3632 helper_->BindBuffer(target, buffer);
3633 if (share_group_->bind_generates_resource())
3634 helper_->CommandBufferHelper::OrderingBarrier();
3637 void GLES2Implementation::BindBufferBaseHelper(
3638 GLenum target, GLuint index, GLuint buffer_id) {
3639 // TODO(zmo): See note #1 above.
3640 // TODO(zmo): See note #2 above.
3641 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3642 this, target, index, buffer_id, &GLES2Implementation::BindBufferBaseStub);
3645 void GLES2Implementation::BindBufferBaseStub(
3646 GLenum target, GLuint index, GLuint buffer) {
3647 helper_->BindBufferBase(target, index, buffer);
3648 if (share_group_->bind_generates_resource())
3649 helper_->CommandBufferHelper::Flush();
3652 void GLES2Implementation::BindBufferRangeHelper(
3653 GLenum target, GLuint index, GLuint buffer_id,
3654 GLintptr offset, GLsizeiptr size) {
3655 // TODO(zmo): See note #1 above.
3656 // TODO(zmo): See note #2 above.
3657 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3658 this, target, index, buffer_id, offset, size,
3659 &GLES2Implementation::BindBufferRangeStub);
3662 void GLES2Implementation::BindBufferRangeStub(
3663 GLenum target, GLuint index, GLuint buffer,
3664 GLintptr offset, GLsizeiptr size) {
3665 helper_->BindBufferRange(target, index, buffer, offset, size);
3666 if (share_group_->bind_generates_resource())
3667 helper_->CommandBufferHelper::Flush();
3670 void GLES2Implementation::BindFramebufferHelper(
3671 GLenum target, GLuint framebuffer) {
3672 // TODO(gman): See note #1 above.
3673 bool changed = false;
3674 switch (target) {
3675 case GL_FRAMEBUFFER:
3676 if (bound_framebuffer_ != framebuffer ||
3677 bound_read_framebuffer_ != framebuffer) {
3678 bound_framebuffer_ = framebuffer;
3679 bound_read_framebuffer_ = framebuffer;
3680 changed = true;
3682 break;
3683 case GL_READ_FRAMEBUFFER:
3684 if (!IsChromiumFramebufferMultisampleAvailable()) {
3685 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3686 return;
3688 if (bound_read_framebuffer_ != framebuffer) {
3689 bound_read_framebuffer_ = framebuffer;
3690 changed = true;
3692 break;
3693 case GL_DRAW_FRAMEBUFFER:
3694 if (!IsChromiumFramebufferMultisampleAvailable()) {
3695 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3696 return;
3698 if (bound_framebuffer_ != framebuffer) {
3699 bound_framebuffer_ = framebuffer;
3700 changed = true;
3702 break;
3703 default:
3704 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3705 return;
3708 if (changed) {
3709 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(
3710 this, target, framebuffer, &GLES2Implementation::BindFramebufferStub);
3714 void GLES2Implementation::BindFramebufferStub(GLenum target,
3715 GLuint framebuffer) {
3716 helper_->BindFramebuffer(target, framebuffer);
3717 if (share_group_->bind_generates_resource())
3718 helper_->CommandBufferHelper::OrderingBarrier();
3721 void GLES2Implementation::BindRenderbufferHelper(
3722 GLenum target, GLuint renderbuffer) {
3723 // TODO(gman): See note #1 above.
3724 bool changed = false;
3725 switch (target) {
3726 case GL_RENDERBUFFER:
3727 if (bound_renderbuffer_ != renderbuffer) {
3728 bound_renderbuffer_ = renderbuffer;
3729 changed = true;
3731 break;
3732 default:
3733 changed = true;
3734 break;
3736 // TODO(zmo): See note #2 above.
3737 if (changed) {
3738 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(
3739 this, target, renderbuffer,
3740 &GLES2Implementation::BindRenderbufferStub);
3744 void GLES2Implementation::BindRenderbufferStub(GLenum target,
3745 GLuint renderbuffer) {
3746 helper_->BindRenderbuffer(target, renderbuffer);
3747 if (share_group_->bind_generates_resource())
3748 helper_->CommandBufferHelper::OrderingBarrier();
3751 void GLES2Implementation::BindSamplerHelper(GLuint unit,
3752 GLuint sampler) {
3753 helper_->BindSampler(unit, sampler);
3756 void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
3757 // TODO(gman): See note #1 above.
3758 // TODO(gman): Change this to false once we figure out why it's failing
3759 // on daisy.
3760 bool changed = true;
3761 TextureUnit& unit = texture_units_[active_texture_unit_];
3762 switch (target) {
3763 case GL_TEXTURE_2D:
3764 if (unit.bound_texture_2d != texture) {
3765 unit.bound_texture_2d = texture;
3766 changed = true;
3768 break;
3769 case GL_TEXTURE_CUBE_MAP:
3770 if (unit.bound_texture_cube_map != texture) {
3771 unit.bound_texture_cube_map = texture;
3772 changed = true;
3774 break;
3775 case GL_TEXTURE_EXTERNAL_OES:
3776 if (unit.bound_texture_external_oes != texture) {
3777 unit.bound_texture_external_oes = texture;
3778 changed = true;
3780 break;
3781 default:
3782 changed = true;
3783 break;
3785 // TODO(gman): See note #2 above.
3786 if (changed) {
3787 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(
3788 this, target, texture, &GLES2Implementation::BindTextureStub);
3792 void GLES2Implementation::BindTextureStub(GLenum target, GLuint texture) {
3793 helper_->BindTexture(target, texture);
3794 if (share_group_->bind_generates_resource())
3795 helper_->CommandBufferHelper::OrderingBarrier();
3798 void GLES2Implementation::BindTransformFeedbackHelper(
3799 GLenum target, GLuint transformfeedback) {
3800 helper_->BindTransformFeedback(target, transformfeedback);
3803 void GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
3804 bool changed = false;
3805 if (vertex_array_object_manager_->BindVertexArray(array, &changed)) {
3806 if (changed) {
3807 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
3808 // because unlike other resources VertexArrayObject ids must
3809 // be generated by GenVertexArrays. A random id to Bind will not
3810 // generate a new object.
3811 helper_->BindVertexArrayOES(array);
3813 } else {
3814 SetGLError(
3815 GL_INVALID_OPERATION, "glBindVertexArrayOES",
3816 "id was not generated with glGenVertexArrayOES");
3820 void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
3821 GLuint valuebuffer) {
3822 bool changed = false;
3823 switch (target) {
3824 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
3825 if (bound_valuebuffer_ != valuebuffer) {
3826 bound_valuebuffer_ = valuebuffer;
3827 changed = true;
3829 break;
3830 default:
3831 changed = true;
3832 break;
3834 // TODO(gman): See note #2 above.
3835 if (changed) {
3836 GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(
3837 this, target, valuebuffer,
3838 &GLES2Implementation::BindValuebufferCHROMIUMStub);
3842 void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target,
3843 GLuint valuebuffer) {
3844 helper_->BindValuebufferCHROMIUM(target, valuebuffer);
3845 if (share_group_->bind_generates_resource())
3846 helper_->CommandBufferHelper::OrderingBarrier();
3849 void GLES2Implementation::UseProgramHelper(GLuint program) {
3850 if (current_program_ != program) {
3851 current_program_ = program;
3852 helper_->UseProgram(program);
3856 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
3857 return vertex_array_object_manager_->IsReservedId(id);
3860 void GLES2Implementation::DeleteBuffersHelper(
3861 GLsizei n, const GLuint* buffers) {
3862 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
3863 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
3864 SetGLError(
3865 GL_INVALID_VALUE,
3866 "glDeleteBuffers", "id not created by this context.");
3867 return;
3869 for (GLsizei ii = 0; ii < n; ++ii) {
3870 if (buffers[ii] == bound_array_buffer_) {
3871 bound_array_buffer_ = 0;
3873 if (buffers[ii] == bound_copy_read_buffer_) {
3874 bound_copy_read_buffer_ = 0;
3876 if (buffers[ii] == bound_copy_write_buffer_) {
3877 bound_copy_write_buffer_ = 0;
3879 if (buffers[ii] == bound_pixel_pack_buffer_) {
3880 bound_pixel_pack_buffer_ = 0;
3882 if (buffers[ii] == bound_pixel_unpack_buffer_) {
3883 bound_pixel_unpack_buffer_ = 0;
3885 if (buffers[ii] == bound_transform_feedback_buffer_) {
3886 bound_transform_feedback_buffer_ = 0;
3888 if (buffers[ii] == bound_uniform_buffer_) {
3889 bound_uniform_buffer_ = 0;
3891 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
3893 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
3894 if (buffer)
3895 RemoveTransferBuffer(buffer);
3897 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
3898 bound_pixel_unpack_transfer_buffer_id_ = 0;
3901 RemoveMappedBufferRangeById(buffers[ii]);
3905 void GLES2Implementation::DeleteBuffersStub(
3906 GLsizei n, const GLuint* buffers) {
3907 helper_->DeleteBuffersImmediate(n, buffers);
3911 void GLES2Implementation::DeleteFramebuffersHelper(
3912 GLsizei n, const GLuint* framebuffers) {
3913 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
3914 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
3915 SetGLError(
3916 GL_INVALID_VALUE,
3917 "glDeleteFramebuffers", "id not created by this context.");
3918 return;
3920 for (GLsizei ii = 0; ii < n; ++ii) {
3921 if (framebuffers[ii] == bound_framebuffer_) {
3922 bound_framebuffer_ = 0;
3924 if (framebuffers[ii] == bound_read_framebuffer_) {
3925 bound_read_framebuffer_ = 0;
3930 void GLES2Implementation::DeleteFramebuffersStub(
3931 GLsizei n, const GLuint* framebuffers) {
3932 helper_->DeleteFramebuffersImmediate(n, framebuffers);
3935 void GLES2Implementation::DeleteRenderbuffersHelper(
3936 GLsizei n, const GLuint* renderbuffers) {
3937 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
3938 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
3939 SetGLError(
3940 GL_INVALID_VALUE,
3941 "glDeleteRenderbuffers", "id not created by this context.");
3942 return;
3944 for (GLsizei ii = 0; ii < n; ++ii) {
3945 if (renderbuffers[ii] == bound_renderbuffer_) {
3946 bound_renderbuffer_ = 0;
3951 void GLES2Implementation::DeleteRenderbuffersStub(
3952 GLsizei n, const GLuint* renderbuffers) {
3953 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
3956 void GLES2Implementation::DeleteTexturesHelper(
3957 GLsizei n, const GLuint* textures) {
3958 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
3959 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
3960 SetGLError(
3961 GL_INVALID_VALUE,
3962 "glDeleteTextures", "id not created by this context.");
3963 return;
3965 for (GLsizei ii = 0; ii < n; ++ii) {
3966 for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
3967 ++tt) {
3968 TextureUnit& unit = texture_units_[tt];
3969 if (textures[ii] == unit.bound_texture_2d) {
3970 unit.bound_texture_2d = 0;
3972 if (textures[ii] == unit.bound_texture_cube_map) {
3973 unit.bound_texture_cube_map = 0;
3975 if (textures[ii] == unit.bound_texture_external_oes) {
3976 unit.bound_texture_external_oes = 0;
3982 void GLES2Implementation::DeleteTexturesStub(GLsizei n,
3983 const GLuint* textures) {
3984 helper_->DeleteTexturesImmediate(n, textures);
3987 void GLES2Implementation::DeleteVertexArraysOESHelper(
3988 GLsizei n, const GLuint* arrays) {
3989 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
3990 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
3991 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
3992 SetGLError(
3993 GL_INVALID_VALUE,
3994 "glDeleteVertexArraysOES", "id not created by this context.");
3995 return;
3999 void GLES2Implementation::DeleteVertexArraysOESStub(
4000 GLsizei n, const GLuint* arrays) {
4001 helper_->DeleteVertexArraysOESImmediate(n, arrays);
4004 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
4005 GLsizei n,
4006 const GLuint* valuebuffers) {
4007 if (!GetIdHandler(id_namespaces::kValuebuffers)
4008 ->FreeIds(this, n, valuebuffers,
4009 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
4010 SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
4011 "id not created by this context.");
4012 return;
4014 for (GLsizei ii = 0; ii < n; ++ii) {
4015 if (valuebuffers[ii] == bound_valuebuffer_) {
4016 bound_valuebuffer_ = 0;
4021 void GLES2Implementation::DeleteSamplersStub(
4022 GLsizei n, const GLuint* samplers) {
4023 helper_->DeleteSamplersImmediate(n, samplers);
4026 void GLES2Implementation::DeleteSamplersHelper(
4027 GLsizei n, const GLuint* samplers) {
4028 if (!GetIdHandler(id_namespaces::kSamplers)->FreeIds(
4029 this, n, samplers, &GLES2Implementation::DeleteSamplersStub)) {
4030 SetGLError(
4031 GL_INVALID_VALUE,
4032 "glDeleteSamplers", "id not created by this context.");
4033 return;
4037 void GLES2Implementation::DeleteTransformFeedbacksStub(
4038 GLsizei n, const GLuint* transformfeedbacks) {
4039 helper_->DeleteTransformFeedbacksImmediate(n, transformfeedbacks);
4042 void GLES2Implementation::DeleteTransformFeedbacksHelper(
4043 GLsizei n, const GLuint* transformfeedbacks) {
4044 if (!GetIdHandler(id_namespaces::kTransformFeedbacks)->FreeIds(
4045 this, n, transformfeedbacks,
4046 &GLES2Implementation::DeleteTransformFeedbacksStub)) {
4047 SetGLError(
4048 GL_INVALID_VALUE,
4049 "glDeleteTransformFeedbacks", "id not created by this context.");
4050 return;
4054 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
4055 GLsizei n,
4056 const GLuint* valuebuffers) {
4057 helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
4060 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
4061 GPU_CLIENT_SINGLE_THREAD_CHECK();
4062 GPU_CLIENT_LOG(
4063 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
4064 vertex_array_object_manager_->SetAttribEnable(index, false);
4065 helper_->DisableVertexAttribArray(index);
4066 CheckGLError();
4069 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
4070 GPU_CLIENT_SINGLE_THREAD_CHECK();
4071 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
4072 << index << ")");
4073 vertex_array_object_manager_->SetAttribEnable(index, true);
4074 helper_->EnableVertexAttribArray(index);
4075 CheckGLError();
4078 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
4079 GPU_CLIENT_SINGLE_THREAD_CHECK();
4080 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
4081 << GLES2Util::GetStringDrawMode(mode) << ", "
4082 << first << ", " << count << ")");
4083 if (count < 0) {
4084 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
4085 return;
4087 bool simulated = false;
4088 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
4089 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
4090 return;
4092 helper_->DrawArrays(mode, first, count);
4093 RestoreArrayBuffer(simulated);
4094 CheckGLError();
4097 void GLES2Implementation::GetVertexAttribfv(
4098 GLuint index, GLenum pname, GLfloat* params) {
4099 GPU_CLIENT_SINGLE_THREAD_CHECK();
4100 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
4101 << index << ", "
4102 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4103 << static_cast<const void*>(params) << ")");
4104 uint32 value = 0;
4105 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4106 *params = static_cast<GLfloat>(value);
4107 return;
4109 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
4110 typedef cmds::GetVertexAttribfv::Result Result;
4111 Result* result = GetResultAs<Result*>();
4112 if (!result) {
4113 return;
4115 result->SetNumResults(0);
4116 helper_->GetVertexAttribfv(
4117 index, pname, GetResultShmId(), GetResultShmOffset());
4118 WaitForCmd();
4119 result->CopyResult(params);
4120 GPU_CLIENT_LOG_CODE_BLOCK({
4121 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4122 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4125 CheckGLError();
4128 void GLES2Implementation::GetVertexAttribiv(
4129 GLuint index, GLenum pname, GLint* params) {
4130 GPU_CLIENT_SINGLE_THREAD_CHECK();
4131 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
4132 << index << ", "
4133 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4134 << static_cast<const void*>(params) << ")");
4135 uint32 value = 0;
4136 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4137 *params = static_cast<GLint>(value);
4138 return;
4140 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
4141 typedef cmds::GetVertexAttribiv::Result Result;
4142 Result* result = GetResultAs<Result*>();
4143 if (!result) {
4144 return;
4146 result->SetNumResults(0);
4147 helper_->GetVertexAttribiv(
4148 index, pname, GetResultShmId(), GetResultShmOffset());
4149 WaitForCmd();
4150 result->CopyResult(params);
4151 GPU_CLIENT_LOG_CODE_BLOCK({
4152 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4153 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4156 CheckGLError();
4159 void GLES2Implementation::GetVertexAttribIiv(
4160 GLuint index, GLenum pname, GLint* params) {
4161 GPU_CLIENT_SINGLE_THREAD_CHECK();
4162 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIiv("
4163 << index << ", "
4164 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4165 << static_cast<const void*>(params) << ")");
4166 uint32 value = 0;
4167 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4168 *params = static_cast<GLint>(value);
4169 return;
4171 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIiv");
4172 typedef cmds::GetVertexAttribiv::Result Result;
4173 Result* result = GetResultAs<Result*>();
4174 if (!result) {
4175 return;
4177 result->SetNumResults(0);
4178 helper_->GetVertexAttribIiv(
4179 index, pname, GetResultShmId(), GetResultShmOffset());
4180 WaitForCmd();
4181 result->CopyResult(params);
4182 GPU_CLIENT_LOG_CODE_BLOCK({
4183 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4184 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4187 CheckGLError();
4190 void GLES2Implementation::GetVertexAttribIuiv(
4191 GLuint index, GLenum pname, GLuint* params) {
4192 GPU_CLIENT_SINGLE_THREAD_CHECK();
4193 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIuiv("
4194 << index << ", "
4195 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4196 << static_cast<const void*>(params) << ")");
4197 uint32 value = 0;
4198 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4199 *params = static_cast<GLuint>(value);
4200 return;
4202 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIuiv");
4203 typedef cmds::GetVertexAttribiv::Result Result;
4204 Result* result = GetResultAs<Result*>();
4205 if (!result) {
4206 return;
4208 result->SetNumResults(0);
4209 helper_->GetVertexAttribIuiv(
4210 index, pname, GetResultShmId(), GetResultShmOffset());
4211 WaitForCmd();
4212 result->CopyResult(params);
4213 GPU_CLIENT_LOG_CODE_BLOCK({
4214 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4215 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4218 CheckGLError();
4221 GLenum GLES2Implementation::GetGraphicsResetStatusKHR() {
4222 GPU_CLIENT_SINGLE_THREAD_CHECK();
4223 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetGraphicsResetStatusKHR()");
4224 // If we can't make command buffers then the context is lost.
4225 if (gpu_control_->IsGpuChannelLost())
4226 return GL_UNKNOWN_CONTEXT_RESET_KHR;
4227 // Otherwise, check the command buffer if it is lost.
4228 if (helper_->IsContextLost()) {
4229 // TODO(danakj): We could GetLastState() off the CommandBuffer and return
4230 // the actual reason here if we cared to.
4231 return GL_UNKNOWN_CONTEXT_RESET_KHR;
4233 return GL_NO_ERROR;
4236 void GLES2Implementation::Swap() {
4237 SwapBuffers();
4240 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
4241 PostSubBufferCHROMIUM(
4242 sub_buffer.x(), sub_buffer.y(), sub_buffer.width(), sub_buffer.height());
4245 static GLenum GetGLESOverlayTransform(gfx::OverlayTransform plane_transform) {
4246 switch (plane_transform) {
4247 case gfx::OVERLAY_TRANSFORM_INVALID:
4248 break;
4249 case gfx::OVERLAY_TRANSFORM_NONE:
4250 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
4251 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
4252 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM;
4253 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
4254 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM;
4255 case gfx::OVERLAY_TRANSFORM_ROTATE_90:
4256 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM;
4257 case gfx::OVERLAY_TRANSFORM_ROTATE_180:
4258 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM;
4259 case gfx::OVERLAY_TRANSFORM_ROTATE_270:
4260 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM;
4262 NOTREACHED();
4263 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
4266 void GLES2Implementation::ScheduleOverlayPlane(
4267 int plane_z_order,
4268 gfx::OverlayTransform plane_transform,
4269 unsigned overlay_texture_id,
4270 const gfx::Rect& display_bounds,
4271 const gfx::RectF& uv_rect) {
4272 ScheduleOverlayPlaneCHROMIUM(plane_z_order,
4273 GetGLESOverlayTransform(plane_transform),
4274 overlay_texture_id,
4275 display_bounds.x(),
4276 display_bounds.y(),
4277 display_bounds.width(),
4278 display_bounds.height(),
4279 uv_rect.x(),
4280 uv_rect.y(),
4281 uv_rect.width(),
4282 uv_rect.height());
4285 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
4286 const char* feature) {
4287 GPU_CLIENT_SINGLE_THREAD_CHECK();
4288 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
4289 << feature << ")");
4290 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
4291 typedef cmds::EnableFeatureCHROMIUM::Result Result;
4292 Result* result = GetResultAs<Result*>();
4293 if (!result) {
4294 return false;
4296 *result = 0;
4297 SetBucketAsCString(kResultBucketId, feature);
4298 helper_->EnableFeatureCHROMIUM(
4299 kResultBucketId, GetResultShmId(), GetResultShmOffset());
4300 WaitForCmd();
4301 helper_->SetBucketSize(kResultBucketId, 0);
4302 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
4303 return *result != 0;
4306 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
4307 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
4308 GPU_CLIENT_SINGLE_THREAD_CHECK();
4309 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
4310 << target << ", " << offset << ", " << size << ", "
4311 << GLES2Util::GetStringEnum(access) << ")");
4312 // NOTE: target is NOT checked because the service will check it
4313 // and we don't know what targets are valid.
4314 if (access != GL_WRITE_ONLY) {
4315 SetGLErrorInvalidEnum(
4316 "glMapBufferSubDataCHROMIUM", access, "access");
4317 return NULL;
4319 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
4320 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
4321 return NULL;
4324 int32 shm_id;
4325 unsigned int shm_offset;
4326 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4327 if (!mem) {
4328 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
4329 return NULL;
4332 std::pair<MappedBufferMap::iterator, bool> result =
4333 mapped_buffers_.insert(std::make_pair(
4334 mem,
4335 MappedBuffer(
4336 access, shm_id, mem, shm_offset, target, offset, size)));
4337 DCHECK(result.second);
4338 GPU_CLIENT_LOG(" returned " << mem);
4339 return mem;
4342 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
4343 GPU_CLIENT_SINGLE_THREAD_CHECK();
4344 GPU_CLIENT_LOG(
4345 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
4346 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
4347 if (it == mapped_buffers_.end()) {
4348 SetGLError(
4349 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
4350 return;
4352 const MappedBuffer& mb = it->second;
4353 helper_->BufferSubData(
4354 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
4355 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
4356 mapped_buffers_.erase(it);
4357 CheckGLError();
4360 GLuint GLES2Implementation::GetBoundBufferHelper(GLenum target) {
4361 GLenum binding = GLES2Util::MapBufferTargetToBindingEnum(target);
4362 GLint id = 0;
4363 bool cached = GetHelper(binding, &id);
4364 DCHECK(cached);
4365 return static_cast<GLuint>(id);
4368 void GLES2Implementation::RemoveMappedBufferRangeByTarget(GLenum target) {
4369 GLuint buffer = GetBoundBufferHelper(target);
4370 RemoveMappedBufferRangeById(buffer);
4373 void GLES2Implementation::RemoveMappedBufferRangeById(GLuint buffer) {
4374 if (buffer > 0) {
4375 auto iter = mapped_buffer_range_map_.find(buffer);
4376 if (iter != mapped_buffer_range_map_.end() && iter->second.shm_memory) {
4377 mapped_memory_->FreePendingToken(
4378 iter->second.shm_memory, helper_->InsertToken());
4379 mapped_buffer_range_map_.erase(iter);
4384 void GLES2Implementation::ClearMappedBufferRangeMap() {
4385 for (auto& buffer_range : mapped_buffer_range_map_) {
4386 if (buffer_range.second.shm_memory) {
4387 mapped_memory_->FreePendingToken(
4388 buffer_range.second.shm_memory, helper_->InsertToken());
4391 mapped_buffer_range_map_.clear();
4394 void* GLES2Implementation::MapBufferRange(
4395 GLenum target, GLintptr offset, GLsizeiptr size, GLbitfield access) {
4396 GPU_CLIENT_SINGLE_THREAD_CHECK();
4397 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferRange("
4398 << GLES2Util::GetStringEnum(target) << ", " << offset << ", "
4399 << size << ", " << access << ")");
4400 if (!ValidateSize("glMapBufferRange", size) ||
4401 !ValidateOffset("glMapBufferRange", offset)) {
4402 return nullptr;
4405 int32 shm_id;
4406 unsigned int shm_offset;
4407 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4408 if (!mem) {
4409 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferRange", "out of memory");
4410 return nullptr;
4413 typedef cmds::MapBufferRange::Result Result;
4414 Result* result = GetResultAs<Result*>();
4415 *result = 0;
4416 helper_->MapBufferRange(target, offset, size, access, shm_id, shm_offset,
4417 GetResultShmId(), GetResultShmOffset());
4418 // TODO(zmo): For write only mode with MAP_INVALID_*_BIT, we should
4419 // consider an early return without WaitForCmd(). crbug.com/465804.
4420 WaitForCmd();
4421 if (*result) {
4422 const GLbitfield kInvalidateBits =
4423 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
4424 if ((access & kInvalidateBits) != 0) {
4425 // We do not read back from the buffer, therefore, we set the client
4426 // side memory to zero to avoid uninitialized data.
4427 memset(mem, 0, size);
4429 GLuint buffer = GetBoundBufferHelper(target);
4430 DCHECK_NE(0u, buffer);
4431 // glMapBufferRange fails on an already mapped buffer.
4432 DCHECK(mapped_buffer_range_map_.find(buffer) ==
4433 mapped_buffer_range_map_.end());
4434 auto iter = mapped_buffer_range_map_.insert(std::make_pair(
4435 buffer,
4436 MappedBuffer(access, shm_id, mem, shm_offset, target, offset, size)));
4437 DCHECK(iter.second);
4438 } else {
4439 mapped_memory_->Free(mem);
4440 mem = nullptr;
4443 GPU_CLIENT_LOG(" returned " << mem);
4444 CheckGLError();
4445 return mem;
4448 GLboolean GLES2Implementation::UnmapBuffer(GLenum target) {
4449 GPU_CLIENT_SINGLE_THREAD_CHECK();
4450 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapBuffer("
4451 << GLES2Util::GetStringEnum(target) << ")");
4452 switch (target) {
4453 case GL_ARRAY_BUFFER:
4454 case GL_ELEMENT_ARRAY_BUFFER:
4455 case GL_COPY_READ_BUFFER:
4456 case GL_COPY_WRITE_BUFFER:
4457 case GL_PIXEL_PACK_BUFFER:
4458 case GL_PIXEL_UNPACK_BUFFER:
4459 case GL_TRANSFORM_FEEDBACK_BUFFER:
4460 case GL_UNIFORM_BUFFER:
4461 break;
4462 default:
4463 SetGLError(GL_INVALID_ENUM, "glUnmapBuffer", "invalid target");
4464 return GL_FALSE;
4466 GLuint buffer = GetBoundBufferHelper(target);
4467 if (buffer == 0) {
4468 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "no buffer bound");
4469 return GL_FALSE;
4471 auto iter = mapped_buffer_range_map_.find(buffer);
4472 if (iter == mapped_buffer_range_map_.end()) {
4473 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "buffer is unmapped");
4474 return GL_FALSE;
4477 helper_->UnmapBuffer(target);
4478 RemoveMappedBufferRangeById(buffer);
4479 // TODO(zmo): There is a rare situation that data might be corrupted and
4480 // GL_FALSE should be returned. We lose context on that sitatuon, so we
4481 // don't have to WaitForCmd().
4482 GPU_CLIENT_LOG(" returned " << GL_TRUE);
4483 CheckGLError();
4484 return GL_TRUE;
4487 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
4488 GLenum target,
4489 GLint level,
4490 GLint xoffset,
4491 GLint yoffset,
4492 GLsizei width,
4493 GLsizei height,
4494 GLenum format,
4495 GLenum type,
4496 GLenum access) {
4497 GPU_CLIENT_SINGLE_THREAD_CHECK();
4498 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
4499 << target << ", " << level << ", "
4500 << xoffset << ", " << yoffset << ", "
4501 << width << ", " << height << ", "
4502 << GLES2Util::GetStringTextureFormat(format) << ", "
4503 << GLES2Util::GetStringPixelType(type) << ", "
4504 << GLES2Util::GetStringEnum(access) << ")");
4505 if (access != GL_WRITE_ONLY) {
4506 SetGLErrorInvalidEnum(
4507 "glMapTexSubImage2DCHROMIUM", access, "access");
4508 return NULL;
4510 // NOTE: target is NOT checked because the service will check it
4511 // and we don't know what targets are valid.
4512 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
4513 SetGLError(
4514 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
4515 return NULL;
4517 uint32 size;
4518 if (!GLES2Util::ComputeImageDataSizes(
4519 width, height, 1, format, type, unpack_alignment_, &size, NULL, NULL)) {
4520 SetGLError(
4521 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
4522 return NULL;
4524 int32 shm_id;
4525 unsigned int shm_offset;
4526 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4527 if (!mem) {
4528 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
4529 return NULL;
4532 std::pair<MappedTextureMap::iterator, bool> result =
4533 mapped_textures_.insert(std::make_pair(
4534 mem,
4535 MappedTexture(
4536 access, shm_id, mem, shm_offset,
4537 target, level, xoffset, yoffset, width, height, format, type)));
4538 DCHECK(result.second);
4539 GPU_CLIENT_LOG(" returned " << mem);
4540 return mem;
4543 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
4544 GPU_CLIENT_SINGLE_THREAD_CHECK();
4545 GPU_CLIENT_LOG(
4546 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
4547 MappedTextureMap::iterator it = mapped_textures_.find(mem);
4548 if (it == mapped_textures_.end()) {
4549 SetGLError(
4550 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
4551 return;
4553 const MappedTexture& mt = it->second;
4554 helper_->TexSubImage2D(
4555 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
4556 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
4557 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
4558 mapped_textures_.erase(it);
4559 CheckGLError();
4562 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
4563 float scale_factor) {
4564 GPU_CLIENT_SINGLE_THREAD_CHECK();
4565 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
4566 << width << ", " << height << ", " << scale_factor << ")");
4567 helper_->ResizeCHROMIUM(width, height, scale_factor);
4568 CheckGLError();
4571 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
4572 GPU_CLIENT_SINGLE_THREAD_CHECK();
4573 GPU_CLIENT_LOG("[" << GetLogPrefix()
4574 << "] glGetRequestableExtensionsCHROMIUM()");
4575 TRACE_EVENT0("gpu",
4576 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
4577 const char* result = NULL;
4578 // Clear the bucket so if the command fails nothing will be in it.
4579 helper_->SetBucketSize(kResultBucketId, 0);
4580 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
4581 std::string str;
4582 if (GetBucketAsString(kResultBucketId, &str)) {
4583 // The set of requestable extensions shrinks as we enable
4584 // them. Because we don't know when the client will stop referring
4585 // to a previous one it queries (see GetString) we need to cache
4586 // the unique results.
4587 std::set<std::string>::const_iterator sit =
4588 requestable_extensions_set_.find(str);
4589 if (sit != requestable_extensions_set_.end()) {
4590 result = sit->c_str();
4591 } else {
4592 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
4593 requestable_extensions_set_.insert(str);
4594 DCHECK(insert_result.second);
4595 result = insert_result.first->c_str();
4598 GPU_CLIENT_LOG(" returned " << result);
4599 return reinterpret_cast<const GLchar*>(result);
4602 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
4603 // with VirtualGL contexts.
4604 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
4605 GPU_CLIENT_SINGLE_THREAD_CHECK();
4606 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
4607 << extension << ")");
4608 SetBucketAsCString(kResultBucketId, extension);
4609 helper_->RequestExtensionCHROMIUM(kResultBucketId);
4610 helper_->SetBucketSize(kResultBucketId, 0);
4612 struct ExtensionCheck {
4613 const char* extension;
4614 ExtensionStatus* status;
4616 const ExtensionCheck checks[] = {
4618 "GL_ANGLE_pack_reverse_row_order",
4619 &angle_pack_reverse_row_order_status_,
4622 "GL_CHROMIUM_framebuffer_multisample",
4623 &chromium_framebuffer_multisample_,
4626 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
4627 for (size_t ii = 0; ii < kNumChecks; ++ii) {
4628 const ExtensionCheck& check = checks[ii];
4629 if (*check.status == kUnavailableExtensionStatus &&
4630 !strcmp(extension, check.extension)) {
4631 *check.status = kUnknownExtensionStatus;
4636 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
4637 GPU_CLIENT_SINGLE_THREAD_CHECK();
4638 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
4639 // Wait if this would add too many rate limit tokens.
4640 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
4641 helper_->WaitForToken(rate_limit_tokens_.front());
4642 rate_limit_tokens_.pop();
4644 rate_limit_tokens_.push(helper_->InsertToken());
4647 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
4648 GLuint program, std::vector<int8>* result) {
4649 DCHECK(result);
4650 // Clear the bucket so if the command fails nothing will be in it.
4651 helper_->SetBucketSize(kResultBucketId, 0);
4652 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
4653 GetBucketContents(kResultBucketId, result);
4656 void GLES2Implementation::GetProgramInfoCHROMIUM(
4657 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4658 GPU_CLIENT_SINGLE_THREAD_CHECK();
4659 if (bufsize < 0) {
4660 SetGLError(
4661 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
4662 return;
4664 if (size == NULL) {
4665 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
4666 return;
4668 // Make sure they've set size to 0 else the value will be undefined on
4669 // lost context.
4670 DCHECK_EQ(0, *size);
4671 std::vector<int8> result;
4672 GetProgramInfoCHROMIUMHelper(program, &result);
4673 if (result.empty()) {
4674 return;
4676 *size = result.size();
4677 if (!info) {
4678 return;
4680 if (static_cast<size_t>(bufsize) < result.size()) {
4681 SetGLError(GL_INVALID_OPERATION,
4682 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
4683 return;
4685 memcpy(info, &result[0], result.size());
4688 void GLES2Implementation::GetUniformBlocksCHROMIUMHelper(
4689 GLuint program, std::vector<int8>* result) {
4690 DCHECK(result);
4691 // Clear the bucket so if the command fails nothing will be in it.
4692 helper_->SetBucketSize(kResultBucketId, 0);
4693 helper_->GetUniformBlocksCHROMIUM(program, kResultBucketId);
4694 GetBucketContents(kResultBucketId, result);
4697 void GLES2Implementation::GetUniformBlocksCHROMIUM(
4698 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4699 GPU_CLIENT_SINGLE_THREAD_CHECK();
4700 if (bufsize < 0) {
4701 SetGLError(
4702 GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "bufsize less than 0.");
4703 return;
4705 if (size == NULL) {
4706 SetGLError(GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "size is null.");
4707 return;
4709 // Make sure they've set size to 0 else the value will be undefined on
4710 // lost context.
4711 DCHECK_EQ(0, *size);
4712 std::vector<int8> result;
4713 GetUniformBlocksCHROMIUMHelper(program, &result);
4714 if (result.empty()) {
4715 return;
4717 *size = result.size();
4718 if (!info) {
4719 return;
4721 if (static_cast<size_t>(bufsize) < result.size()) {
4722 SetGLError(GL_INVALID_OPERATION, "glGetUniformBlocksCHROMIUM",
4723 "bufsize is too small for result.");
4724 return;
4726 memcpy(info, &result[0], result.size());
4729 void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
4730 GLuint program, std::vector<int8>* result) {
4731 DCHECK(result);
4732 // Clear the bucket so if the command fails nothing will be in it.
4733 helper_->SetBucketSize(kResultBucketId, 0);
4734 helper_->GetUniformsES3CHROMIUM(program, kResultBucketId);
4735 GetBucketContents(kResultBucketId, result);
4738 void GLES2Implementation::GetUniformsES3CHROMIUM(
4739 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4740 GPU_CLIENT_SINGLE_THREAD_CHECK();
4741 if (bufsize < 0) {
4742 SetGLError(
4743 GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "bufsize less than 0.");
4744 return;
4746 if (size == NULL) {
4747 SetGLError(GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "size is null.");
4748 return;
4750 // Make sure they've set size to 0 else the value will be undefined on
4751 // lost context.
4752 DCHECK_EQ(0, *size);
4753 std::vector<int8> result;
4754 GetUniformsES3CHROMIUMHelper(program, &result);
4755 if (result.empty()) {
4756 return;
4758 *size = result.size();
4759 if (!info) {
4760 return;
4762 if (static_cast<size_t>(bufsize) < result.size()) {
4763 SetGLError(GL_INVALID_OPERATION,
4764 "glGetUniformsES3CHROMIUM", "bufsize is too small for result.");
4765 return;
4767 memcpy(info, &result[0], result.size());
4770 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
4771 GLuint program, std::vector<int8>* result) {
4772 DCHECK(result);
4773 // Clear the bucket so if the command fails nothing will be in it.
4774 helper_->SetBucketSize(kResultBucketId, 0);
4775 helper_->GetTransformFeedbackVaryingsCHROMIUM(program, kResultBucketId);
4776 GetBucketContents(kResultBucketId, result);
4779 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(
4780 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4781 GPU_CLIENT_SINGLE_THREAD_CHECK();
4782 if (bufsize < 0) {
4783 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4784 "bufsize less than 0.");
4785 return;
4787 if (size == NULL) {
4788 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4789 "size is null.");
4790 return;
4792 // Make sure they've set size to 0 else the value will be undefined on
4793 // lost context.
4794 DCHECK_EQ(0, *size);
4795 std::vector<int8> result;
4796 GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
4797 if (result.empty()) {
4798 return;
4800 *size = result.size();
4801 if (!info) {
4802 return;
4804 if (static_cast<size_t>(bufsize) < result.size()) {
4805 SetGLError(GL_INVALID_OPERATION, "glGetTransformFeedbackVaryingsCHROMIUM",
4806 "bufsize is too small for result.");
4807 return;
4809 memcpy(info, &result[0], result.size());
4812 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
4813 GPU_CLIENT_SINGLE_THREAD_CHECK();
4814 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
4815 << texture << ")");
4816 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
4817 helper_->CommandBufferHelper::Flush();
4818 return gpu_control_->CreateStreamTexture(texture);
4821 void GLES2Implementation::PostSubBufferCHROMIUM(
4822 GLint x, GLint y, GLint width, GLint height) {
4823 GPU_CLIENT_SINGLE_THREAD_CHECK();
4824 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
4825 << x << ", " << y << ", " << width << ", " << height << ")");
4826 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
4827 "width", width, "height", height);
4829 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
4830 swap_buffers_tokens_.push(helper_->InsertToken());
4831 helper_->PostSubBufferCHROMIUM(x, y, width, height);
4832 helper_->CommandBufferHelper::Flush();
4833 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
4834 helper_->WaitForToken(swap_buffers_tokens_.front());
4835 swap_buffers_tokens_.pop();
4839 void GLES2Implementation::DeleteQueriesEXTHelper(
4840 GLsizei n, const GLuint* queries) {
4841 for (GLsizei ii = 0; ii < n; ++ii) {
4842 query_tracker_->RemoveQuery(queries[ii]);
4843 query_id_allocator_->FreeID(queries[ii]);
4846 helper_->DeleteQueriesEXTImmediate(n, queries);
4849 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
4850 GPU_CLIENT_SINGLE_THREAD_CHECK();
4851 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
4853 // TODO(gman): To be spec compliant IDs from other contexts sharing
4854 // resources need to return true here even though you can't share
4855 // queries across contexts?
4856 return query_tracker_->GetQuery(id) != NULL;
4859 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
4860 GPU_CLIENT_SINGLE_THREAD_CHECK();
4861 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
4862 << GLES2Util::GetStringQueryTarget(target)
4863 << ", " << id << ")");
4865 switch (target) {
4866 case GL_COMMANDS_ISSUED_CHROMIUM:
4867 case GL_LATENCY_QUERY_CHROMIUM:
4868 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
4869 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
4870 case GL_GET_ERROR_QUERY_CHROMIUM:
4871 break;
4872 case GL_COMMANDS_COMPLETED_CHROMIUM:
4873 if (!capabilities_.sync_query) {
4874 SetGLError(
4875 GL_INVALID_OPERATION, "glBeginQueryEXT",
4876 "not enabled for commands completed queries");
4877 return;
4879 break;
4880 case GL_ANY_SAMPLES_PASSED:
4881 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
4882 if (!capabilities_.occlusion_query_boolean) {
4883 SetGLError(
4884 GL_INVALID_OPERATION, "glBeginQueryEXT",
4885 "not enabled for occlusion queries");
4886 return;
4888 break;
4889 case GL_TIME_ELAPSED_EXT:
4890 if (!capabilities_.timer_queries) {
4891 SetGLError(
4892 GL_INVALID_OPERATION, "glBeginQueryEXT",
4893 "not enabled for timing queries");
4894 return;
4896 break;
4897 default:
4898 SetGLError(
4899 GL_INVALID_ENUM, "glBeginQueryEXT", "unknown query target");
4900 return;
4903 // if any outstanding queries INV_OP
4904 if (query_tracker_->GetCurrentQuery(target)) {
4905 SetGLError(
4906 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
4907 return;
4910 if (id == 0) {
4911 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
4912 return;
4915 if (!query_id_allocator_->InUse(id)) {
4916 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "invalid id");
4917 return;
4920 if (query_tracker_->BeginQuery(id, target, this))
4921 CheckGLError();
4924 void GLES2Implementation::EndQueryEXT(GLenum target) {
4925 GPU_CLIENT_SINGLE_THREAD_CHECK();
4926 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
4927 << GLES2Util::GetStringQueryTarget(target) << ")");
4928 // Don't do anything if the context is lost.
4929 if (helper_->IsContextLost()) {
4930 return;
4933 if (query_tracker_->EndQuery(target, this))
4934 CheckGLError();
4937 void GLES2Implementation::QueryCounterEXT(GLuint id, GLenum target) {
4938 GPU_CLIENT_SINGLE_THREAD_CHECK();
4939 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] QueryCounterEXT("
4940 << id
4941 << ", " << GLES2Util::GetStringQueryTarget(target) << ")");
4943 switch (target) {
4944 case GL_TIMESTAMP_EXT:
4945 if (!capabilities_.timer_queries) {
4946 SetGLError(
4947 GL_INVALID_OPERATION, "glQueryCounterEXT",
4948 "not enabled for timing queries");
4949 return;
4951 break;
4952 default:
4953 SetGLError(
4954 GL_INVALID_ENUM, "glQueryCounterEXT", "unknown query target");
4955 return;
4958 if (id == 0) {
4959 SetGLError(GL_INVALID_OPERATION, "glQueryCounterEXT", "id is 0");
4960 return;
4963 if (!query_id_allocator_->InUse(id)) {
4964 SetGLError(GL_INVALID_OPERATION, "glQueryCounterEXT", "invalid id");
4965 return;
4968 if (query_tracker_->QueryCounter(id, target, this))
4969 CheckGLError();
4972 void GLES2Implementation::GetQueryivEXT(
4973 GLenum target, GLenum pname, GLint* params) {
4974 GPU_CLIENT_SINGLE_THREAD_CHECK();
4975 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
4976 << GLES2Util::GetStringQueryTarget(target) << ", "
4977 << GLES2Util::GetStringQueryParameter(pname) << ", "
4978 << static_cast<const void*>(params) << ")");
4979 if (pname == GL_QUERY_COUNTER_BITS_EXT) {
4980 // We convert all queries to CPU time so we support 64 bits.
4981 *params = 64;
4982 return;
4983 } else if (pname != GL_CURRENT_QUERY_EXT) {
4984 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
4985 return;
4987 QueryTracker::Query* query = query_tracker_->GetCurrentQuery(target);
4988 *params = query ? query->id() : 0;
4989 GPU_CLIENT_LOG(" " << *params);
4990 CheckGLError();
4993 void GLES2Implementation::GetQueryObjectuivEXT(
4994 GLuint id, GLenum pname, GLuint* params) {
4995 GLuint64 result = 0;
4996 if (GetQueryObjectValueHelper("glQueryObjectuivEXT", id, pname, &result))
4997 *params = base::saturated_cast<GLuint>(result);
5000 void GLES2Implementation::GetQueryObjectui64vEXT(
5001 GLuint id, GLenum pname, GLuint64* params) {
5002 GLuint64 result = 0;
5003 if (GetQueryObjectValueHelper("glQueryObjectui64vEXT", id, pname, &result))
5004 *params = result;
5007 void GLES2Implementation::DrawArraysInstancedANGLE(
5008 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
5009 GPU_CLIENT_SINGLE_THREAD_CHECK();
5010 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
5011 << GLES2Util::GetStringDrawMode(mode) << ", "
5012 << first << ", " << count << ", " << primcount << ")");
5013 if (count < 0) {
5014 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
5015 return;
5017 if (primcount < 0) {
5018 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
5019 return;
5021 if (primcount == 0) {
5022 return;
5024 bool simulated = false;
5025 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
5026 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
5027 &simulated)) {
5028 return;
5030 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
5031 RestoreArrayBuffer(simulated);
5032 CheckGLError();
5035 void GLES2Implementation::DrawElementsInstancedANGLE(
5036 GLenum mode, GLsizei count, GLenum type, const void* indices,
5037 GLsizei primcount) {
5038 GPU_CLIENT_SINGLE_THREAD_CHECK();
5039 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
5040 << GLES2Util::GetStringDrawMode(mode) << ", "
5041 << count << ", "
5042 << GLES2Util::GetStringIndexType(type) << ", "
5043 << static_cast<const void*>(indices) << ", "
5044 << primcount << ")");
5045 if (count < 0) {
5046 SetGLError(GL_INVALID_VALUE,
5047 "glDrawElementsInstancedANGLE", "count less than 0.");
5048 return;
5050 if (count == 0) {
5051 return;
5053 if (primcount < 0) {
5054 SetGLError(GL_INVALID_VALUE,
5055 "glDrawElementsInstancedANGLE", "primcount < 0");
5056 return;
5058 if (primcount == 0) {
5059 return;
5061 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
5062 !ValidateOffset("glDrawElementsInstancedANGLE",
5063 reinterpret_cast<GLintptr>(indices))) {
5064 return;
5066 GLuint offset = 0;
5067 bool simulated = false;
5068 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
5069 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
5070 indices, &offset, &simulated)) {
5071 return;
5073 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
5074 RestoreElementAndArrayBuffers(simulated);
5075 CheckGLError();
5078 void GLES2Implementation::GenMailboxCHROMIUM(
5079 GLbyte* mailbox) {
5080 GPU_CLIENT_SINGLE_THREAD_CHECK();
5081 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
5082 << static_cast<const void*>(mailbox) << ")");
5083 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
5085 gpu::Mailbox result = gpu::Mailbox::Generate();
5086 memcpy(mailbox, result.name, sizeof(result.name));
5089 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target,
5090 const GLbyte* data) {
5091 GPU_CLIENT_SINGLE_THREAD_CHECK();
5092 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
5093 << static_cast<const void*>(data) << ")");
5094 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5095 DCHECK(mailbox.Verify()) << "ProduceTextureCHROMIUM was passed a "
5096 "mailbox that was not generated by "
5097 "GenMailboxCHROMIUM.";
5098 helper_->ProduceTextureCHROMIUMImmediate(target, data);
5099 CheckGLError();
5102 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
5103 GLuint texture, GLenum target, const GLbyte* data) {
5104 GPU_CLIENT_SINGLE_THREAD_CHECK();
5105 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
5106 << static_cast<const void*>(data) << ")");
5107 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5108 DCHECK(mailbox.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
5109 "mailbox that was not generated by "
5110 "GenMailboxCHROMIUM.";
5111 helper_->ProduceTextureDirectCHROMIUMImmediate(texture, target, data);
5112 CheckGLError();
5115 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target,
5116 const GLbyte* data) {
5117 GPU_CLIENT_SINGLE_THREAD_CHECK();
5118 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
5119 << static_cast<const void*>(data) << ")");
5120 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5121 DCHECK(mailbox.Verify()) << "ConsumeTextureCHROMIUM was passed a "
5122 "mailbox that was not generated by "
5123 "GenMailboxCHROMIUM.";
5124 helper_->ConsumeTextureCHROMIUMImmediate(target, data);
5125 CheckGLError();
5128 GLuint GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
5129 GLenum target, const GLbyte* data) {
5130 GPU_CLIENT_SINGLE_THREAD_CHECK();
5131 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
5132 << static_cast<const void*>(data) << ")");
5133 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5134 DCHECK(mailbox.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
5135 "mailbox that was not generated by "
5136 "GenMailboxCHROMIUM.";
5137 GLuint client_id;
5138 GetIdHandler(id_namespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
5139 helper_->CreateAndConsumeTextureCHROMIUMImmediate(target,
5140 client_id, data);
5141 if (share_group_->bind_generates_resource())
5142 helper_->CommandBufferHelper::Flush();
5143 CheckGLError();
5144 return client_id;
5147 void GLES2Implementation::PushGroupMarkerEXT(
5148 GLsizei length, const GLchar* marker) {
5149 GPU_CLIENT_SINGLE_THREAD_CHECK();
5150 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
5151 << length << ", " << marker << ")");
5152 if (!marker) {
5153 marker = "";
5155 SetBucketAsString(
5156 kResultBucketId,
5157 (length ? std::string(marker, length) : std::string(marker)));
5158 helper_->PushGroupMarkerEXT(kResultBucketId);
5159 helper_->SetBucketSize(kResultBucketId, 0);
5160 debug_marker_manager_.PushGroup(
5161 length ? std::string(marker, length) : std::string(marker));
5164 void GLES2Implementation::InsertEventMarkerEXT(
5165 GLsizei length, const GLchar* marker) {
5166 GPU_CLIENT_SINGLE_THREAD_CHECK();
5167 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
5168 << length << ", " << marker << ")");
5169 if (!marker) {
5170 marker = "";
5172 SetBucketAsString(
5173 kResultBucketId,
5174 (length ? std::string(marker, length) : std::string(marker)));
5175 helper_->InsertEventMarkerEXT(kResultBucketId);
5176 helper_->SetBucketSize(kResultBucketId, 0);
5177 debug_marker_manager_.SetMarker(
5178 length ? std::string(marker, length) : std::string(marker));
5181 void GLES2Implementation::PopGroupMarkerEXT() {
5182 GPU_CLIENT_SINGLE_THREAD_CHECK();
5183 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
5184 helper_->PopGroupMarkerEXT();
5185 debug_marker_manager_.PopGroup();
5188 void GLES2Implementation::TraceBeginCHROMIUM(
5189 const char* category_name, const char* trace_name) {
5190 GPU_CLIENT_SINGLE_THREAD_CHECK();
5191 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
5192 << category_name << ", " << trace_name << ")");
5193 SetBucketAsCString(kResultBucketId, category_name);
5194 SetBucketAsCString(kResultBucketId + 1, trace_name);
5195 helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1);
5196 helper_->SetBucketSize(kResultBucketId, 0);
5197 helper_->SetBucketSize(kResultBucketId + 1, 0);
5198 current_trace_stack_++;
5201 void GLES2Implementation::TraceEndCHROMIUM() {
5202 GPU_CLIENT_SINGLE_THREAD_CHECK();
5203 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
5204 if (current_trace_stack_ == 0) {
5205 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
5206 "missing begin trace");
5207 return;
5209 helper_->TraceEndCHROMIUM();
5210 current_trace_stack_--;
5213 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
5214 GPU_CLIENT_SINGLE_THREAD_CHECK();
5215 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
5216 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
5217 switch (target) {
5218 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
5219 if (access != GL_READ_ONLY) {
5220 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
5221 return NULL;
5223 break;
5224 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
5225 if (access != GL_WRITE_ONLY) {
5226 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
5227 return NULL;
5229 break;
5230 default:
5231 SetGLError(
5232 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
5233 return NULL;
5235 GLuint buffer_id;
5236 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
5237 if (!buffer_id) {
5238 return NULL;
5240 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
5241 if (!buffer) {
5242 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
5243 return NULL;
5245 if (buffer->mapped()) {
5246 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
5247 return NULL;
5249 // Here we wait for previous transfer operations to be finished.
5250 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
5251 // with this method of synchronization. Until this is fixed,
5252 // MapBufferCHROMIUM will not block even if the transfer is not ready
5253 // for these calls.
5254 if (buffer->last_usage_token()) {
5255 helper_->WaitForToken(buffer->last_usage_token());
5256 buffer->set_last_usage_token(0);
5258 buffer->set_mapped(true);
5260 GPU_CLIENT_LOG(" returned " << buffer->address());
5261 CheckGLError();
5262 return buffer->address();
5265 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
5266 GPU_CLIENT_SINGLE_THREAD_CHECK();
5267 GPU_CLIENT_LOG(
5268 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
5269 GLuint buffer_id;
5270 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
5271 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
5273 if (!buffer_id) {
5274 return false;
5276 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
5277 if (!buffer) {
5278 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
5279 return false;
5281 if (!buffer->mapped()) {
5282 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
5283 return false;
5285 buffer->set_mapped(false);
5286 CheckGLError();
5287 return true;
5290 bool GLES2Implementation::EnsureAsyncUploadSync() {
5291 if (async_upload_sync_)
5292 return true;
5294 int32 shm_id;
5295 unsigned int shm_offset;
5296 void* mem = mapped_memory_->Alloc(sizeof(AsyncUploadSync),
5297 &shm_id,
5298 &shm_offset);
5299 if (!mem)
5300 return false;
5302 async_upload_sync_shm_id_ = shm_id;
5303 async_upload_sync_shm_offset_ = shm_offset;
5304 async_upload_sync_ = static_cast<AsyncUploadSync*>(mem);
5305 async_upload_sync_->Reset();
5307 return true;
5310 uint32 GLES2Implementation::NextAsyncUploadToken() {
5311 async_upload_token_++;
5312 if (async_upload_token_ == 0)
5313 async_upload_token_++;
5314 return async_upload_token_;
5317 void GLES2Implementation::PollAsyncUploads() {
5318 if (!async_upload_sync_)
5319 return;
5321 if (helper_->IsContextLost()) {
5322 DetachedAsyncUploadMemoryList::iterator it =
5323 detached_async_upload_memory_.begin();
5324 while (it != detached_async_upload_memory_.end()) {
5325 mapped_memory_->Free(it->first);
5326 it = detached_async_upload_memory_.erase(it);
5328 return;
5331 DetachedAsyncUploadMemoryList::iterator it =
5332 detached_async_upload_memory_.begin();
5333 while (it != detached_async_upload_memory_.end()) {
5334 if (HasAsyncUploadTokenPassed(it->second)) {
5335 mapped_memory_->Free(it->first);
5336 it = detached_async_upload_memory_.erase(it);
5337 } else {
5338 break;
5343 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
5344 // Free all completed unmanaged async uploads buffers.
5345 PollAsyncUploads();
5347 // Synchronously free rest of the unmanaged async upload buffers.
5348 if (!detached_async_upload_memory_.empty()) {
5349 WaitAllAsyncTexImage2DCHROMIUMHelper();
5350 WaitForCmd();
5351 PollAsyncUploads();
5355 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
5356 GLenum target, GLint level, GLenum internalformat, GLsizei width,
5357 GLsizei height, GLint border, GLenum format, GLenum type,
5358 const void* pixels) {
5359 GPU_CLIENT_SINGLE_THREAD_CHECK();
5360 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
5361 << GLES2Util::GetStringTextureTarget(target) << ", "
5362 << level << ", "
5363 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
5364 << width << ", " << height << ", " << border << ", "
5365 << GLES2Util::GetStringTextureFormat(format) << ", "
5366 << GLES2Util::GetStringPixelType(type) << ", "
5367 << static_cast<const void*>(pixels) << ")");
5368 if (level < 0 || height < 0 || width < 0) {
5369 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
5370 return;
5372 if (border != 0) {
5373 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
5374 return;
5376 uint32 size;
5377 uint32 unpadded_row_size;
5378 uint32 padded_row_size;
5379 if (!GLES2Util::ComputeImageDataSizes(
5380 width, height, 1, format, type, unpack_alignment_, &size,
5381 &unpadded_row_size, &padded_row_size)) {
5382 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
5383 return;
5386 // If there's no data/buffer just issue the AsyncTexImage2D
5387 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
5388 helper_->AsyncTexImage2DCHROMIUM(
5389 target, level, internalformat, width, height, format, type,
5390 0, 0, 0, 0, 0);
5391 return;
5394 if (!EnsureAsyncUploadSync()) {
5395 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
5396 return;
5399 // Otherwise, async uploads require a transfer buffer to be bound.
5400 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
5401 // the buffer before the transfer is finished. (Currently such
5402 // synchronization has to be handled manually.)
5403 GLuint offset = ToGLuint(pixels);
5404 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
5405 bound_pixel_unpack_transfer_buffer_id_,
5406 "glAsyncTexImage2DCHROMIUM", offset, size);
5407 if (buffer && buffer->shm_id() != -1) {
5408 uint32 async_token = NextAsyncUploadToken();
5409 buffer->set_last_async_upload_token(async_token);
5410 helper_->AsyncTexImage2DCHROMIUM(
5411 target, level, internalformat, width, height, format, type,
5412 buffer->shm_id(), buffer->shm_offset() + offset,
5413 async_token,
5414 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
5418 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
5419 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
5420 GLsizei height, GLenum format, GLenum type, const void* pixels) {
5421 GPU_CLIENT_SINGLE_THREAD_CHECK();
5422 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
5423 << GLES2Util::GetStringTextureTarget(target) << ", "
5424 << level << ", "
5425 << xoffset << ", " << yoffset << ", "
5426 << width << ", " << height << ", "
5427 << GLES2Util::GetStringTextureFormat(format) << ", "
5428 << GLES2Util::GetStringPixelType(type) << ", "
5429 << static_cast<const void*>(pixels) << ")");
5430 if (level < 0 || height < 0 || width < 0) {
5431 SetGLError(
5432 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
5433 return;
5436 uint32 size;
5437 uint32 unpadded_row_size;
5438 uint32 padded_row_size;
5439 if (!GLES2Util::ComputeImageDataSizes(
5440 width, height, 1, format, type, unpack_alignment_, &size,
5441 &unpadded_row_size, &padded_row_size)) {
5442 SetGLError(
5443 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
5444 return;
5447 if (!EnsureAsyncUploadSync()) {
5448 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
5449 return;
5452 // Async uploads require a transfer buffer to be bound.
5453 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
5454 // the buffer before the transfer is finished. (Currently such
5455 // synchronization has to be handled manually.)
5456 GLuint offset = ToGLuint(pixels);
5457 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
5458 bound_pixel_unpack_transfer_buffer_id_,
5459 "glAsyncTexSubImage2DCHROMIUM", offset, size);
5460 if (buffer && buffer->shm_id() != -1) {
5461 uint32 async_token = NextAsyncUploadToken();
5462 buffer->set_last_async_upload_token(async_token);
5463 helper_->AsyncTexSubImage2DCHROMIUM(
5464 target, level, xoffset, yoffset, width, height, format, type,
5465 buffer->shm_id(), buffer->shm_offset() + offset,
5466 async_token,
5467 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
5471 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
5472 GPU_CLIENT_SINGLE_THREAD_CHECK();
5473 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
5474 << GLES2Util::GetStringTextureTarget(target) << ")");
5475 helper_->WaitAsyncTexImage2DCHROMIUM(target);
5476 CheckGLError();
5479 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUMHelper() {
5480 helper_->WaitAllAsyncTexImage2DCHROMIUM();
5483 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
5484 GPU_CLIENT_SINGLE_THREAD_CHECK();
5485 GPU_CLIENT_LOG("[" << GetLogPrefix()
5486 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
5487 WaitAllAsyncTexImage2DCHROMIUMHelper();
5488 CheckGLError();
5491 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
5492 GPU_CLIENT_SINGLE_THREAD_CHECK();
5493 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
5494 helper_->CommandBufferHelper::Flush();
5495 return gpu_control_->InsertSyncPoint();
5498 GLuint GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
5499 GPU_CLIENT_SINGLE_THREAD_CHECK();
5500 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
5501 DCHECK(capabilities_.future_sync_points);
5502 return gpu_control_->InsertFutureSyncPoint();
5505 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point) {
5506 GPU_CLIENT_SINGLE_THREAD_CHECK();
5507 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
5508 << sync_point << ")");
5509 DCHECK(capabilities_.future_sync_points);
5510 helper_->CommandBufferHelper::Flush();
5511 gpu_control_->RetireSyncPoint(sync_point);
5514 namespace {
5516 bool ValidImageFormat(GLenum internalformat,
5517 const Capabilities& capabilities) {
5518 switch (internalformat) {
5519 case GL_ATC_RGB_AMD:
5520 case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
5521 return capabilities.texture_format_atc;
5522 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
5523 return capabilities.texture_format_dxt1;
5524 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
5525 return capabilities.texture_format_dxt5;
5526 case GL_ETC1_RGB8_OES:
5527 return capabilities.texture_format_etc1;
5528 case GL_R8:
5529 case GL_RGB:
5530 case GL_RGBA:
5531 case GL_BGRA_EXT:
5532 return true;
5533 default:
5534 return false;
5538 bool ValidImageUsage(GLenum usage) {
5539 switch (usage) {
5540 case GL_MAP_CHROMIUM:
5541 case GL_SCANOUT_CHROMIUM:
5542 return true;
5543 default:
5544 return false;
5548 } // namespace
5550 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer,
5551 GLsizei width,
5552 GLsizei height,
5553 GLenum internalformat) {
5554 if (width <= 0) {
5555 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
5556 return 0;
5559 if (height <= 0) {
5560 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
5561 return 0;
5564 if (!ValidImageFormat(internalformat, capabilities_)) {
5565 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "invalid format");
5566 return 0;
5569 int32_t image_id =
5570 gpu_control_->CreateImage(buffer, width, height, internalformat);
5571 if (image_id < 0) {
5572 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "image_id < 0");
5573 return 0;
5575 return image_id;
5578 GLuint GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer,
5579 GLsizei width,
5580 GLsizei height,
5581 GLenum internalformat) {
5582 GPU_CLIENT_SINGLE_THREAD_CHECK();
5583 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
5584 << ", " << height << ", "
5585 << GLES2Util::GetStringImageInternalFormat(internalformat)
5586 << ")");
5587 GLuint image_id =
5588 CreateImageCHROMIUMHelper(buffer, width, height, internalformat);
5589 CheckGLError();
5590 return image_id;
5593 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
5594 // Flush the command stream to make sure all pending commands
5595 // that may refer to the image_id are executed on the service side.
5596 helper_->CommandBufferHelper::Flush();
5597 gpu_control_->DestroyImage(image_id);
5600 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
5601 GPU_CLIENT_SINGLE_THREAD_CHECK();
5602 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
5603 << image_id << ")");
5604 DestroyImageCHROMIUMHelper(image_id);
5605 CheckGLError();
5608 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
5609 GLsizei width,
5610 GLsizei height,
5611 GLenum internalformat,
5612 GLenum usage) {
5613 if (width <= 0) {
5614 SetGLError(
5615 GL_INVALID_VALUE, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
5616 return 0;
5619 if (height <= 0) {
5620 SetGLError(GL_INVALID_VALUE,
5621 "glCreateGpuMemoryBufferImageCHROMIUM",
5622 "height <= 0");
5623 return 0;
5626 if (!ValidImageFormat(internalformat, capabilities_)) {
5627 SetGLError(GL_INVALID_VALUE,
5628 "glCreateGpuMemoryBufferImageCHROMIUM",
5629 "invalid format");
5630 return 0;
5633 if (!ValidImageUsage(usage)) {
5634 SetGLError(GL_INVALID_VALUE,
5635 "glCreateGpuMemoryBufferImageCHROMIUM",
5636 "invalid usage");
5637 return 0;
5640 // Flush the command stream to ensure ordering in case the newly
5641 // returned image_id has recently been in use with a different buffer.
5642 helper_->CommandBufferHelper::Flush();
5643 int32_t image_id = gpu_control_->CreateGpuMemoryBufferImage(
5644 width, height, internalformat, usage);
5645 if (image_id < 0) {
5646 SetGLError(GL_OUT_OF_MEMORY,
5647 "glCreateGpuMemoryBufferImageCHROMIUM",
5648 "image_id < 0");
5649 return 0;
5651 return image_id;
5654 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
5655 GLsizei width,
5656 GLsizei height,
5657 GLenum internalformat,
5658 GLenum usage) {
5659 GPU_CLIENT_SINGLE_THREAD_CHECK();
5660 GPU_CLIENT_LOG("[" << GetLogPrefix()
5661 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
5662 << ", " << height << ", "
5663 << GLES2Util::GetStringImageInternalFormat(internalformat)
5664 << ", " << GLES2Util::GetStringImageUsage(usage) << ")");
5665 GLuint image_id = CreateGpuMemoryBufferImageCHROMIUMHelper(
5666 width, height, internalformat, usage);
5667 CheckGLError();
5668 return image_id;
5671 bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
5672 if (size < 0) {
5673 SetGLError(GL_INVALID_VALUE, func, "size < 0");
5674 return false;
5676 if (!base::IsValueInRangeForNumericType<int32_t>(size)) {
5677 SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
5678 return false;
5680 return true;
5683 bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
5684 if (offset < 0) {
5685 SetGLError(GL_INVALID_VALUE, func, "offset < 0");
5686 return false;
5688 if (!base::IsValueInRangeForNumericType<int32_t>(offset)) {
5689 SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
5690 return false;
5692 return true;
5695 bool GLES2Implementation::GetSamplerParameterfvHelper(
5696 GLuint /* sampler */, GLenum /* pname */, GLfloat* /* params */) {
5697 // TODO(zmo): Implement client side caching.
5698 return false;
5701 bool GLES2Implementation::GetSamplerParameterivHelper(
5702 GLuint /* sampler */, GLenum /* pname */, GLint* /* params */) {
5703 // TODO(zmo): Implement client side caching.
5704 return false;
5707 bool GLES2Implementation::PackStringsToBucket(GLsizei count,
5708 const char* const* str,
5709 const GLint* length,
5710 const char* func_name) {
5711 DCHECK_LE(0, count);
5712 // Compute the total size.
5713 base::CheckedNumeric<size_t> total_size = count;
5714 total_size += 1;
5715 total_size *= sizeof(GLint);
5716 if (!total_size.IsValid()) {
5717 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5718 return false;
5720 size_t header_size = total_size.ValueOrDefault(0);
5721 std::vector<GLint> header(count + 1);
5722 header[0] = static_cast<GLint>(count);
5723 for (GLsizei ii = 0; ii < count; ++ii) {
5724 GLint len = 0;
5725 if (str[ii]) {
5726 len = (length && length[ii] >= 0)
5727 ? length[ii]
5728 : base::checked_cast<GLint>(strlen(str[ii]));
5730 total_size += len;
5731 total_size += 1; // NULL at the end of each char array.
5732 if (!total_size.IsValid()) {
5733 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5734 return false;
5736 header[ii + 1] = len;
5738 // Pack data into a bucket on the service.
5739 helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
5740 size_t offset = 0;
5741 for (GLsizei ii = 0; ii <= count; ++ii) {
5742 const char* src =
5743 (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
5744 base::CheckedNumeric<size_t> checked_size =
5745 (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
5746 if (ii > 0) {
5747 checked_size += 1; // NULL in the end.
5749 if (!checked_size.IsValid()) {
5750 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5751 return false;
5753 size_t size = checked_size.ValueOrDefault(0);
5754 while (size) {
5755 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
5756 if (!buffer.valid() || buffer.size() == 0) {
5757 SetGLError(GL_OUT_OF_MEMORY, func_name, "too large");
5758 return false;
5760 size_t copy_size = buffer.size();
5761 if (ii > 0 && buffer.size() == size)
5762 --copy_size;
5763 if (copy_size)
5764 memcpy(buffer.address(), src, copy_size);
5765 if (copy_size < buffer.size()) {
5766 // Append NULL in the end.
5767 DCHECK(copy_size + 1 == buffer.size());
5768 char* str = reinterpret_cast<char*>(buffer.address());
5769 str[copy_size] = 0;
5771 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
5772 buffer.shm_id(), buffer.offset());
5773 offset += buffer.size();
5774 src += buffer.size();
5775 size -= buffer.size();
5778 DCHECK_EQ(total_size.ValueOrDefault(0), offset);
5779 return true;
5782 void GLES2Implementation::UniformBlockBinding(GLuint program,
5783 GLuint index,
5784 GLuint binding) {
5785 GPU_CLIENT_SINGLE_THREAD_CHECK();
5786 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
5787 << ", " << index << ", " << binding << ")");
5788 share_group_->program_info_manager()->UniformBlockBinding(
5789 this, program, index, binding);
5790 helper_->UniformBlockBinding(program, index, binding);
5791 CheckGLError();
5794 GLenum GLES2Implementation::ClientWaitSync(
5795 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5796 GPU_CLIENT_SINGLE_THREAD_CHECK();
5797 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync
5798 << ", " << flags << ", " << timeout << ")");
5799 typedef cmds::ClientWaitSync::Result Result;
5800 Result* result = GetResultAs<Result*>();
5801 if (!result) {
5802 SetGLError(GL_OUT_OF_MEMORY, "ClientWaitSync", "");
5803 return GL_WAIT_FAILED;
5805 *result = GL_WAIT_FAILED;
5806 uint32_t v32_0 = 0, v32_1 = 0;
5807 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5808 helper_->ClientWaitSync(
5809 ToGLuint(sync), flags, v32_0, v32_1,
5810 GetResultShmId(), GetResultShmOffset());
5811 WaitForCmd();
5812 GPU_CLIENT_LOG("returned " << *result);
5813 CheckGLError();
5814 return *result;
5817 void GLES2Implementation::WaitSync(
5818 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5819 GPU_CLIENT_SINGLE_THREAD_CHECK();
5820 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync << ", "
5821 << flags << ", " << timeout << ")");
5822 uint32_t v32_0 = 0, v32_1 = 0;
5823 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5824 helper_->WaitSync(ToGLuint(sync), flags, v32_0, v32_1);
5825 CheckGLError();
5828 void GLES2Implementation::GetInternalformativ(
5829 GLenum target, GLenum format, GLenum pname,
5830 GLsizei buf_size, GLint* params) {
5831 GPU_CLIENT_SINGLE_THREAD_CHECK();
5832 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
5833 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetInternalformativ("
5834 << GLES2Util::GetStringRenderBufferTarget(target) << ", "
5835 << GLES2Util::GetStringRenderBufferFormat(format) << ", "
5836 << GLES2Util::GetStringInternalFormatParameter(pname)
5837 << ", " << buf_size << ", "
5838 << static_cast<const void*>(params) << ")");
5839 if (buf_size < 0) {
5840 SetGLError(GL_INVALID_VALUE, "glGetInternalformativ", "bufSize < 0");
5841 return;
5843 TRACE_EVENT0("gpu", "GLES2Implementation::GetInternalformativ");
5844 if (GetInternalformativHelper(target, format, pname, buf_size, params)) {
5845 return;
5847 typedef cmds::GetInternalformativ::Result Result;
5848 Result* result = GetResultAs<Result*>();
5849 if (!result) {
5850 return;
5852 result->SetNumResults(0);
5853 helper_->GetInternalformativ(target, format, pname,
5854 GetResultShmId(), GetResultShmOffset());
5855 WaitForCmd();
5856 GPU_CLIENT_LOG_CODE_BLOCK({
5857 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
5858 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
5861 if (buf_size > 0 && params) {
5862 GLint* data = result->GetData();
5863 if (buf_size >= result->GetNumResults()) {
5864 buf_size = result->GetNumResults();
5866 for (GLsizei ii = 0; ii < buf_size; ++ii) {
5867 params[ii] = data[ii];
5870 CheckGLError();
5873 GLuint GLES2Implementation::GenPathsCHROMIUM(GLsizei range) {
5874 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenPathsCHROMIUM(" << range
5875 << ")");
5876 GPU_CLIENT_SINGLE_THREAD_CHECK();
5877 static const char kFunctionName[] = "glGenPathsCHROMIUM";
5878 if (range < 0) {
5879 SetGLError(GL_INVALID_VALUE, kFunctionName, "range < 0");
5880 return 0;
5882 if (!base::IsValueInRangeForNumericType<int32_t>(range)) {
5883 SetGLError(GL_INVALID_OPERATION, kFunctionName, "range more than 32-bit");
5884 return 0;
5886 if (range == 0)
5887 return 0;
5889 GLuint first_client_id = 0;
5890 GetRangeIdHandler(id_namespaces::kPaths)
5891 ->MakeIdRange(this, range, &first_client_id);
5893 if (first_client_id == 0) {
5894 // Ran out of id space. Is not specified to raise any gl errors.
5895 return 0;
5898 helper_->GenPathsCHROMIUM(first_client_id, range);
5900 GPU_CLIENT_LOG_CODE_BLOCK({
5901 for (GLsizei i = 0; i < range; ++i) {
5902 GPU_CLIENT_LOG(" " << i << ": " << (first_client_id + i));
5905 CheckGLError();
5906 return first_client_id;
5909 void GLES2Implementation::DeletePathsCHROMIUM(GLuint first_client_id,
5910 GLsizei range) {
5911 GPU_CLIENT_SINGLE_THREAD_CHECK();
5912 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeletePathsCHROMIUM("
5913 << first_client_id << ", " << range << ")");
5914 static const char kFunctionName[] = "glDeletePathsCHROMIUM";
5916 if (range < 0) {
5917 SetGLError(GL_INVALID_VALUE, kFunctionName, "range < 0");
5918 return;
5920 if (!base::IsValueInRangeForNumericType<int32_t>(range)) {
5921 SetGLError(GL_INVALID_OPERATION, kFunctionName, "range more than 32-bit");
5922 return;
5924 if (range == 0)
5925 return;
5927 GLuint last_client_id;
5928 if (!SafeAddUint32(first_client_id, range - 1, &last_client_id)) {
5929 SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow");
5930 return;
5933 GetRangeIdHandler(id_namespaces::kPaths)
5934 ->FreeIdRange(this, first_client_id, range,
5935 &GLES2Implementation::DeletePathsCHROMIUMStub);
5936 CheckGLError();
5939 void GLES2Implementation::DeletePathsCHROMIUMStub(GLuint first_client_id,
5940 GLsizei range) {
5941 helper_->DeletePathsCHROMIUM(first_client_id, range);
5944 void GLES2Implementation::PathCommandsCHROMIUM(GLuint path,
5945 GLsizei num_commands,
5946 const GLubyte* commands,
5947 GLsizei num_coords,
5948 GLenum coord_type,
5949 const void* coords) {
5950 GPU_CLIENT_SINGLE_THREAD_CHECK();
5951 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPathCommandsCHROMIUM(" << path
5952 << ", " << num_commands << ", " << commands << ", "
5953 << num_coords << ", " << coords << ")");
5954 static const char kFunctionName[] = "glPathCommandsCHROMIUM";
5955 if (path == 0) {
5956 SetGLError(GL_INVALID_VALUE, kFunctionName, "invalid path object");
5957 return;
5959 if (num_commands < 0) {
5960 SetGLError(GL_INVALID_VALUE, kFunctionName, "numCommands < 0");
5961 return;
5963 if (num_commands != 0 && !commands) {
5964 SetGLError(GL_INVALID_VALUE, kFunctionName, "missing commands");
5965 return;
5967 if (num_coords < 0) {
5968 SetGLError(GL_INVALID_VALUE, kFunctionName, "numCoords < 0");
5969 return;
5971 if (num_coords != 0 && !coords) {
5972 SetGLError(GL_INVALID_VALUE, kFunctionName, "missing coords");
5973 return;
5975 uint32 coord_type_size = GLES2Util::GetGLTypeSizeForPathCoordType(coord_type);
5976 if (coord_type_size == 0) {
5977 SetGLError(GL_INVALID_ENUM, kFunctionName, "invalid coordType");
5978 return;
5980 if (num_commands == 0) {
5981 // No commands must mean no coords, thus nothing to memcpy. Let
5982 // the service validate the call. Validate coord_type above, so
5983 // that the parameters will be checked the in the same order
5984 // regardless of num_commands.
5985 helper_->PathCommandsCHROMIUM(path, num_commands, 0, 0, num_coords,
5986 coord_type, 0, 0);
5987 CheckGLError();
5988 return;
5991 uint32 coords_size;
5992 if (!SafeMultiplyUint32(num_coords, coord_type_size, &coords_size)) {
5993 SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow");
5994 return;
5997 uint32 required_buffer_size;
5998 if (!SafeAddUint32(coords_size, num_commands, &required_buffer_size)) {
5999 SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow");
6000 return;
6003 ScopedTransferBufferPtr buffer(required_buffer_size, helper_,
6004 transfer_buffer_);
6005 if (!buffer.valid() || buffer.size() < required_buffer_size) {
6006 SetGLError(GL_OUT_OF_MEMORY, kFunctionName, "too large");
6007 return;
6010 uint32 coords_shm_id = 0;
6011 uint32 coords_shm_offset = 0;
6012 // Copy coords first because they need more strict alignment.
6013 if (coords_size > 0) {
6014 unsigned char* coords_addr = static_cast<unsigned char*>(buffer.address());
6015 memcpy(coords_addr, coords, coords_size);
6016 coords_shm_id = buffer.shm_id();
6017 coords_shm_offset = buffer.offset();
6020 DCHECK(num_commands > 0);
6021 unsigned char* commands_addr =
6022 static_cast<unsigned char*>(buffer.address()) + coords_size;
6023 memcpy(commands_addr, commands, num_commands);
6025 helper_->PathCommandsCHROMIUM(path, num_commands, buffer.shm_id(),
6026 buffer.offset() + coords_size, num_coords,
6027 coord_type, coords_shm_id, coords_shm_offset);
6028 CheckGLError();
6031 // Include the auto-generated part of this file. We split this because it means
6032 // we can easily edit the non-auto generated parts right here in this file
6033 // instead of having to edit some template or the code generator.
6034 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
6036 } // namespace gles2
6037 } // namespace gpu