Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blob7708bc129c7aec036cc6186e7ab3d128beec0a79
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // A class to emulate GLES2 over command buffers.
7 #include "gpu/command_buffer/client/gles2_implementation.h"
9 #include <GLES2/gl2ext.h>
10 #include <GLES2/gl2extchromium.h>
11 #include <GLES3/gl3.h>
12 #include <algorithm>
13 #include <limits>
14 #include <map>
15 #include <queue>
16 #include <set>
17 #include <sstream>
18 #include <string>
19 #include "base/bind.h"
20 #include "base/compiler_specific.h"
21 #include "base/numerics/safe_math.h"
22 #include "gpu/command_buffer/client/buffer_tracker.h"
23 #include "gpu/command_buffer/client/gpu_control.h"
24 #include "gpu/command_buffer/client/program_info_manager.h"
25 #include "gpu/command_buffer/client/query_tracker.h"
26 #include "gpu/command_buffer/client/transfer_buffer.h"
27 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
28 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
29 #include "gpu/command_buffer/common/trace_event.h"
31 #if defined(GPU_CLIENT_DEBUG)
32 #include "base/command_line.h"
33 #include "gpu/command_buffer/client/gpu_switches.h"
34 #endif
36 namespace gpu {
37 namespace gles2 {
39 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
40 static GLuint ToGLuint(const void* ptr) {
41 return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
44 #if !defined(_MSC_VER)
45 const size_t GLES2Implementation::kMaxSizeOfSimpleResult;
46 const unsigned int GLES2Implementation::kStartingOffset;
47 #endif
49 GLES2Implementation::GLStaticState::GLStaticState() {
52 GLES2Implementation::GLStaticState::~GLStaticState() {
55 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
56 GLES2Implementation* gles2_implementation)
57 : gles2_implementation_(gles2_implementation) {
58 CHECK_EQ(0, gles2_implementation_->use_count_);
59 ++gles2_implementation_->use_count_;
62 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
63 --gles2_implementation_->use_count_;
64 CHECK_EQ(0, gles2_implementation_->use_count_);
67 GLES2Implementation::GLES2Implementation(
68 GLES2CmdHelper* helper,
69 ShareGroup* share_group,
70 TransferBufferInterface* transfer_buffer,
71 bool bind_generates_resource,
72 bool lose_context_when_out_of_memory,
73 bool support_client_side_arrays,
74 GpuControl* gpu_control)
75 : helper_(helper),
76 transfer_buffer_(transfer_buffer),
77 angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
78 chromium_framebuffer_multisample_(kUnknownExtensionStatus),
79 pack_alignment_(4),
80 unpack_alignment_(4),
81 unpack_flip_y_(false),
82 unpack_row_length_(0),
83 unpack_image_height_(0),
84 unpack_skip_rows_(0),
85 unpack_skip_pixels_(0),
86 unpack_skip_images_(0),
87 pack_reverse_row_order_(false),
88 active_texture_unit_(0),
89 bound_framebuffer_(0),
90 bound_read_framebuffer_(0),
91 bound_renderbuffer_(0),
92 bound_valuebuffer_(0),
93 current_program_(0),
94 bound_array_buffer_(0),
95 bound_copy_read_buffer_(0),
96 bound_copy_write_buffer_(0),
97 bound_pixel_pack_buffer_(0),
98 bound_pixel_unpack_buffer_(0),
99 bound_transform_feedback_buffer_(0),
100 bound_uniform_buffer_(0),
101 bound_pixel_pack_transfer_buffer_id_(0),
102 bound_pixel_unpack_transfer_buffer_id_(0),
103 async_upload_token_(0),
104 async_upload_sync_(NULL),
105 async_upload_sync_shm_id_(0),
106 async_upload_sync_shm_offset_(0),
107 error_bits_(0),
108 debug_(false),
109 lose_context_when_out_of_memory_(lose_context_when_out_of_memory),
110 support_client_side_arrays_(support_client_side_arrays),
111 use_count_(0),
112 error_message_callback_(NULL),
113 current_trace_stack_(0),
114 gpu_control_(gpu_control),
115 capabilities_(gpu_control->GetCapabilities()),
116 weak_ptr_factory_(this) {
117 DCHECK(helper);
118 DCHECK(transfer_buffer);
119 DCHECK(gpu_control);
121 std::stringstream ss;
122 ss << std::hex << this;
123 this_in_hex_ = ss.str();
125 GPU_CLIENT_LOG_CODE_BLOCK({
126 debug_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
127 switches::kEnableGPUClientLogging);
130 share_group_ =
131 (share_group ? share_group : new ShareGroup(bind_generates_resource));
132 DCHECK(share_group_->bind_generates_resource() == bind_generates_resource);
134 memset(&reserved_ids_, 0, sizeof(reserved_ids_));
137 bool GLES2Implementation::Initialize(
138 unsigned int starting_transfer_buffer_size,
139 unsigned int min_transfer_buffer_size,
140 unsigned int max_transfer_buffer_size,
141 unsigned int mapped_memory_limit) {
142 TRACE_EVENT0("gpu", "GLES2Implementation::Initialize");
143 DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
144 DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
145 DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
147 if (!transfer_buffer_->Initialize(
148 starting_transfer_buffer_size,
149 kStartingOffset,
150 min_transfer_buffer_size,
151 max_transfer_buffer_size,
152 kAlignment,
153 kSizeToFlush)) {
154 return false;
157 mapped_memory_.reset(
158 new MappedMemoryManager(
159 helper_,
160 base::Bind(&GLES2Implementation::PollAsyncUploads,
161 // The mapped memory manager is owned by |this| here, and
162 // since its destroyed before before we destroy ourselves
163 // we don't need extra safety measures for this closure.
164 base::Unretained(this)),
165 mapped_memory_limit));
167 unsigned chunk_size = 2 * 1024 * 1024;
168 if (mapped_memory_limit != kNoLimit) {
169 // Use smaller chunks if the client is very memory conscientious.
170 chunk_size = std::min(mapped_memory_limit / 4, chunk_size);
172 mapped_memory_->set_chunk_size_multiple(chunk_size);
174 GLStaticState::ShaderPrecisionMap* shader_precisions =
175 &static_state_.shader_precisions;
176 capabilities_.VisitPrecisions([shader_precisions](
177 GLenum shader, GLenum type, Capabilities::ShaderPrecision* result) {
178 const GLStaticState::ShaderPrecisionKey key(shader, type);
179 cmds::GetShaderPrecisionFormat::Result cached_result = {
180 true, result->min_range, result->max_range, result->precision};
181 shader_precisions->insert(std::make_pair(key, cached_result));
184 util_.set_num_compressed_texture_formats(
185 capabilities_.num_compressed_texture_formats);
186 util_.set_num_shader_binary_formats(capabilities_.num_shader_binary_formats);
188 texture_units_.reset(
189 new TextureUnit[capabilities_.max_combined_texture_image_units]);
191 query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
192 buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
194 query_id_allocator_.reset(new IdAllocator());
195 if (support_client_side_arrays_) {
196 GetIdHandler(id_namespaces::kBuffers)->MakeIds(
197 this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
200 vertex_array_object_manager_.reset(new VertexArrayObjectManager(
201 capabilities_.max_vertex_attribs, reserved_ids_[0], reserved_ids_[1],
202 support_client_side_arrays_));
204 // GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
205 // on Client & Service.
206 if (capabilities_.bind_generates_resource_chromium !=
207 (share_group_->bind_generates_resource() ? 1 : 0)) {
208 SetGLError(GL_INVALID_OPERATION,
209 "Initialize",
210 "Service bind_generates_resource mismatch.");
211 return false;
214 return true;
217 GLES2Implementation::~GLES2Implementation() {
218 // Make sure the queries are finished otherwise we'll delete the
219 // shared memory (mapped_memory_) which will free the memory used
220 // by the queries. The GPU process when validating that memory is still
221 // shared will fail and abort (ie, it will stop running).
222 WaitForCmd();
223 query_tracker_.reset();
225 // GLES2Implementation::Initialize() could fail before allocating
226 // reserved_ids_, so we need delete them carefully.
227 if (support_client_side_arrays_ && reserved_ids_[0]) {
228 DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
231 // Release remaining BufferRange mem; This is when a MapBufferRange() is
232 // called but not the UnmapBuffer() pair.
233 ClearMappedBufferRangeMap();
235 // Release any per-context data in share group.
236 share_group_->FreeContext(this);
238 buffer_tracker_.reset();
240 FreeAllAsyncUploadBuffers();
242 if (async_upload_sync_) {
243 mapped_memory_->Free(async_upload_sync_);
244 async_upload_sync_ = NULL;
247 // Make sure the commands make it the service.
248 WaitForCmd();
251 GLES2CmdHelper* GLES2Implementation::helper() const {
252 return helper_;
255 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
256 return share_group_->GetIdHandler(namespace_id);
259 IdAllocator* GLES2Implementation::GetIdAllocator(int namespace_id) const {
260 if (namespace_id == id_namespaces::kQueries)
261 return query_id_allocator_.get();
262 NOTREACHED();
263 return NULL;
266 void* GLES2Implementation::GetResultBuffer() {
267 return transfer_buffer_->GetResultBuffer();
270 int32 GLES2Implementation::GetResultShmId() {
271 return transfer_buffer_->GetShmId();
274 uint32 GLES2Implementation::GetResultShmOffset() {
275 return transfer_buffer_->GetResultOffset();
278 void GLES2Implementation::FreeUnusedSharedMemory() {
279 mapped_memory_->FreeUnused();
282 void GLES2Implementation::FreeEverything() {
283 FreeAllAsyncUploadBuffers();
284 WaitForCmd();
285 query_tracker_->Shrink();
286 FreeUnusedSharedMemory();
287 transfer_buffer_->Free();
288 helper_->FreeRingBuffer();
291 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
292 if (!helper_->IsContextLost())
293 callback.Run();
296 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
297 const base::Closure& callback) {
298 gpu_control_->SignalSyncPoint(
299 sync_point,
300 base::Bind(&GLES2Implementation::RunIfContextNotLost,
301 weak_ptr_factory_.GetWeakPtr(),
302 callback));
305 void GLES2Implementation::SignalQuery(uint32 query,
306 const base::Closure& callback) {
307 // Flush previously entered commands to ensure ordering with any
308 // glBeginQueryEXT() calls that may have been put into the context.
309 ShallowFlushCHROMIUM();
310 gpu_control_->SignalQuery(
311 query,
312 base::Bind(&GLES2Implementation::RunIfContextNotLost,
313 weak_ptr_factory_.GetWeakPtr(),
314 callback));
317 void GLES2Implementation::SetSurfaceVisible(bool visible) {
318 TRACE_EVENT1(
319 "gpu", "GLES2Implementation::SetSurfaceVisible", "visible", visible);
320 // TODO(piman): This probably should be ShallowFlushCHROMIUM().
321 Flush();
322 gpu_control_->SetSurfaceVisible(visible);
323 if (!visible)
324 FreeEverything();
327 void GLES2Implementation::WaitForCmd() {
328 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
329 helper_->CommandBufferHelper::Finish();
332 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
333 const char* extensions =
334 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
335 if (!extensions)
336 return false;
338 int length = strlen(ext);
339 while (true) {
340 int n = strcspn(extensions, " ");
341 if (n == length && 0 == strncmp(ext, extensions, length)) {
342 return true;
344 if ('\0' == extensions[n]) {
345 return false;
347 extensions += n + 1;
351 bool GLES2Implementation::IsExtensionAvailableHelper(
352 const char* extension, ExtensionStatus* status) {
353 switch (*status) {
354 case kAvailableExtensionStatus:
355 return true;
356 case kUnavailableExtensionStatus:
357 return false;
358 default: {
359 bool available = IsExtensionAvailable(extension);
360 *status = available ? kAvailableExtensionStatus :
361 kUnavailableExtensionStatus;
362 return available;
367 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
368 return IsExtensionAvailableHelper(
369 "GL_ANGLE_pack_reverse_row_order",
370 &angle_pack_reverse_row_order_status_);
373 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
374 return IsExtensionAvailableHelper(
375 "GL_CHROMIUM_framebuffer_multisample",
376 &chromium_framebuffer_multisample_);
379 const std::string& GLES2Implementation::GetLogPrefix() const {
380 const std::string& prefix(debug_marker_manager_.GetMarker());
381 return prefix.empty() ? this_in_hex_ : prefix;
384 GLenum GLES2Implementation::GetError() {
385 GPU_CLIENT_SINGLE_THREAD_CHECK();
386 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
387 GLenum err = GetGLError();
388 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
389 return err;
392 GLenum GLES2Implementation::GetClientSideGLError() {
393 if (error_bits_ == 0) {
394 return GL_NO_ERROR;
397 GLenum error = GL_NO_ERROR;
398 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
399 if ((error_bits_ & mask) != 0) {
400 error = GLES2Util::GLErrorBitToGLError(mask);
401 break;
404 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
405 return error;
408 GLenum GLES2Implementation::GetGLError() {
409 TRACE_EVENT0("gpu", "GLES2::GetGLError");
410 // Check the GL error first, then our wrapped error.
411 typedef cmds::GetError::Result Result;
412 Result* result = GetResultAs<Result*>();
413 // If we couldn't allocate a result the context is lost.
414 if (!result) {
415 return GL_NO_ERROR;
417 *result = GL_NO_ERROR;
418 helper_->GetError(GetResultShmId(), GetResultShmOffset());
419 WaitForCmd();
420 GLenum error = *result;
421 if (error == GL_NO_ERROR) {
422 error = GetClientSideGLError();
423 } else {
424 // There was an error, clear the corresponding wrapped error.
425 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
427 return error;
430 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
431 void GLES2Implementation::FailGLError(GLenum error) {
432 if (error != GL_NO_ERROR) {
433 NOTREACHED() << "Error";
436 // NOTE: Calling GetGLError overwrites data in the result buffer.
437 void GLES2Implementation::CheckGLError() {
438 FailGLError(GetGLError());
440 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
442 void GLES2Implementation::SetGLError(
443 GLenum error, const char* function_name, const char* msg) {
444 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
445 << GLES2Util::GetStringError(error) << ": "
446 << function_name << ": " << msg);
447 FailGLError(error);
448 if (msg) {
449 last_error_ = msg;
451 if (error_message_callback_) {
452 std::string temp(GLES2Util::GetStringError(error) + " : " +
453 function_name + ": " + (msg ? msg : ""));
454 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
456 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
458 if (error == GL_OUT_OF_MEMORY && lose_context_when_out_of_memory_) {
459 helper_->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
460 GL_UNKNOWN_CONTEXT_RESET_ARB);
464 void GLES2Implementation::SetGLErrorInvalidEnum(
465 const char* function_name, GLenum value, const char* label) {
466 SetGLError(GL_INVALID_ENUM, function_name,
467 (std::string(label) + " was " +
468 GLES2Util::GetStringEnum(value)).c_str());
471 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
472 std::vector<int8>* data) {
473 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
474 DCHECK(data);
475 const uint32 kStartSize = 32 * 1024;
476 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
477 if (!buffer.valid()) {
478 return false;
480 typedef cmd::GetBucketStart::Result Result;
481 Result* result = GetResultAs<Result*>();
482 if (!result) {
483 return false;
485 *result = 0;
486 helper_->GetBucketStart(
487 bucket_id, GetResultShmId(), GetResultShmOffset(),
488 buffer.size(), buffer.shm_id(), buffer.offset());
489 WaitForCmd();
490 uint32 size = *result;
491 data->resize(size);
492 if (size > 0u) {
493 uint32 offset = 0;
494 while (size) {
495 if (!buffer.valid()) {
496 buffer.Reset(size);
497 if (!buffer.valid()) {
498 return false;
500 helper_->GetBucketData(
501 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
502 WaitForCmd();
504 uint32 size_to_copy = std::min(size, buffer.size());
505 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
506 offset += size_to_copy;
507 size -= size_to_copy;
508 buffer.Release();
510 // Free the bucket. This is not required but it does free up the memory.
511 // and we don't have to wait for the result so from the client's perspective
512 // it's cheap.
513 helper_->SetBucketSize(bucket_id, 0);
515 return true;
518 void GLES2Implementation::SetBucketContents(
519 uint32 bucket_id, const void* data, size_t size) {
520 DCHECK(data);
521 helper_->SetBucketSize(bucket_id, size);
522 if (size > 0u) {
523 uint32 offset = 0;
524 while (size) {
525 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
526 if (!buffer.valid()) {
527 return;
529 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
530 buffer.size());
531 helper_->SetBucketData(
532 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
533 offset += buffer.size();
534 size -= buffer.size();
539 void GLES2Implementation::SetBucketAsCString(
540 uint32 bucket_id, const char* str) {
541 // NOTE: strings are passed NULL terminated. That means the empty
542 // string will have a size of 1 and no-string will have a size of 0
543 if (str) {
544 SetBucketContents(bucket_id, str, strlen(str) + 1);
545 } else {
546 helper_->SetBucketSize(bucket_id, 0);
550 bool GLES2Implementation::GetBucketAsString(
551 uint32 bucket_id, std::string* str) {
552 DCHECK(str);
553 std::vector<int8> data;
554 // NOTE: strings are passed NULL terminated. That means the empty
555 // string will have a size of 1 and no-string will have a size of 0
556 if (!GetBucketContents(bucket_id, &data)) {
557 return false;
559 if (data.empty()) {
560 return false;
562 str->assign(&data[0], &data[0] + data.size() - 1);
563 return true;
566 void GLES2Implementation::SetBucketAsString(
567 uint32 bucket_id, const std::string& str) {
568 // NOTE: strings are passed NULL terminated. That means the empty
569 // string will have a size of 1 and no-string will have a size of 0
570 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
573 void GLES2Implementation::Disable(GLenum cap) {
574 GPU_CLIENT_SINGLE_THREAD_CHECK();
575 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
576 << GLES2Util::GetStringCapability(cap) << ")");
577 bool changed = false;
578 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
579 helper_->Disable(cap);
581 CheckGLError();
584 void GLES2Implementation::Enable(GLenum cap) {
585 GPU_CLIENT_SINGLE_THREAD_CHECK();
586 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
587 << GLES2Util::GetStringCapability(cap) << ")");
588 bool changed = false;
589 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
590 helper_->Enable(cap);
592 CheckGLError();
595 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
596 GPU_CLIENT_SINGLE_THREAD_CHECK();
597 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
598 << GLES2Util::GetStringCapability(cap) << ")");
599 bool state = false;
600 if (!state_.GetEnabled(cap, &state)) {
601 typedef cmds::IsEnabled::Result Result;
602 Result* result = GetResultAs<Result*>();
603 if (!result) {
604 return GL_FALSE;
606 *result = 0;
607 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
608 WaitForCmd();
609 state = (*result) != 0;
612 GPU_CLIENT_LOG("returned " << state);
613 CheckGLError();
614 return state;
617 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
618 // TODO(zmo): For all the BINDING points, there is a possibility where
619 // resources are shared among multiple contexts, that the cached points
620 // are invalid. It is not a problem for now, but once we allow resource
621 // sharing in WebGL, we need to implement a mechanism to allow correct
622 // client side binding points tracking. crbug.com/465562.
624 // ES2 parameters.
625 switch (pname) {
626 case GL_ACTIVE_TEXTURE:
627 *params = active_texture_unit_ + GL_TEXTURE0;
628 return true;
629 case GL_ARRAY_BUFFER_BINDING:
630 *params = bound_array_buffer_;
631 return true;
632 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
633 *params =
634 vertex_array_object_manager_->bound_element_array_buffer();
635 return true;
636 case GL_FRAMEBUFFER_BINDING:
637 *params = bound_framebuffer_;
638 return true;
639 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
640 *params = capabilities_.max_combined_texture_image_units;
641 return true;
642 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
643 *params = capabilities_.max_cube_map_texture_size;
644 return true;
645 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
646 *params = capabilities_.max_fragment_uniform_vectors;
647 return true;
648 case GL_MAX_RENDERBUFFER_SIZE:
649 *params = capabilities_.max_renderbuffer_size;
650 return true;
651 case GL_MAX_TEXTURE_IMAGE_UNITS:
652 *params = capabilities_.max_texture_image_units;
653 return true;
654 case GL_MAX_TEXTURE_SIZE:
655 *params = capabilities_.max_texture_size;
656 return true;
657 case GL_MAX_VARYING_VECTORS:
658 *params = capabilities_.max_varying_vectors;
659 return true;
660 case GL_MAX_VERTEX_ATTRIBS:
661 *params = capabilities_.max_vertex_attribs;
662 return true;
663 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
664 *params = capabilities_.max_vertex_texture_image_units;
665 return true;
666 case GL_MAX_VERTEX_UNIFORM_VECTORS:
667 *params = capabilities_.max_vertex_uniform_vectors;
668 return true;
669 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
670 *params = capabilities_.num_compressed_texture_formats;
671 return true;
672 case GL_NUM_SHADER_BINARY_FORMATS:
673 *params = capabilities_.num_shader_binary_formats;
674 return true;
675 case GL_RENDERBUFFER_BINDING:
676 *params = bound_renderbuffer_;
677 return true;
678 case GL_TEXTURE_BINDING_2D:
679 *params = texture_units_[active_texture_unit_].bound_texture_2d;
680 return true;
681 case GL_TEXTURE_BINDING_CUBE_MAP:
682 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
683 return true;
685 // Non-standard parameters.
686 case GL_TEXTURE_BINDING_EXTERNAL_OES:
687 *params =
688 texture_units_[active_texture_unit_].bound_texture_external_oes;
689 return true;
690 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
691 *params = bound_pixel_pack_transfer_buffer_id_;
692 return true;
693 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
694 *params = bound_pixel_unpack_transfer_buffer_id_;
695 return true;
696 case GL_READ_FRAMEBUFFER_BINDING:
697 if (IsChromiumFramebufferMultisampleAvailable()) {
698 *params = bound_read_framebuffer_;
699 return true;
701 break;
703 // Non-cached parameters.
704 case GL_ALIASED_LINE_WIDTH_RANGE:
705 case GL_ALIASED_POINT_SIZE_RANGE:
706 case GL_ALPHA_BITS:
707 case GL_BLEND:
708 case GL_BLEND_COLOR:
709 case GL_BLEND_DST_ALPHA:
710 case GL_BLEND_DST_RGB:
711 case GL_BLEND_EQUATION_ALPHA:
712 case GL_BLEND_EQUATION_RGB:
713 case GL_BLEND_SRC_ALPHA:
714 case GL_BLEND_SRC_RGB:
715 case GL_BLUE_BITS:
716 case GL_COLOR_CLEAR_VALUE:
717 case GL_COLOR_WRITEMASK:
718 case GL_COMPRESSED_TEXTURE_FORMATS:
719 case GL_CULL_FACE:
720 case GL_CULL_FACE_MODE:
721 case GL_CURRENT_PROGRAM:
722 case GL_DEPTH_BITS:
723 case GL_DEPTH_CLEAR_VALUE:
724 case GL_DEPTH_FUNC:
725 case GL_DEPTH_RANGE:
726 case GL_DEPTH_TEST:
727 case GL_DEPTH_WRITEMASK:
728 case GL_DITHER:
729 case GL_FRONT_FACE:
730 case GL_GENERATE_MIPMAP_HINT:
731 case GL_GREEN_BITS:
732 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
733 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
734 case GL_LINE_WIDTH:
735 case GL_MAX_VIEWPORT_DIMS:
736 case GL_PACK_ALIGNMENT:
737 case GL_POLYGON_OFFSET_FACTOR:
738 case GL_POLYGON_OFFSET_FILL:
739 case GL_POLYGON_OFFSET_UNITS:
740 case GL_RED_BITS:
741 case GL_SAMPLE_ALPHA_TO_COVERAGE:
742 case GL_SAMPLE_BUFFERS:
743 case GL_SAMPLE_COVERAGE:
744 case GL_SAMPLE_COVERAGE_INVERT:
745 case GL_SAMPLE_COVERAGE_VALUE:
746 case GL_SAMPLES:
747 case GL_SCISSOR_BOX:
748 case GL_SCISSOR_TEST:
749 case GL_SHADER_BINARY_FORMATS:
750 case GL_SHADER_COMPILER:
751 case GL_STENCIL_BACK_FAIL:
752 case GL_STENCIL_BACK_FUNC:
753 case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
754 case GL_STENCIL_BACK_PASS_DEPTH_PASS:
755 case GL_STENCIL_BACK_REF:
756 case GL_STENCIL_BACK_VALUE_MASK:
757 case GL_STENCIL_BACK_WRITEMASK:
758 case GL_STENCIL_BITS:
759 case GL_STENCIL_CLEAR_VALUE:
760 case GL_STENCIL_FAIL:
761 case GL_STENCIL_FUNC:
762 case GL_STENCIL_PASS_DEPTH_FAIL:
763 case GL_STENCIL_PASS_DEPTH_PASS:
764 case GL_STENCIL_REF:
765 case GL_STENCIL_TEST:
766 case GL_STENCIL_VALUE_MASK:
767 case GL_STENCIL_WRITEMASK:
768 case GL_SUBPIXEL_BITS:
769 case GL_UNPACK_ALIGNMENT:
770 case GL_VIEWPORT:
771 return false;
772 default:
773 break;
776 if (capabilities_.major_version < 3) {
777 return false;
780 // ES3 parameters.
781 switch (pname) {
782 case GL_COPY_READ_BUFFER_BINDING:
783 *params = bound_copy_read_buffer_;
784 return true;
785 case GL_COPY_WRITE_BUFFER_BINDING:
786 *params = bound_copy_write_buffer_;
787 return true;
788 case GL_MAJOR_VERSION:
789 *params = capabilities_.major_version;
790 return true;
791 case GL_MAX_3D_TEXTURE_SIZE:
792 *params = capabilities_.max_3d_texture_size;
793 return true;
794 case GL_MAX_ARRAY_TEXTURE_LAYERS:
795 *params = capabilities_.max_array_texture_layers;
796 return true;
797 case GL_MAX_COLOR_ATTACHMENTS:
798 *params = capabilities_.max_color_attachments;
799 return true;
800 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
801 *params = static_cast<GLint>(
802 capabilities_.max_combined_fragment_uniform_components);
803 return true;
804 case GL_MAX_COMBINED_UNIFORM_BLOCKS:
805 *params = capabilities_.max_combined_uniform_blocks;
806 return true;
807 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
808 *params = static_cast<GLint>(
809 capabilities_.max_combined_vertex_uniform_components);
810 return true;
811 case GL_MAX_DRAW_BUFFERS:
812 *params = capabilities_.max_draw_buffers;
813 return true;
814 case GL_MAX_ELEMENT_INDEX:
815 *params = static_cast<GLint>(capabilities_.max_element_index);
816 return true;
817 case GL_MAX_ELEMENTS_INDICES:
818 *params = capabilities_.max_elements_indices;
819 return true;
820 case GL_MAX_ELEMENTS_VERTICES:
821 *params = capabilities_.max_elements_vertices;
822 return true;
823 case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
824 *params = capabilities_.max_fragment_input_components;
825 return true;
826 case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
827 *params = capabilities_.max_fragment_uniform_blocks;
828 return true;
829 case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
830 *params = capabilities_.max_fragment_uniform_components;
831 return true;
832 case GL_MAX_PROGRAM_TEXEL_OFFSET:
833 *params = capabilities_.max_program_texel_offset;
834 return true;
835 case GL_MAX_SAMPLES:
836 *params = capabilities_.max_samples;
837 return true;
838 case GL_MAX_SERVER_WAIT_TIMEOUT:
839 *params = static_cast<GLint>(capabilities_.max_server_wait_timeout);
840 return true;
841 case GL_MAX_TEXTURE_LOD_BIAS:
842 *params = static_cast<GLint>(capabilities_.max_texture_lod_bias);
843 return true;
844 case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
845 *params = capabilities_.max_transform_feedback_interleaved_components;
846 return true;
847 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
848 *params = capabilities_.max_transform_feedback_separate_attribs;
849 return true;
850 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
851 *params = capabilities_.max_transform_feedback_separate_components;
852 return true;
853 case GL_MAX_UNIFORM_BLOCK_SIZE:
854 *params = static_cast<GLint>(capabilities_.max_uniform_block_size);
855 return true;
856 case GL_MAX_UNIFORM_BUFFER_BINDINGS:
857 *params = capabilities_.max_uniform_buffer_bindings;
858 return true;
859 case GL_MAX_VARYING_COMPONENTS:
860 *params = capabilities_.max_varying_components;
861 return true;
862 case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
863 *params = capabilities_.max_vertex_output_components;
864 return true;
865 case GL_MAX_VERTEX_UNIFORM_BLOCKS:
866 *params = capabilities_.max_vertex_uniform_blocks;
867 return true;
868 case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
869 *params = capabilities_.max_vertex_uniform_components;
870 return true;
871 case GL_MIN_PROGRAM_TEXEL_OFFSET:
872 *params = capabilities_.min_program_texel_offset;
873 return true;
874 case GL_MINOR_VERSION:
875 *params = capabilities_.minor_version;
876 return true;
877 case GL_NUM_EXTENSIONS:
878 *params = capabilities_.num_extensions;
879 return true;
880 case GL_NUM_PROGRAM_BINARY_FORMATS:
881 *params = capabilities_.num_program_binary_formats;
882 return true;
883 case GL_PIXEL_PACK_BUFFER_BINDING:
884 *params = bound_pixel_pack_buffer_;
885 return true;
886 case GL_PIXEL_UNPACK_BUFFER_BINDING:
887 *params = bound_pixel_unpack_buffer_;
888 return true;
889 case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
890 *params = bound_transform_feedback_buffer_;
891 return true;
892 case GL_UNIFORM_BUFFER_BINDING:
893 *params = bound_uniform_buffer_;
894 return true;
895 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
896 *params = capabilities_.uniform_buffer_offset_alignment;
897 return true;
899 // Non-cached ES3 parameters.
900 case GL_DRAW_BUFFER0:
901 case GL_DRAW_BUFFER1:
902 case GL_DRAW_BUFFER2:
903 case GL_DRAW_BUFFER3:
904 case GL_DRAW_BUFFER4:
905 case GL_DRAW_BUFFER5:
906 case GL_DRAW_BUFFER6:
907 case GL_DRAW_BUFFER7:
908 case GL_DRAW_BUFFER8:
909 case GL_DRAW_BUFFER9:
910 case GL_DRAW_BUFFER10:
911 case GL_DRAW_BUFFER11:
912 case GL_DRAW_BUFFER12:
913 case GL_DRAW_BUFFER13:
914 case GL_DRAW_BUFFER14:
915 case GL_DRAW_BUFFER15:
916 case GL_DRAW_FRAMEBUFFER_BINDING:
917 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
918 case GL_PACK_ROW_LENGTH:
919 case GL_PACK_SKIP_PIXELS:
920 case GL_PACK_SKIP_ROWS:
921 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
922 case GL_PROGRAM_BINARY_FORMATS:
923 case GL_RASTERIZER_DISCARD:
924 case GL_READ_BUFFER:
925 case GL_READ_FRAMEBUFFER_BINDING:
926 case GL_SAMPLER_BINDING:
927 case GL_TEXTURE_BINDING_2D_ARRAY:
928 case GL_TEXTURE_BINDING_3D:
929 case GL_TRANSFORM_FEEDBACK_BINDING:
930 case GL_TRANSFORM_FEEDBACK_ACTIVE:
931 case GL_TRANSFORM_FEEDBACK_PAUSED:
932 case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
933 case GL_TRANSFORM_FEEDBACK_BUFFER_START:
934 case GL_UNIFORM_BUFFER_SIZE:
935 case GL_UNIFORM_BUFFER_START:
936 case GL_UNPACK_IMAGE_HEIGHT:
937 case GL_UNPACK_ROW_LENGTH:
938 case GL_UNPACK_SKIP_IMAGES:
939 case GL_UNPACK_SKIP_PIXELS:
940 case GL_UNPACK_SKIP_ROWS:
941 case GL_VERTEX_ARRAY_BINDING:
942 return false;
943 default:
944 return false;
948 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
949 // TODO(gman): Make this handle pnames that return more than 1 value.
950 GLint value;
951 if (!GetHelper(pname, &value)) {
952 return false;
954 *params = static_cast<GLboolean>(value);
955 return true;
958 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
959 // TODO(gman): Make this handle pnames that return more than 1 value.
960 switch (pname) {
961 case GL_MAX_TEXTURE_LOD_BIAS:
962 *params = capabilities_.max_texture_lod_bias;
963 return true;
964 default:
965 break;
967 GLint value;
968 if (!GetHelper(pname, &value)) {
969 return false;
971 *params = static_cast<GLfloat>(value);
972 return true;
975 bool GLES2Implementation::GetInteger64vHelper(GLenum pname, GLint64* params) {
976 switch (pname) {
977 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
978 *params = capabilities_.max_combined_fragment_uniform_components;
979 return true;
980 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
981 *params = capabilities_.max_combined_vertex_uniform_components;
982 return true;
983 case GL_MAX_ELEMENT_INDEX:
984 *params = capabilities_.max_element_index;
985 return true;
986 case GL_MAX_SERVER_WAIT_TIMEOUT:
987 *params = capabilities_.max_server_wait_timeout;
988 return true;
989 case GL_MAX_UNIFORM_BLOCK_SIZE:
990 *params = capabilities_.max_uniform_block_size;
991 return true;
992 default:
993 break;
995 GLint value;
996 if (!GetHelper(pname, &value)) {
997 return false;
999 *params = static_cast<GLint64>(value);
1000 return true;
1003 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
1004 return GetHelper(pname, params);
1007 bool GLES2Implementation::GetIntegeri_vHelper(
1008 GLenum pname, GLuint index, GLint* data) {
1009 // TODO(zmo): Implement client side caching.
1010 return false;
1013 bool GLES2Implementation::GetInteger64i_vHelper(
1014 GLenum pname, GLuint index, GLint64* data) {
1015 // TODO(zmo): Implement client side caching.
1016 return false;
1019 bool GLES2Implementation::GetInternalformativHelper(
1020 GLenum target, GLenum format, GLenum pname, GLsizei bufSize,
1021 GLint* params) {
1022 // TODO(zmo): Implement the client side caching.
1023 return false;
1026 bool GLES2Implementation::GetSyncivHelper(
1027 GLsync sync, GLenum pname, GLsizei bufsize, GLsizei* length,
1028 GLint* values) {
1029 GLint value = 0;
1030 switch (pname) {
1031 case GL_OBJECT_TYPE:
1032 value = GL_SYNC_FENCE;
1033 break;
1034 case GL_SYNC_CONDITION:
1035 value = GL_SYNC_GPU_COMMANDS_COMPLETE;
1036 break;
1037 case GL_SYNC_FLAGS:
1038 value = 0;
1039 break;
1040 default:
1041 return false;
1043 if (bufsize > 0) {
1044 DCHECK(values);
1045 *values = value;
1047 if (length) {
1048 *length = 1;
1050 return true;
1053 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
1054 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1055 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
1056 Result* result = GetResultAs<Result*>();
1057 if (!result) {
1058 return 0;
1060 *result = 0;
1061 helper_->GetMaxValueInBufferCHROMIUM(
1062 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
1063 WaitForCmd();
1064 return *result;
1067 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
1068 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1069 GPU_CLIENT_SINGLE_THREAD_CHECK();
1070 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
1071 << buffer_id << ", " << count << ", "
1072 << GLES2Util::GetStringGetMaxIndexType(type)
1073 << ", " << offset << ")");
1074 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
1075 buffer_id, count, type, offset);
1076 GPU_CLIENT_LOG("returned " << result);
1077 CheckGLError();
1078 return result;
1081 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
1082 if (restore) {
1083 RestoreArrayBuffer(restore);
1084 // Restore the element array binding.
1085 // We only need to restore it if it wasn't a client side array.
1086 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
1087 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1092 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
1093 if (restore) {
1094 // Restore the user's current binding.
1095 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_);
1099 void GLES2Implementation::DrawElements(
1100 GLenum mode, GLsizei count, GLenum type, const void* indices) {
1101 GPU_CLIENT_SINGLE_THREAD_CHECK();
1102 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
1103 << GLES2Util::GetStringDrawMode(mode) << ", "
1104 << count << ", "
1105 << GLES2Util::GetStringIndexType(type) << ", "
1106 << static_cast<const void*>(indices) << ")");
1107 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1110 void GLES2Implementation::DrawRangeElements(
1111 GLenum mode, GLuint start, GLuint end,
1112 GLsizei count, GLenum type, const void* indices) {
1113 GPU_CLIENT_SINGLE_THREAD_CHECK();
1114 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawRangeElements("
1115 << GLES2Util::GetStringDrawMode(mode) << ", "
1116 << start << ", " << end << ", " << count << ", "
1117 << GLES2Util::GetStringIndexType(type) << ", "
1118 << static_cast<const void*>(indices) << ")");
1119 if (end < start) {
1120 SetGLError(GL_INVALID_VALUE, "glDrawRangeElements", "end < start");
1121 return;
1123 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1126 void GLES2Implementation::DrawElementsImpl(
1127 GLenum mode, GLsizei count, GLenum type, const void* indices,
1128 const char* func_name) {
1129 if (count < 0) {
1130 SetGLError(GL_INVALID_VALUE, func_name, "count < 0");
1131 return;
1133 bool simulated = false;
1134 GLuint offset = ToGLuint(indices);
1135 if (count > 0) {
1136 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
1137 !ValidateOffset(func_name, reinterpret_cast<GLintptr>(indices))) {
1138 return;
1140 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
1141 func_name, this, helper_, count, type, 0, indices,
1142 &offset, &simulated)) {
1143 return;
1146 helper_->DrawElements(mode, count, type, offset);
1147 RestoreElementAndArrayBuffers(simulated);
1148 CheckGLError();
1151 void GLES2Implementation::Flush() {
1152 GPU_CLIENT_SINGLE_THREAD_CHECK();
1153 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
1154 // Insert the cmd to call glFlush
1155 helper_->Flush();
1156 // Flush our command buffer
1157 // (tell the service to execute up to the flush cmd.)
1158 helper_->CommandBufferHelper::Flush();
1161 void GLES2Implementation::ShallowFlushCHROMIUM() {
1162 GPU_CLIENT_SINGLE_THREAD_CHECK();
1163 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
1164 // Flush our command buffer
1165 // (tell the service to execute up to the flush cmd.)
1166 helper_->CommandBufferHelper::Flush();
1167 // TODO(piman): Add the FreeEverything() logic here.
1170 void GLES2Implementation::OrderingBarrierCHROMIUM() {
1171 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOrderingBarrierCHROMIUM");
1172 // Flush command buffer at the GPU channel level. May be implemented as
1173 // Flush().
1174 helper_->CommandBufferHelper::OrderingBarrier();
1177 void GLES2Implementation::Finish() {
1178 GPU_CLIENT_SINGLE_THREAD_CHECK();
1179 FinishHelper();
1182 void GLES2Implementation::ShallowFinishCHROMIUM() {
1183 GPU_CLIENT_SINGLE_THREAD_CHECK();
1184 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
1185 // Flush our command buffer (tell the service to execute up to the flush cmd
1186 // and don't return until it completes).
1187 helper_->CommandBufferHelper::Finish();
1190 void GLES2Implementation::FinishHelper() {
1191 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
1192 TRACE_EVENT0("gpu", "GLES2::Finish");
1193 // Insert the cmd to call glFinish
1194 helper_->Finish();
1195 // Finish our command buffer
1196 // (tell the service to execute up to the Finish cmd and wait for it to
1197 // execute.)
1198 helper_->CommandBufferHelper::Finish();
1201 void GLES2Implementation::SwapBuffers() {
1202 GPU_CLIENT_SINGLE_THREAD_CHECK();
1203 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
1204 // TODO(piman): Strictly speaking we'd want to insert the token after the
1205 // swap, but the state update with the updated token might not have happened
1206 // by the time the SwapBuffer callback gets called, forcing us to synchronize
1207 // with the GPU process more than needed. So instead, make it happen before.
1208 // All it means is that we could be slightly looser on the kMaxSwapBuffers
1209 // semantics if the client doesn't use the callback mechanism, and by chance
1210 // the scheduler yields between the InsertToken and the SwapBuffers.
1211 swap_buffers_tokens_.push(helper_->InsertToken());
1212 helper_->SwapBuffers();
1213 helper_->CommandBufferHelper::Flush();
1214 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
1215 // compensate for TODO above.
1216 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
1217 helper_->WaitForToken(swap_buffers_tokens_.front());
1218 swap_buffers_tokens_.pop();
1222 void GLES2Implementation::SwapInterval(int interval) {
1223 GPU_CLIENT_SINGLE_THREAD_CHECK();
1224 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapInterval("
1225 << interval << ")");
1226 helper_->SwapInterval(interval);
1229 void GLES2Implementation::BindAttribLocation(
1230 GLuint program, GLuint index, const char* name) {
1231 GPU_CLIENT_SINGLE_THREAD_CHECK();
1232 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
1233 << program << ", " << index << ", " << name << ")");
1234 SetBucketAsString(kResultBucketId, name);
1235 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
1236 helper_->SetBucketSize(kResultBucketId, 0);
1237 CheckGLError();
1240 void GLES2Implementation::BindUniformLocationCHROMIUM(
1241 GLuint program, GLint location, const char* name) {
1242 GPU_CLIENT_SINGLE_THREAD_CHECK();
1243 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1244 << program << ", " << location << ", " << name << ")");
1245 SetBucketAsString(kResultBucketId, name);
1246 helper_->BindUniformLocationCHROMIUMBucket(
1247 program, location, kResultBucketId);
1248 helper_->SetBucketSize(kResultBucketId, 0);
1249 CheckGLError();
1252 void GLES2Implementation::GetVertexAttribPointerv(
1253 GLuint index, GLenum pname, void** ptr) {
1254 GPU_CLIENT_SINGLE_THREAD_CHECK();
1255 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1256 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1257 << static_cast<void*>(ptr) << ")");
1258 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
1259 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1260 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1261 typedef cmds::GetVertexAttribPointerv::Result Result;
1262 Result* result = GetResultAs<Result*>();
1263 if (!result) {
1264 return;
1266 result->SetNumResults(0);
1267 helper_->GetVertexAttribPointerv(
1268 index, pname, GetResultShmId(), GetResultShmOffset());
1269 WaitForCmd();
1270 result->CopyResult(ptr);
1271 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1273 GPU_CLIENT_LOG_CODE_BLOCK({
1274 for (int32 i = 0; i < num_results; ++i) {
1275 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
1278 CheckGLError();
1281 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1282 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1283 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
1284 SetGLError(
1285 GL_INVALID_VALUE,
1286 "glDeleteProgram", "id not created by this context.");
1287 return false;
1289 if (program == current_program_) {
1290 current_program_ = 0;
1292 return true;
1295 void GLES2Implementation::DeleteProgramStub(
1296 GLsizei n, const GLuint* programs) {
1297 DCHECK_EQ(1, n);
1298 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1299 helper_->DeleteProgram(programs[0]);
1302 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1303 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1304 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1305 SetGLError(
1306 GL_INVALID_VALUE,
1307 "glDeleteShader", "id not created by this context.");
1308 return false;
1310 return true;
1313 void GLES2Implementation::DeleteShaderStub(
1314 GLsizei n, const GLuint* shaders) {
1315 DCHECK_EQ(1, n);
1316 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1317 helper_->DeleteShader(shaders[0]);
1320 void GLES2Implementation::DeleteSyncHelper(GLsync sync) {
1321 GLuint sync_uint = ToGLuint(sync);
1322 if (!GetIdHandler(id_namespaces::kSyncs)->FreeIds(
1323 this, 1, &sync_uint, &GLES2Implementation::DeleteSyncStub)) {
1324 SetGLError(
1325 GL_INVALID_VALUE,
1326 "glDeleteSync", "id not created by this context.");
1330 void GLES2Implementation::DeleteSyncStub(GLsizei n, const GLuint* syncs) {
1331 DCHECK_EQ(1, n);
1332 helper_->DeleteSync(syncs[0]);
1335 GLint GLES2Implementation::GetAttribLocationHelper(
1336 GLuint program, const char* name) {
1337 typedef cmds::GetAttribLocation::Result Result;
1338 Result* result = GetResultAs<Result*>();
1339 if (!result) {
1340 return -1;
1342 *result = -1;
1343 SetBucketAsCString(kResultBucketId, name);
1344 helper_->GetAttribLocation(
1345 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1346 WaitForCmd();
1347 helper_->SetBucketSize(kResultBucketId, 0);
1348 return *result;
1351 GLint GLES2Implementation::GetAttribLocation(
1352 GLuint program, const char* name) {
1353 GPU_CLIENT_SINGLE_THREAD_CHECK();
1354 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1355 << ", " << name << ")");
1356 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1357 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1358 this, program, name);
1359 GPU_CLIENT_LOG("returned " << loc);
1360 CheckGLError();
1361 return loc;
1364 GLint GLES2Implementation::GetUniformLocationHelper(
1365 GLuint program, const char* name) {
1366 typedef cmds::GetUniformLocation::Result Result;
1367 Result* result = GetResultAs<Result*>();
1368 if (!result) {
1369 return -1;
1371 *result = -1;
1372 SetBucketAsCString(kResultBucketId, name);
1373 helper_->GetUniformLocation(program, kResultBucketId,
1374 GetResultShmId(), GetResultShmOffset());
1375 WaitForCmd();
1376 helper_->SetBucketSize(kResultBucketId, 0);
1377 return *result;
1380 GLint GLES2Implementation::GetUniformLocation(
1381 GLuint program, const char* name) {
1382 GPU_CLIENT_SINGLE_THREAD_CHECK();
1383 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1384 << ", " << name << ")");
1385 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1386 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1387 this, program, name);
1388 GPU_CLIENT_LOG("returned " << loc);
1389 CheckGLError();
1390 return loc;
1393 bool GLES2Implementation::GetUniformIndicesHelper(
1394 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1395 typedef cmds::GetUniformIndices::Result Result;
1396 Result* result = GetResultAs<Result*>();
1397 if (!result) {
1398 return false;
1400 result->SetNumResults(0);
1401 if (!PackStringsToBucket(count, names, NULL, "glGetUniformIndices")) {
1402 return false;
1404 helper_->GetUniformIndices(program, kResultBucketId,
1405 GetResultShmId(), GetResultShmOffset());
1406 WaitForCmd();
1407 if (result->GetNumResults() != count) {
1408 return false;
1410 result->CopyResult(indices);
1411 return true;
1414 void GLES2Implementation::GetUniformIndices(
1415 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1416 GPU_CLIENT_SINGLE_THREAD_CHECK();
1417 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
1418 << ", " << count << ", " << names << ", " << indices << ")");
1419 TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
1420 if (count < 0) {
1421 SetGLError(GL_INVALID_VALUE, "glGetUniformIndices", "count < 0");
1422 return;
1424 if (count == 0) {
1425 return;
1427 bool success = share_group_->program_info_manager()->GetUniformIndices(
1428 this, program, count, names, indices);
1429 if (success) {
1430 GPU_CLIENT_LOG_CODE_BLOCK({
1431 for (GLsizei ii = 0; ii < count; ++ii) {
1432 GPU_CLIENT_LOG(" " << ii << ": " << indices[ii]);
1436 CheckGLError();
1439 bool GLES2Implementation::GetProgramivHelper(
1440 GLuint program, GLenum pname, GLint* params) {
1441 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1442 this, program, pname, params);
1443 GPU_CLIENT_LOG_CODE_BLOCK({
1444 if (got_value) {
1445 GPU_CLIENT_LOG(" 0: " << *params);
1448 return got_value;
1451 GLint GLES2Implementation::GetFragDataLocationHelper(
1452 GLuint program, const char* name) {
1453 typedef cmds::GetFragDataLocation::Result Result;
1454 Result* result = GetResultAs<Result*>();
1455 if (!result) {
1456 return -1;
1458 *result = -1;
1459 SetBucketAsCString(kResultBucketId, name);
1460 helper_->GetFragDataLocation(
1461 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1462 WaitForCmd();
1463 helper_->SetBucketSize(kResultBucketId, 0);
1464 return *result;
1467 GLint GLES2Implementation::GetFragDataLocation(
1468 GLuint program, const char* name) {
1469 GPU_CLIENT_SINGLE_THREAD_CHECK();
1470 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataLocation("
1471 << program << ", " << name << ")");
1472 TRACE_EVENT0("gpu", "GLES2::GetFragDataLocation");
1473 GLint loc = share_group_->program_info_manager()->GetFragDataLocation(
1474 this, program, name);
1475 GPU_CLIENT_LOG("returned " << loc);
1476 CheckGLError();
1477 return loc;
1480 GLuint GLES2Implementation::GetUniformBlockIndexHelper(
1481 GLuint program, const char* name) {
1482 typedef cmds::GetUniformBlockIndex::Result Result;
1483 Result* result = GetResultAs<Result*>();
1484 if (!result) {
1485 return GL_INVALID_INDEX;
1487 *result = GL_INVALID_INDEX;
1488 SetBucketAsCString(kResultBucketId, name);
1489 helper_->GetUniformBlockIndex(
1490 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1491 WaitForCmd();
1492 helper_->SetBucketSize(kResultBucketId, 0);
1493 return *result;
1496 GLuint GLES2Implementation::GetUniformBlockIndex(
1497 GLuint program, const char* name) {
1498 GPU_CLIENT_SINGLE_THREAD_CHECK();
1499 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformBlockIndex("
1500 << program << ", " << name << ")");
1501 TRACE_EVENT0("gpu", "GLES2::GetUniformBlockIndex");
1502 GLuint index = share_group_->program_info_manager()->GetUniformBlockIndex(
1503 this, program, name);
1504 GPU_CLIENT_LOG("returned " << index);
1505 CheckGLError();
1506 return index;
1509 void GLES2Implementation::LinkProgram(GLuint program) {
1510 GPU_CLIENT_SINGLE_THREAD_CHECK();
1511 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1512 helper_->LinkProgram(program);
1513 share_group_->program_info_manager()->CreateInfo(program);
1514 CheckGLError();
1517 void GLES2Implementation::ShaderBinary(
1518 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1519 GLsizei length) {
1520 GPU_CLIENT_SINGLE_THREAD_CHECK();
1521 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1522 << static_cast<const void*>(shaders) << ", "
1523 << GLES2Util::GetStringEnum(binaryformat) << ", "
1524 << static_cast<const void*>(binary) << ", "
1525 << length << ")");
1526 if (n < 0) {
1527 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1528 return;
1530 if (length < 0) {
1531 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1532 return;
1534 // TODO(gman): ShaderBinary should use buckets.
1535 unsigned int shader_id_size = n * sizeof(*shaders);
1536 ScopedTransferBufferArray<GLint> buffer(
1537 shader_id_size + length, helper_, transfer_buffer_);
1538 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1539 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1540 return;
1542 void* shader_ids = buffer.elements();
1543 void* shader_data = buffer.elements() + shader_id_size;
1544 memcpy(shader_ids, shaders, shader_id_size);
1545 memcpy(shader_data, binary, length);
1546 helper_->ShaderBinary(
1548 buffer.shm_id(),
1549 buffer.offset(),
1550 binaryformat,
1551 buffer.shm_id(),
1552 buffer.offset() + shader_id_size,
1553 length);
1554 CheckGLError();
1557 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1558 GPU_CLIENT_SINGLE_THREAD_CHECK();
1559 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1560 << GLES2Util::GetStringPixelStore(pname) << ", "
1561 << param << ")");
1562 switch (pname) {
1563 case GL_PACK_ALIGNMENT:
1564 pack_alignment_ = param;
1565 break;
1566 case GL_UNPACK_ALIGNMENT:
1567 unpack_alignment_ = param;
1568 break;
1569 case GL_UNPACK_ROW_LENGTH_EXT:
1570 unpack_row_length_ = param;
1571 return;
1572 case GL_UNPACK_IMAGE_HEIGHT:
1573 unpack_image_height_ = param;
1574 return;
1575 case GL_UNPACK_SKIP_ROWS_EXT:
1576 unpack_skip_rows_ = param;
1577 return;
1578 case GL_UNPACK_SKIP_PIXELS_EXT:
1579 unpack_skip_pixels_ = param;
1580 return;
1581 case GL_UNPACK_SKIP_IMAGES:
1582 unpack_skip_images_ = param;
1583 return;
1584 case GL_UNPACK_FLIP_Y_CHROMIUM:
1585 unpack_flip_y_ = (param != 0);
1586 break;
1587 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1588 pack_reverse_row_order_ =
1589 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1590 break;
1591 default:
1592 break;
1594 helper_->PixelStorei(pname, param);
1595 CheckGLError();
1598 void GLES2Implementation::VertexAttribIPointer(
1599 GLuint index, GLint size, GLenum type, GLsizei stride, const void* ptr) {
1600 GPU_CLIENT_SINGLE_THREAD_CHECK();
1601 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribIPointer("
1602 << index << ", "
1603 << size << ", "
1604 << GLES2Util::GetStringVertexAttribIType(type) << ", "
1605 << stride << ", "
1606 << ptr << ")");
1607 // Record the info on the client side.
1608 if (!vertex_array_object_manager_->SetAttribPointer(bound_array_buffer_,
1609 index,
1610 size,
1611 type,
1612 GL_FALSE,
1613 stride,
1614 ptr,
1615 GL_TRUE)) {
1616 SetGLError(GL_INVALID_OPERATION, "glVertexAttribIPointer",
1617 "client side arrays are not allowed in vertex array objects.");
1618 return;
1620 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
1621 // Only report NON client side buffers to the service.
1622 if (!ValidateOffset("glVertexAttribIPointer",
1623 reinterpret_cast<GLintptr>(ptr))) {
1624 return;
1626 helper_->VertexAttribIPointer(index, size, type, stride, ToGLuint(ptr));
1628 CheckGLError();
1631 void GLES2Implementation::VertexAttribPointer(
1632 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1633 const void* ptr) {
1634 GPU_CLIENT_SINGLE_THREAD_CHECK();
1635 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1636 << index << ", "
1637 << size << ", "
1638 << GLES2Util::GetStringVertexAttribType(type) << ", "
1639 << GLES2Util::GetStringBool(normalized) << ", "
1640 << stride << ", "
1641 << ptr << ")");
1642 // Record the info on the client side.
1643 if (!vertex_array_object_manager_->SetAttribPointer(bound_array_buffer_,
1644 index,
1645 size,
1646 type,
1647 normalized,
1648 stride,
1649 ptr,
1650 GL_FALSE)) {
1651 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1652 "client side arrays are not allowed in vertex array objects.");
1653 return;
1655 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
1656 // Only report NON client side buffers to the service.
1657 if (!ValidateOffset("glVertexAttribPointer",
1658 reinterpret_cast<GLintptr>(ptr))) {
1659 return;
1661 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1662 ToGLuint(ptr));
1664 CheckGLError();
1667 void GLES2Implementation::VertexAttribDivisorANGLE(
1668 GLuint index, GLuint divisor) {
1669 GPU_CLIENT_SINGLE_THREAD_CHECK();
1670 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1671 << index << ", "
1672 << divisor << ") ");
1673 // Record the info on the client side.
1674 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1675 helper_->VertexAttribDivisorANGLE(index, divisor);
1676 CheckGLError();
1679 void GLES2Implementation::BufferDataHelper(
1680 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1681 if (!ValidateSize("glBufferData", size))
1682 return;
1684 #if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
1685 // Do not upload uninitialized data. Even if it's not a bug, it can cause a
1686 // bogus MSan report during a readback later. This is because MSan doesn't
1687 // understand shared memory and would assume we were reading back the same
1688 // unintialized data.
1689 if (data) __msan_check_mem_is_initialized(data, size);
1690 #endif
1692 GLuint buffer_id;
1693 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1694 if (!buffer_id) {
1695 return;
1698 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1699 if (buffer)
1700 RemoveTransferBuffer(buffer);
1702 // Create new buffer.
1703 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1704 DCHECK(buffer);
1705 if (buffer->address() && data)
1706 memcpy(buffer->address(), data, size);
1707 return;
1710 RemoveMappedBufferRangeByTarget(target);
1712 // If there is no data just send BufferData
1713 if (size == 0 || !data) {
1714 helper_->BufferData(target, size, 0, 0, usage);
1715 return;
1718 // See if we can send all at once.
1719 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1720 if (!buffer.valid()) {
1721 return;
1724 if (buffer.size() >= static_cast<unsigned int>(size)) {
1725 memcpy(buffer.address(), data, size);
1726 helper_->BufferData(
1727 target,
1728 size,
1729 buffer.shm_id(),
1730 buffer.offset(),
1731 usage);
1732 return;
1735 // Make the buffer with BufferData then send via BufferSubData
1736 helper_->BufferData(target, size, 0, 0, usage);
1737 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1738 CheckGLError();
1741 void GLES2Implementation::BufferData(
1742 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1743 GPU_CLIENT_SINGLE_THREAD_CHECK();
1744 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1745 << GLES2Util::GetStringBufferTarget(target) << ", "
1746 << size << ", "
1747 << static_cast<const void*>(data) << ", "
1748 << GLES2Util::GetStringBufferUsage(usage) << ")");
1749 BufferDataHelper(target, size, data, usage);
1750 CheckGLError();
1753 void GLES2Implementation::BufferSubDataHelper(
1754 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1755 if (size == 0) {
1756 return;
1759 if (!ValidateSize("glBufferSubData", size) ||
1760 !ValidateOffset("glBufferSubData", offset)) {
1761 return;
1764 GLuint buffer_id;
1765 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1766 if (!buffer_id) {
1767 return;
1769 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1770 if (!buffer) {
1771 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1772 return;
1775 int32 end = 0;
1776 int32 buffer_size = buffer->size();
1777 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1778 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1779 return;
1782 if (buffer->address() && data)
1783 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1784 return;
1787 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1788 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1791 void GLES2Implementation::BufferSubDataHelperImpl(
1792 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1793 ScopedTransferBufferPtr* buffer) {
1794 DCHECK(buffer);
1795 DCHECK_GT(size, 0);
1797 const int8* source = static_cast<const int8*>(data);
1798 while (size) {
1799 if (!buffer->valid() || buffer->size() == 0) {
1800 buffer->Reset(size);
1801 if (!buffer->valid()) {
1802 return;
1805 memcpy(buffer->address(), source, buffer->size());
1806 helper_->BufferSubData(
1807 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1808 offset += buffer->size();
1809 source += buffer->size();
1810 size -= buffer->size();
1811 buffer->Release();
1815 void GLES2Implementation::BufferSubData(
1816 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1817 GPU_CLIENT_SINGLE_THREAD_CHECK();
1818 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1819 << GLES2Util::GetStringBufferTarget(target) << ", "
1820 << offset << ", " << size << ", "
1821 << static_cast<const void*>(data) << ")");
1822 BufferSubDataHelper(target, offset, size, data);
1823 CheckGLError();
1826 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
1827 int32 token = buffer->last_usage_token();
1828 uint32 async_token = buffer->last_async_upload_token();
1830 if (async_token) {
1831 if (HasAsyncUploadTokenPassed(async_token)) {
1832 buffer_tracker_->Free(buffer);
1833 } else {
1834 detached_async_upload_memory_.push_back(
1835 std::make_pair(buffer->address(), async_token));
1836 buffer_tracker_->Unmanage(buffer);
1838 } else if (token) {
1839 if (helper_->HasTokenPassed(token))
1840 buffer_tracker_->Free(buffer);
1841 else
1842 buffer_tracker_->FreePendingToken(buffer, token);
1843 } else {
1844 buffer_tracker_->Free(buffer);
1847 buffer_tracker_->RemoveBuffer(buffer->id());
1850 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1851 GLenum target,
1852 const char* function_name,
1853 GLuint* buffer_id) {
1854 *buffer_id = 0;
1856 switch (target) {
1857 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1858 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1859 break;
1860 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1861 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1862 break;
1863 default:
1864 // Unknown target
1865 return false;
1867 if (!*buffer_id) {
1868 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1870 return true;
1873 BufferTracker::Buffer*
1874 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1875 GLuint buffer_id,
1876 const char* function_name,
1877 GLuint offset, GLsizei size) {
1878 DCHECK(buffer_id);
1879 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1880 if (!buffer) {
1881 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1882 return NULL;
1884 if (buffer->mapped()) {
1885 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1886 return NULL;
1888 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1889 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1890 return NULL;
1892 return buffer;
1895 void GLES2Implementation::CompressedTexImage2D(
1896 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1897 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1898 GPU_CLIENT_SINGLE_THREAD_CHECK();
1899 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1900 << GLES2Util::GetStringTextureTarget(target) << ", "
1901 << level << ", "
1902 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1903 << width << ", " << height << ", " << border << ", "
1904 << image_size << ", "
1905 << static_cast<const void*>(data) << ")");
1906 if (width < 0 || height < 0 || level < 0) {
1907 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1908 return;
1910 if (border != 0) {
1911 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "border != 0");
1912 return;
1914 if (height == 0 || width == 0) {
1915 return;
1917 // If there's a pixel unpack buffer bound use it when issuing
1918 // CompressedTexImage2D.
1919 if (bound_pixel_unpack_transfer_buffer_id_) {
1920 GLuint offset = ToGLuint(data);
1921 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1922 bound_pixel_unpack_transfer_buffer_id_,
1923 "glCompressedTexImage2D", offset, image_size);
1924 if (buffer && buffer->shm_id() != -1) {
1925 helper_->CompressedTexImage2D(
1926 target, level, internalformat, width, height, image_size,
1927 buffer->shm_id(), buffer->shm_offset() + offset);
1928 buffer->set_last_usage_token(helper_->InsertToken());
1930 return;
1932 SetBucketContents(kResultBucketId, data, image_size);
1933 helper_->CompressedTexImage2DBucket(
1934 target, level, internalformat, width, height, kResultBucketId);
1935 // Free the bucket. This is not required but it does free up the memory.
1936 // and we don't have to wait for the result so from the client's perspective
1937 // it's cheap.
1938 helper_->SetBucketSize(kResultBucketId, 0);
1939 CheckGLError();
1942 void GLES2Implementation::CompressedTexSubImage2D(
1943 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1944 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1945 GPU_CLIENT_SINGLE_THREAD_CHECK();
1946 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1947 << GLES2Util::GetStringTextureTarget(target) << ", "
1948 << level << ", "
1949 << xoffset << ", " << yoffset << ", "
1950 << width << ", " << height << ", "
1951 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1952 << image_size << ", "
1953 << static_cast<const void*>(data) << ")");
1954 if (width < 0 || height < 0 || level < 0) {
1955 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1956 return;
1958 // If there's a pixel unpack buffer bound use it when issuing
1959 // CompressedTexSubImage2D.
1960 if (bound_pixel_unpack_transfer_buffer_id_) {
1961 GLuint offset = ToGLuint(data);
1962 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1963 bound_pixel_unpack_transfer_buffer_id_,
1964 "glCompressedTexSubImage2D", offset, image_size);
1965 if (buffer && buffer->shm_id() != -1) {
1966 helper_->CompressedTexSubImage2D(
1967 target, level, xoffset, yoffset, width, height, format, image_size,
1968 buffer->shm_id(), buffer->shm_offset() + offset);
1969 buffer->set_last_usage_token(helper_->InsertToken());
1970 CheckGLError();
1972 return;
1974 SetBucketContents(kResultBucketId, data, image_size);
1975 helper_->CompressedTexSubImage2DBucket(
1976 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1977 // Free the bucket. This is not required but it does free up the memory.
1978 // and we don't have to wait for the result so from the client's perspective
1979 // it's cheap.
1980 helper_->SetBucketSize(kResultBucketId, 0);
1981 CheckGLError();
1984 void GLES2Implementation::CompressedTexImage3D(
1985 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1986 GLsizei height, GLsizei depth, GLint border, GLsizei image_size,
1987 const void* data) {
1988 GPU_CLIENT_SINGLE_THREAD_CHECK();
1989 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage3D("
1990 << GLES2Util::GetStringTexture3DTarget(target) << ", " << level << ", "
1991 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1992 << width << ", " << height << ", " << depth << ", " << border << ", "
1993 << image_size << ", " << static_cast<const void*>(data) << ")");
1994 if (width < 0 || height < 0 || depth < 0 || level < 0) {
1995 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "dimension < 0");
1996 return;
1998 if (border != 0) {
1999 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "border != 0");
2000 return;
2002 if (height == 0 || width == 0 || depth == 0) {
2003 return;
2005 // If there's a pixel unpack buffer bound use it when issuing
2006 // CompressedTexImage3D.
2007 if (bound_pixel_unpack_transfer_buffer_id_) {
2008 GLuint offset = ToGLuint(data);
2009 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2010 bound_pixel_unpack_transfer_buffer_id_,
2011 "glCompressedTexImage3D", offset, image_size);
2012 if (buffer && buffer->shm_id() != -1) {
2013 helper_->CompressedTexImage3D(
2014 target, level, internalformat, width, height, depth, image_size,
2015 buffer->shm_id(), buffer->shm_offset() + offset);
2016 buffer->set_last_usage_token(helper_->InsertToken());
2018 return;
2020 SetBucketContents(kResultBucketId, data, image_size);
2021 helper_->CompressedTexImage3DBucket(
2022 target, level, internalformat, width, height, depth, kResultBucketId);
2023 // Free the bucket. This is not required but it does free up the memory.
2024 // and we don't have to wait for the result so from the client's perspective
2025 // it's cheap.
2026 helper_->SetBucketSize(kResultBucketId, 0);
2027 CheckGLError();
2030 void GLES2Implementation::CompressedTexSubImage3D(
2031 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2032 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2033 GLsizei image_size, const void* data) {
2034 GPU_CLIENT_SINGLE_THREAD_CHECK();
2035 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage3D("
2036 << GLES2Util::GetStringTextureTarget(target) << ", "
2037 << level << ", "
2038 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2039 << width << ", " << height << ", " << depth << ", "
2040 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
2041 << image_size << ", "
2042 << static_cast<const void*>(data) << ")");
2043 if (width < 0 || height < 0 || depth < 0 || level < 0) {
2044 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage3D", "dimension < 0");
2045 return;
2047 // If there's a pixel unpack buffer bound use it when issuing
2048 // CompressedTexSubImage3D.
2049 if (bound_pixel_unpack_transfer_buffer_id_) {
2050 GLuint offset = ToGLuint(data);
2051 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2052 bound_pixel_unpack_transfer_buffer_id_,
2053 "glCompressedTexSubImage3D", offset, image_size);
2054 if (buffer && buffer->shm_id() != -1) {
2055 helper_->CompressedTexSubImage3D(
2056 target, level, xoffset, yoffset, zoffset,
2057 width, height, depth, format, image_size,
2058 buffer->shm_id(), buffer->shm_offset() + offset);
2059 buffer->set_last_usage_token(helper_->InsertToken());
2060 CheckGLError();
2062 return;
2064 SetBucketContents(kResultBucketId, data, image_size);
2065 helper_->CompressedTexSubImage3DBucket(
2066 target, level, xoffset, yoffset, zoffset, width, height, depth, format,
2067 kResultBucketId);
2068 // Free the bucket. This is not required but it does free up the memory.
2069 // and we don't have to wait for the result so from the client's perspective
2070 // it's cheap.
2071 helper_->SetBucketSize(kResultBucketId, 0);
2072 CheckGLError();
2075 namespace {
2077 void CopyRectToBuffer(
2078 const void* pixels,
2079 uint32 height,
2080 uint32 unpadded_row_size,
2081 uint32 pixels_padded_row_size,
2082 bool flip_y,
2083 void* buffer,
2084 uint32 buffer_padded_row_size) {
2085 const int8* source = static_cast<const int8*>(pixels);
2086 int8* dest = static_cast<int8*>(buffer);
2087 if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
2088 if (flip_y) {
2089 dest += buffer_padded_row_size * (height - 1);
2091 // the last row is copied unpadded at the end
2092 for (; height > 1; --height) {
2093 memcpy(dest, source, buffer_padded_row_size);
2094 if (flip_y) {
2095 dest -= buffer_padded_row_size;
2096 } else {
2097 dest += buffer_padded_row_size;
2099 source += pixels_padded_row_size;
2101 memcpy(dest, source, unpadded_row_size);
2102 } else {
2103 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
2104 memcpy(dest, source, size);
2108 } // anonymous namespace
2110 void GLES2Implementation::TexImage2D(
2111 GLenum target, GLint level, GLint internalformat, GLsizei width,
2112 GLsizei height, GLint border, GLenum format, GLenum type,
2113 const void* pixels) {
2114 GPU_CLIENT_SINGLE_THREAD_CHECK();
2115 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
2116 << GLES2Util::GetStringTextureTarget(target) << ", "
2117 << level << ", "
2118 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2119 << width << ", " << height << ", " << border << ", "
2120 << GLES2Util::GetStringTextureFormat(format) << ", "
2121 << GLES2Util::GetStringPixelType(type) << ", "
2122 << static_cast<const void*>(pixels) << ")");
2123 if (level < 0 || height < 0 || width < 0) {
2124 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
2125 return;
2127 if (border != 0) {
2128 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
2129 return;
2131 uint32 size;
2132 uint32 unpadded_row_size;
2133 uint32 padded_row_size;
2134 if (!GLES2Util::ComputeImageDataSizes(
2135 width, height, 1, format, type, unpack_alignment_, &size,
2136 &unpadded_row_size, &padded_row_size)) {
2137 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
2138 return;
2141 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
2142 if (bound_pixel_unpack_transfer_buffer_id_) {
2143 GLuint offset = ToGLuint(pixels);
2144 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2145 bound_pixel_unpack_transfer_buffer_id_,
2146 "glTexImage2D", offset, size);
2147 if (buffer && buffer->shm_id() != -1) {
2148 helper_->TexImage2D(
2149 target, level, internalformat, width, height, format, type,
2150 buffer->shm_id(), buffer->shm_offset() + offset);
2151 buffer->set_last_usage_token(helper_->InsertToken());
2152 CheckGLError();
2154 return;
2157 // If there's no data just issue TexImage2D
2158 if (!pixels) {
2159 helper_->TexImage2D(
2160 target, level, internalformat, width, height, format, type,
2161 0, 0);
2162 CheckGLError();
2163 return;
2166 // compute the advance bytes per row for the src pixels
2167 uint32 src_padded_row_size;
2168 if (unpack_row_length_ > 0) {
2169 if (!GLES2Util::ComputeImagePaddedRowSize(
2170 unpack_row_length_, format, type, unpack_alignment_,
2171 &src_padded_row_size)) {
2172 SetGLError(
2173 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2174 return;
2176 } else {
2177 src_padded_row_size = padded_row_size;
2180 // advance pixels pointer past the skip rows and skip pixels
2181 pixels = reinterpret_cast<const int8*>(pixels) +
2182 unpack_skip_rows_ * src_padded_row_size;
2183 if (unpack_skip_pixels_) {
2184 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2185 pixels = reinterpret_cast<const int8*>(pixels) +
2186 unpack_skip_pixels_ * group_size;
2189 // Check if we can send it all at once.
2190 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
2191 if (!buffer.valid()) {
2192 return;
2195 if (buffer.size() >= size) {
2196 CopyRectToBuffer(
2197 pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
2198 buffer.address(), padded_row_size);
2199 helper_->TexImage2D(
2200 target, level, internalformat, width, height, format, type,
2201 buffer.shm_id(), buffer.offset());
2202 CheckGLError();
2203 return;
2206 // No, so send it using TexSubImage2D.
2207 helper_->TexImage2D(
2208 target, level, internalformat, width, height, format, type,
2209 0, 0);
2210 TexSubImage2DImpl(
2211 target, level, 0, 0, width, height, format, type, unpadded_row_size,
2212 pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
2213 CheckGLError();
2216 void GLES2Implementation::TexImage3D(
2217 GLenum target, GLint level, GLint internalformat, GLsizei width,
2218 GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type,
2219 const void* pixels) {
2220 GPU_CLIENT_SINGLE_THREAD_CHECK();
2221 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D("
2222 << GLES2Util::GetStringTextureTarget(target) << ", "
2223 << level << ", "
2224 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2225 << width << ", " << height << ", " << depth << ", " << border << ", "
2226 << GLES2Util::GetStringTextureFormat(format) << ", "
2227 << GLES2Util::GetStringPixelType(type) << ", "
2228 << static_cast<const void*>(pixels) << ")");
2229 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2230 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "dimension < 0");
2231 return;
2233 if (border != 0) {
2234 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "border != 0");
2235 return;
2237 uint32 size;
2238 uint32 unpadded_row_size;
2239 uint32 padded_row_size;
2240 if (!GLES2Util::ComputeImageDataSizes(
2241 width, height, depth, format, type, unpack_alignment_, &size,
2242 &unpadded_row_size, &padded_row_size)) {
2243 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large");
2244 return;
2247 // If there's a pixel unpack buffer bound use it when issuing TexImage3D.
2248 if (bound_pixel_unpack_transfer_buffer_id_) {
2249 GLuint offset = ToGLuint(pixels);
2250 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2251 bound_pixel_unpack_transfer_buffer_id_,
2252 "glTexImage3D", offset, size);
2253 if (buffer && buffer->shm_id() != -1) {
2254 helper_->TexImage3D(
2255 target, level, internalformat, width, height, depth, format, type,
2256 buffer->shm_id(), buffer->shm_offset() + offset);
2257 buffer->set_last_usage_token(helper_->InsertToken());
2258 CheckGLError();
2260 return;
2263 // If there's no data just issue TexImage3D
2264 if (!pixels) {
2265 helper_->TexImage3D(
2266 target, level, internalformat, width, height, depth, format, type,
2267 0, 0);
2268 CheckGLError();
2269 return;
2272 // compute the advance bytes per row for the src pixels
2273 uint32 src_padded_row_size;
2274 if (unpack_row_length_ > 0) {
2275 if (!GLES2Util::ComputeImagePaddedRowSize(
2276 unpack_row_length_, format, type, unpack_alignment_,
2277 &src_padded_row_size)) {
2278 SetGLError(
2279 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2280 return;
2282 } else {
2283 src_padded_row_size = padded_row_size;
2285 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2287 // advance pixels pointer past the skip images/rows/pixels
2288 pixels = reinterpret_cast<const int8*>(pixels) +
2289 unpack_skip_images_ * src_padded_row_size * src_height +
2290 unpack_skip_rows_ * src_padded_row_size;
2291 if (unpack_skip_pixels_) {
2292 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2293 pixels = reinterpret_cast<const int8*>(pixels) +
2294 unpack_skip_pixels_ * group_size;
2297 // Check if we can send it all at once.
2298 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
2299 if (!buffer.valid()) {
2300 return;
2303 if (buffer.size() >= size) {
2304 void* buffer_pointer = buffer.address();
2305 for (GLsizei z = 0; z < depth; ++z) {
2306 // Only the last row of the last image is unpadded.
2307 uint32 src_unpadded_row_size =
2308 (z == depth - 1) ? unpadded_row_size : src_padded_row_size;
2309 // TODO(zmo): Ignore flip_y flag for now.
2310 CopyRectToBuffer(
2311 pixels, height, src_unpadded_row_size, src_padded_row_size, false,
2312 buffer_pointer, padded_row_size);
2313 pixels = reinterpret_cast<const int8*>(pixels) +
2314 src_padded_row_size * src_height;
2315 buffer_pointer = reinterpret_cast<int8*>(buffer_pointer) +
2316 padded_row_size * height;
2318 helper_->TexImage3D(
2319 target, level, internalformat, width, height, depth, format, type,
2320 buffer.shm_id(), buffer.offset());
2321 CheckGLError();
2322 return;
2325 // No, so send it using TexSubImage3D.
2326 helper_->TexImage3D(
2327 target, level, internalformat, width, height, depth, format, type,
2328 0, 0);
2329 TexSubImage3DImpl(
2330 target, level, 0, 0, 0, width, height, depth, format, type,
2331 unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &buffer,
2332 padded_row_size);
2333 CheckGLError();
2336 void GLES2Implementation::TexSubImage2D(
2337 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2338 GLsizei height, GLenum format, GLenum type, const void* pixels) {
2339 GPU_CLIENT_SINGLE_THREAD_CHECK();
2340 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
2341 << GLES2Util::GetStringTextureTarget(target) << ", "
2342 << level << ", "
2343 << xoffset << ", " << yoffset << ", "
2344 << width << ", " << height << ", "
2345 << GLES2Util::GetStringTextureFormat(format) << ", "
2346 << GLES2Util::GetStringPixelType(type) << ", "
2347 << static_cast<const void*>(pixels) << ")");
2349 if (level < 0 || height < 0 || width < 0) {
2350 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
2351 return;
2353 if (height == 0 || width == 0) {
2354 return;
2357 uint32 temp_size;
2358 uint32 unpadded_row_size;
2359 uint32 padded_row_size;
2360 if (!GLES2Util::ComputeImageDataSizes(
2361 width, height, 1, format, type, unpack_alignment_, &temp_size,
2362 &unpadded_row_size, &padded_row_size)) {
2363 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
2364 return;
2367 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2368 if (bound_pixel_unpack_transfer_buffer_id_) {
2369 GLuint offset = ToGLuint(pixels);
2370 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2371 bound_pixel_unpack_transfer_buffer_id_,
2372 "glTexSubImage2D", offset, temp_size);
2373 if (buffer && buffer->shm_id() != -1) {
2374 helper_->TexSubImage2D(
2375 target, level, xoffset, yoffset, width, height, format, type,
2376 buffer->shm_id(), buffer->shm_offset() + offset, false);
2377 buffer->set_last_usage_token(helper_->InsertToken());
2378 CheckGLError();
2380 return;
2383 // compute the advance bytes per row for the src pixels
2384 uint32 src_padded_row_size;
2385 if (unpack_row_length_ > 0) {
2386 if (!GLES2Util::ComputeImagePaddedRowSize(
2387 unpack_row_length_, format, type, unpack_alignment_,
2388 &src_padded_row_size)) {
2389 SetGLError(
2390 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2391 return;
2393 } else {
2394 src_padded_row_size = padded_row_size;
2397 // advance pixels pointer past the skip rows and skip pixels
2398 pixels = reinterpret_cast<const int8*>(pixels) +
2399 unpack_skip_rows_ * src_padded_row_size;
2400 if (unpack_skip_pixels_) {
2401 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2402 pixels = reinterpret_cast<const int8*>(pixels) +
2403 unpack_skip_pixels_ * group_size;
2406 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2407 TexSubImage2DImpl(
2408 target, level, xoffset, yoffset, width, height, format, type,
2409 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
2410 padded_row_size);
2411 CheckGLError();
2414 void GLES2Implementation::TexSubImage3D(
2415 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2416 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2417 const void* pixels) {
2418 GPU_CLIENT_SINGLE_THREAD_CHECK();
2419 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D("
2420 << GLES2Util::GetStringTextureTarget(target) << ", "
2421 << level << ", "
2422 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2423 << width << ", " << height << ", " << depth << ", "
2424 << GLES2Util::GetStringTextureFormat(format) << ", "
2425 << GLES2Util::GetStringPixelType(type) << ", "
2426 << static_cast<const void*>(pixels) << ")");
2428 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2429 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "dimension < 0");
2430 return;
2432 if (height == 0 || width == 0 || depth == 0) {
2433 return;
2436 uint32 temp_size;
2437 uint32 unpadded_row_size;
2438 uint32 padded_row_size;
2439 if (!GLES2Util::ComputeImageDataSizes(
2440 width, height, depth, format, type, unpack_alignment_, &temp_size,
2441 &unpadded_row_size, &padded_row_size)) {
2442 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "size to large");
2443 return;
2446 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2447 if (bound_pixel_unpack_transfer_buffer_id_) {
2448 GLuint offset = ToGLuint(pixels);
2449 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2450 bound_pixel_unpack_transfer_buffer_id_,
2451 "glTexSubImage3D", offset, temp_size);
2452 if (buffer && buffer->shm_id() != -1) {
2453 helper_->TexSubImage3D(
2454 target, level, xoffset, yoffset, zoffset, width, height, depth,
2455 format, type, buffer->shm_id(), buffer->shm_offset() + offset, false);
2456 buffer->set_last_usage_token(helper_->InsertToken());
2457 CheckGLError();
2459 return;
2462 // compute the advance bytes per row for the src pixels
2463 uint32 src_padded_row_size;
2464 if (unpack_row_length_ > 0) {
2465 if (!GLES2Util::ComputeImagePaddedRowSize(
2466 unpack_row_length_, format, type, unpack_alignment_,
2467 &src_padded_row_size)) {
2468 SetGLError(
2469 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2470 return;
2472 } else {
2473 src_padded_row_size = padded_row_size;
2475 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2477 // advance pixels pointer past the skip images/rows/pixels
2478 pixels = reinterpret_cast<const int8*>(pixels) +
2479 unpack_skip_images_ * src_padded_row_size * src_height +
2480 unpack_skip_rows_ * src_padded_row_size;
2481 if (unpack_skip_pixels_) {
2482 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2483 pixels = reinterpret_cast<const int8*>(pixels) +
2484 unpack_skip_pixels_ * group_size;
2487 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2488 TexSubImage3DImpl(
2489 target, level, xoffset, yoffset, zoffset, width, height, depth,
2490 format, type, unpadded_row_size, pixels, src_padded_row_size, GL_FALSE,
2491 &buffer, padded_row_size);
2492 CheckGLError();
2495 static GLint ComputeNumRowsThatFitInBuffer(
2496 uint32 padded_row_size, uint32 unpadded_row_size,
2497 unsigned int size, GLsizei remaining_rows) {
2498 DCHECK_GE(unpadded_row_size, 0u);
2499 if (padded_row_size == 0) {
2500 return 1;
2502 GLint num_rows = size / padded_row_size;
2503 if (num_rows + 1 == remaining_rows &&
2504 size - num_rows * padded_row_size >= unpadded_row_size) {
2505 num_rows++;
2507 return num_rows;
2510 void GLES2Implementation::TexSubImage2DImpl(
2511 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2512 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
2513 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
2514 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
2515 DCHECK(buffer);
2516 DCHECK_GE(level, 0);
2517 DCHECK_GT(height, 0);
2518 DCHECK_GT(width, 0);
2520 const int8* source = reinterpret_cast<const int8*>(pixels);
2521 GLint original_yoffset = yoffset;
2522 // Transfer by rows.
2523 while (height) {
2524 unsigned int desired_size =
2525 buffer_padded_row_size * (height - 1) + unpadded_row_size;
2526 if (!buffer->valid() || buffer->size() == 0) {
2527 buffer->Reset(desired_size);
2528 if (!buffer->valid()) {
2529 return;
2533 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2534 buffer_padded_row_size, unpadded_row_size, buffer->size(), height);
2535 num_rows = std::min(num_rows, height);
2536 CopyRectToBuffer(
2537 source, num_rows, unpadded_row_size, pixels_padded_row_size,
2538 unpack_flip_y_, buffer->address(), buffer_padded_row_size);
2539 GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
2540 helper_->TexSubImage2D(
2541 target, level, xoffset, y, width, num_rows, format, type,
2542 buffer->shm_id(), buffer->offset(), internal);
2543 buffer->Release();
2544 yoffset += num_rows;
2545 source += num_rows * pixels_padded_row_size;
2546 height -= num_rows;
2550 void GLES2Implementation::TexSubImage3DImpl(
2551 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei zoffset,
2552 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2553 uint32 unpadded_row_size, const void* pixels, uint32 pixels_padded_row_size,
2554 GLboolean internal, ScopedTransferBufferPtr* buffer,
2555 uint32 buffer_padded_row_size) {
2556 DCHECK(buffer);
2557 DCHECK_GE(level, 0);
2558 DCHECK_GT(height, 0);
2559 DCHECK_GT(width, 0);
2560 DCHECK_GT(depth, 0);
2561 const int8* source = reinterpret_cast<const int8*>(pixels);
2562 GLsizei total_rows = height * depth;
2563 GLint row_index = 0, depth_index = 0;
2564 while (total_rows) {
2565 // Each time, we either copy one or more images, or copy one or more rows
2566 // within a single image, depending on the buffer size limit.
2567 GLsizei max_rows;
2568 unsigned int desired_size;
2569 if (row_index > 0) {
2570 // We are in the middle of an image. Send the remaining of the image.
2571 max_rows = height - row_index;
2572 if (total_rows <= height) {
2573 // Last image, so last row is unpadded.
2574 desired_size = buffer_padded_row_size * (max_rows - 1) +
2575 unpadded_row_size;
2576 } else {
2577 desired_size = buffer_padded_row_size * max_rows;
2579 } else {
2580 // Send all the remaining data if possible.
2581 max_rows = total_rows;
2582 desired_size =
2583 buffer_padded_row_size * (max_rows - 1) + unpadded_row_size;
2585 if (!buffer->valid() || buffer->size() == 0) {
2586 buffer->Reset(desired_size);
2587 if (!buffer->valid()) {
2588 return;
2591 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2592 buffer_padded_row_size, unpadded_row_size, buffer->size(), total_rows);
2593 num_rows = std::min(num_rows, max_rows);
2594 GLint num_images = num_rows / height;
2595 GLsizei my_height, my_depth;
2596 if (num_images > 0) {
2597 num_rows = num_images * height;
2598 my_height = height;
2599 my_depth = num_images;
2600 } else {
2601 my_height = num_rows;
2602 my_depth = 1;
2605 // TODO(zmo): Ignore flip_y flag for now.
2606 if (num_images > 0) {
2607 int8* buffer_pointer = reinterpret_cast<int8*>(buffer->address());
2608 uint32 src_height =
2609 unpack_image_height_ > 0 ? unpack_image_height_ : height;
2610 uint32 image_size_dst = buffer_padded_row_size * height;
2611 uint32 image_size_src = pixels_padded_row_size * src_height;
2612 for (GLint ii = 0; ii < num_images; ++ii) {
2613 uint32 my_unpadded_row_size;
2614 if (total_rows == num_rows && ii + 1 == num_images)
2615 my_unpadded_row_size = unpadded_row_size;
2616 else
2617 my_unpadded_row_size = pixels_padded_row_size;
2618 CopyRectToBuffer(
2619 source + ii * image_size_src, my_height, my_unpadded_row_size,
2620 pixels_padded_row_size, false, buffer_pointer + ii * image_size_dst,
2621 buffer_padded_row_size);
2623 } else {
2624 uint32 my_unpadded_row_size;
2625 if (total_rows == num_rows)
2626 my_unpadded_row_size = unpadded_row_size;
2627 else
2628 my_unpadded_row_size = pixels_padded_row_size;
2629 CopyRectToBuffer(
2630 source, my_height, my_unpadded_row_size, pixels_padded_row_size,
2631 false, buffer->address(), buffer_padded_row_size);
2633 helper_->TexSubImage3D(
2634 target, level, xoffset, yoffset + row_index, zoffset + depth_index,
2635 width, my_height, my_depth,
2636 format, type, buffer->shm_id(), buffer->offset(), internal);
2637 buffer->Release();
2639 total_rows -= num_rows;
2640 if (total_rows > 0) {
2641 GLint num_image_paddings;
2642 if (num_images > 0) {
2643 DCHECK_EQ(row_index, 0);
2644 depth_index += num_images;
2645 num_image_paddings = num_images;
2646 } else {
2647 row_index = (row_index + my_height) % height;
2648 num_image_paddings = 0;
2649 if (my_height > 0 && row_index == 0) {
2650 depth_index++;
2651 num_image_paddings++;
2654 source += num_rows * pixels_padded_row_size;
2655 if (unpack_image_height_ > height && num_image_paddings > 0) {
2656 source += num_image_paddings * (unpack_image_height_ - height) *
2657 pixels_padded_row_size;
2663 bool GLES2Implementation::GetActiveAttribHelper(
2664 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2665 GLenum* type, char* name) {
2666 // Clear the bucket so if the command fails nothing will be in it.
2667 helper_->SetBucketSize(kResultBucketId, 0);
2668 typedef cmds::GetActiveAttrib::Result Result;
2669 Result* result = GetResultAs<Result*>();
2670 if (!result) {
2671 return false;
2673 // Set as failed so if the command fails we'll recover.
2674 result->success = false;
2675 helper_->GetActiveAttrib(program, index, kResultBucketId,
2676 GetResultShmId(), GetResultShmOffset());
2677 WaitForCmd();
2678 if (result->success) {
2679 if (size) {
2680 *size = result->size;
2682 if (type) {
2683 *type = result->type;
2685 if (length || name) {
2686 std::vector<int8> str;
2687 GetBucketContents(kResultBucketId, &str);
2688 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2689 std::max(static_cast<size_t>(0),
2690 str.size() - 1));
2691 if (length) {
2692 *length = max_size;
2694 if (name && bufsize > 0) {
2695 memcpy(name, &str[0], max_size);
2696 name[max_size] = '\0';
2700 return result->success != 0;
2703 void GLES2Implementation::GetActiveAttrib(
2704 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2705 GLenum* type, char* name) {
2706 GPU_CLIENT_SINGLE_THREAD_CHECK();
2707 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2708 << program << ", " << index << ", " << bufsize << ", "
2709 << static_cast<const void*>(length) << ", "
2710 << static_cast<const void*>(size) << ", "
2711 << static_cast<const void*>(type) << ", "
2712 << static_cast<const void*>(name) << ", ");
2713 if (bufsize < 0) {
2714 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
2715 return;
2717 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2718 bool success = share_group_->program_info_manager()->GetActiveAttrib(
2719 this, program, index, bufsize, length, size, type, name);
2720 if (success) {
2721 if (size) {
2722 GPU_CLIENT_LOG(" size: " << *size);
2724 if (type) {
2725 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2727 if (name) {
2728 GPU_CLIENT_LOG(" name: " << name);
2731 CheckGLError();
2734 bool GLES2Implementation::GetActiveUniformHelper(
2735 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2736 GLenum* type, char* name) {
2737 // Clear the bucket so if the command fails nothing will be in it.
2738 helper_->SetBucketSize(kResultBucketId, 0);
2739 typedef cmds::GetActiveUniform::Result Result;
2740 Result* result = GetResultAs<Result*>();
2741 if (!result) {
2742 return false;
2744 // Set as failed so if the command fails we'll recover.
2745 result->success = false;
2746 helper_->GetActiveUniform(program, index, kResultBucketId,
2747 GetResultShmId(), GetResultShmOffset());
2748 WaitForCmd();
2749 if (result->success) {
2750 if (size) {
2751 *size = result->size;
2753 if (type) {
2754 *type = result->type;
2756 if (length || name) {
2757 std::vector<int8> str;
2758 GetBucketContents(kResultBucketId, &str);
2759 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2760 std::max(static_cast<size_t>(0),
2761 str.size() - 1));
2762 if (length) {
2763 *length = max_size;
2765 if (name && bufsize > 0) {
2766 memcpy(name, &str[0], max_size);
2767 name[max_size] = '\0';
2771 return result->success != 0;
2774 void GLES2Implementation::GetActiveUniform(
2775 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2776 GLenum* type, char* name) {
2777 GPU_CLIENT_SINGLE_THREAD_CHECK();
2778 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2779 << program << ", " << index << ", " << bufsize << ", "
2780 << static_cast<const void*>(length) << ", "
2781 << static_cast<const void*>(size) << ", "
2782 << static_cast<const void*>(type) << ", "
2783 << static_cast<const void*>(name) << ", ");
2784 if (bufsize < 0) {
2785 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2786 return;
2788 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2789 bool success = share_group_->program_info_manager()->GetActiveUniform(
2790 this, program, index, bufsize, length, size, type, name);
2791 if (success) {
2792 if (size) {
2793 GPU_CLIENT_LOG(" size: " << *size);
2795 if (type) {
2796 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2798 if (name) {
2799 GPU_CLIENT_LOG(" name: " << name);
2802 CheckGLError();
2805 bool GLES2Implementation::GetActiveUniformBlockNameHelper(
2806 GLuint program, GLuint index, GLsizei bufsize,
2807 GLsizei* length, char* name) {
2808 DCHECK_LE(0, bufsize);
2809 // Clear the bucket so if the command fails nothing will be in it.
2810 helper_->SetBucketSize(kResultBucketId, 0);
2811 typedef cmds::GetActiveUniformBlockName::Result Result;
2812 Result* result = GetResultAs<Result*>();
2813 if (!result) {
2814 return false;
2816 // Set as failed so if the command fails we'll recover.
2817 *result = 0;
2818 helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
2819 GetResultShmId(), GetResultShmOffset());
2820 WaitForCmd();
2821 if (*result) {
2822 if (bufsize == 0) {
2823 if (length) {
2824 *length = 0;
2826 } else if (length || name) {
2827 std::vector<int8> str;
2828 GetBucketContents(kResultBucketId, &str);
2829 DCHECK_GT(str.size(), 0u);
2830 GLsizei max_size =
2831 std::min(bufsize, static_cast<GLsizei>(str.size())) - 1;
2832 if (length) {
2833 *length = max_size;
2835 if (name) {
2836 memcpy(name, &str[0], max_size);
2837 name[max_size] = '\0';
2841 return *result != 0;
2844 void GLES2Implementation::GetActiveUniformBlockName(
2845 GLuint program, GLuint index, GLsizei bufsize,
2846 GLsizei* length, char* name) {
2847 GPU_CLIENT_SINGLE_THREAD_CHECK();
2848 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
2849 << program << ", " << index << ", " << bufsize << ", "
2850 << static_cast<const void*>(length) << ", "
2851 << static_cast<const void*>(name) << ")");
2852 if (bufsize < 0) {
2853 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformBlockName", "bufsize < 0");
2854 return;
2856 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockName");
2857 bool success =
2858 share_group_->program_info_manager()->GetActiveUniformBlockName(
2859 this, program, index, bufsize, length, name);
2860 if (success) {
2861 if (name) {
2862 GPU_CLIENT_LOG(" name: " << name);
2865 CheckGLError();
2868 bool GLES2Implementation::GetActiveUniformBlockivHelper(
2869 GLuint program, GLuint index, GLenum pname, GLint* params) {
2870 typedef cmds::GetActiveUniformBlockiv::Result Result;
2871 Result* result = GetResultAs<Result*>();
2872 if (!result) {
2873 return false;
2875 result->SetNumResults(0);
2876 helper_->GetActiveUniformBlockiv(
2877 program, index, pname, GetResultShmId(), GetResultShmOffset());
2878 WaitForCmd();
2879 if (result->GetNumResults() > 0) {
2880 if (params) {
2881 result->CopyResult(params);
2883 GPU_CLIENT_LOG_CODE_BLOCK({
2884 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
2885 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2888 return true;
2890 return false;
2893 void GLES2Implementation::GetActiveUniformBlockiv(
2894 GLuint program, GLuint index, GLenum pname, GLint* params) {
2895 GPU_CLIENT_SINGLE_THREAD_CHECK();
2896 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
2897 << program << ", " << index << ", "
2898 << GLES2Util::GetStringUniformBlockParameter(pname) << ", "
2899 << static_cast<const void*>(params) << ")");
2900 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
2901 bool success =
2902 share_group_->program_info_manager()->GetActiveUniformBlockiv(
2903 this, program, index, pname, params);
2904 if (success) {
2905 if (params) {
2906 // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
2907 // be more than one value returned in params.
2908 GPU_CLIENT_LOG(" params: " << params[0]);
2911 CheckGLError();
2914 bool GLES2Implementation::GetActiveUniformsivHelper(
2915 GLuint program, GLsizei count, const GLuint* indices,
2916 GLenum pname, GLint* params) {
2917 typedef cmds::GetActiveUniformsiv::Result Result;
2918 Result* result = GetResultAs<Result*>();
2919 if (!result) {
2920 return false;
2922 result->SetNumResults(0);
2923 base::CheckedNumeric<size_t> bytes = static_cast<size_t>(count);
2924 bytes *= sizeof(GLuint);
2925 if (!bytes.IsValid()) {
2926 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count overflow");
2927 return false;
2929 SetBucketContents(kResultBucketId, indices, bytes.ValueOrDefault(0));
2930 helper_->GetActiveUniformsiv(
2931 program, kResultBucketId, pname, GetResultShmId(), GetResultShmOffset());
2932 WaitForCmd();
2933 bool success = result->GetNumResults() == count;
2934 if (success) {
2935 if (params) {
2936 result->CopyResult(params);
2938 GPU_CLIENT_LOG_CODE_BLOCK({
2939 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
2940 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2944 helper_->SetBucketSize(kResultBucketId, 0);
2945 return success;
2948 void GLES2Implementation::GetActiveUniformsiv(
2949 GLuint program, GLsizei count, const GLuint* indices,
2950 GLenum pname, GLint* params) {
2951 GPU_CLIENT_SINGLE_THREAD_CHECK();
2952 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv("
2953 << program << ", " << count << ", "
2954 << static_cast<const void*>(indices) << ", "
2955 << GLES2Util::GetStringUniformParameter(pname) << ", "
2956 << static_cast<const void*>(params) << ")");
2957 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
2958 if (count < 0) {
2959 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count < 0");
2960 return;
2962 bool success = share_group_->program_info_manager()->GetActiveUniformsiv(
2963 this, program, count, indices, pname, params);
2964 if (success) {
2965 if (params) {
2966 GPU_CLIENT_LOG_CODE_BLOCK({
2967 for (GLsizei ii = 0; ii < count; ++ii) {
2968 GPU_CLIENT_LOG(" " << ii << ": " << params[ii]);
2973 CheckGLError();
2976 void GLES2Implementation::GetAttachedShaders(
2977 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
2978 GPU_CLIENT_SINGLE_THREAD_CHECK();
2979 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2980 << program << ", " << maxcount << ", "
2981 << static_cast<const void*>(count) << ", "
2982 << static_cast<const void*>(shaders) << ", ");
2983 if (maxcount < 0) {
2984 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
2985 return;
2987 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2988 typedef cmds::GetAttachedShaders::Result Result;
2989 uint32 size = Result::ComputeSize(maxcount);
2990 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
2991 if (!result) {
2992 return;
2994 result->SetNumResults(0);
2995 helper_->GetAttachedShaders(
2996 program,
2997 transfer_buffer_->GetShmId(),
2998 transfer_buffer_->GetOffset(result),
2999 size);
3000 int32 token = helper_->InsertToken();
3001 WaitForCmd();
3002 if (count) {
3003 *count = result->GetNumResults();
3005 result->CopyResult(shaders);
3006 GPU_CLIENT_LOG_CODE_BLOCK({
3007 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3008 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3011 transfer_buffer_->FreePendingToken(result, token);
3012 CheckGLError();
3015 void GLES2Implementation::GetShaderPrecisionFormat(
3016 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
3017 GPU_CLIENT_SINGLE_THREAD_CHECK();
3018 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
3019 << GLES2Util::GetStringShaderType(shadertype) << ", "
3020 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
3021 << static_cast<const void*>(range) << ", "
3022 << static_cast<const void*>(precision) << ", ");
3023 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
3024 typedef cmds::GetShaderPrecisionFormat::Result Result;
3025 Result* result = GetResultAs<Result*>();
3026 if (!result) {
3027 return;
3030 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
3031 GLStaticState::ShaderPrecisionMap::iterator i =
3032 static_state_.shader_precisions.find(key);
3033 if (i != static_state_.shader_precisions.end()) {
3034 *result = i->second;
3035 } else {
3036 result->success = false;
3037 helper_->GetShaderPrecisionFormat(
3038 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
3039 WaitForCmd();
3040 if (result->success)
3041 static_state_.shader_precisions[key] = *result;
3044 if (result->success) {
3045 if (range) {
3046 range[0] = result->min_range;
3047 range[1] = result->max_range;
3048 GPU_CLIENT_LOG(" min_range: " << range[0]);
3049 GPU_CLIENT_LOG(" min_range: " << range[1]);
3051 if (precision) {
3052 precision[0] = result->precision;
3053 GPU_CLIENT_LOG(" min_range: " << precision[0]);
3056 CheckGLError();
3059 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
3060 const char* result = NULL;
3061 // Clears the bucket so if the command fails nothing will be in it.
3062 helper_->SetBucketSize(kResultBucketId, 0);
3063 helper_->GetString(name, kResultBucketId);
3064 std::string str;
3065 if (GetBucketAsString(kResultBucketId, &str)) {
3066 // Adds extensions implemented on client side only.
3067 switch (name) {
3068 case GL_EXTENSIONS:
3069 str += std::string(str.empty() ? "" : " ") +
3070 "GL_CHROMIUM_flipy "
3071 "GL_EXT_unpack_subimage "
3072 "GL_CHROMIUM_map_sub";
3073 if (capabilities_.image)
3074 str += " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
3075 if (capabilities_.future_sync_points)
3076 str += " GL_CHROMIUM_future_sync_point";
3077 break;
3078 default:
3079 break;
3082 // Because of WebGL the extensions can change. We have to cache each unique
3083 // result since we don't know when the client will stop referring to a
3084 // previous one it queries.
3085 GLStringMap::iterator it = gl_strings_.find(name);
3086 if (it == gl_strings_.end()) {
3087 std::set<std::string> strings;
3088 std::pair<GLStringMap::iterator, bool> insert_result =
3089 gl_strings_.insert(std::make_pair(name, strings));
3090 DCHECK(insert_result.second);
3091 it = insert_result.first;
3093 std::set<std::string>& string_set = it->second;
3094 std::set<std::string>::const_iterator sit = string_set.find(str);
3095 if (sit != string_set.end()) {
3096 result = sit->c_str();
3097 } else {
3098 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
3099 string_set.insert(str);
3100 DCHECK(insert_result.second);
3101 result = insert_result.first->c_str();
3104 return reinterpret_cast<const GLubyte*>(result);
3107 const GLubyte* GLES2Implementation::GetString(GLenum name) {
3108 GPU_CLIENT_SINGLE_THREAD_CHECK();
3109 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
3110 << GLES2Util::GetStringStringType(name) << ")");
3111 TRACE_EVENT0("gpu", "GLES2::GetString");
3112 const GLubyte* result = GetStringHelper(name);
3113 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
3114 CheckGLError();
3115 return result;
3118 bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
3119 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3120 GLenum* type, char* name) {
3121 // Clear the bucket so if the command fails nothing will be in it.
3122 helper_->SetBucketSize(kResultBucketId, 0);
3123 typedef cmds::GetTransformFeedbackVarying::Result Result;
3124 Result* result = GetResultAs<Result*>();
3125 if (!result) {
3126 return false;
3128 // Set as failed so if the command fails we'll recover.
3129 result->success = false;
3130 helper_->GetTransformFeedbackVarying(
3131 program, index, kResultBucketId, GetResultShmId(), GetResultShmOffset());
3132 WaitForCmd();
3133 if (result->success) {
3134 if (size) {
3135 *size = result->size;
3137 if (type) {
3138 *type = result->type;
3140 if (length || name) {
3141 std::vector<int8> str;
3142 GetBucketContents(kResultBucketId, &str);
3143 GLsizei max_size = std::min(bufsize, static_cast<GLsizei>(str.size()));
3144 if (max_size > 0) {
3145 --max_size;
3147 if (length) {
3148 *length = max_size;
3150 if (name) {
3151 if (max_size > 0) {
3152 memcpy(name, &str[0], max_size);
3153 name[max_size] = '\0';
3154 } else if (bufsize > 0) {
3155 name[0] = '\0';
3160 return result->success != 0;
3163 void GLES2Implementation::GetTransformFeedbackVarying(
3164 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3165 GLenum* type, char* name) {
3166 GPU_CLIENT_SINGLE_THREAD_CHECK();
3167 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
3168 << program << ", " << index << ", " << bufsize << ", "
3169 << static_cast<const void*>(length) << ", "
3170 << static_cast<const void*>(size) << ", "
3171 << static_cast<const void*>(type) << ", "
3172 << static_cast<const void*>(name) << ", ");
3173 if (bufsize < 0) {
3174 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVarying",
3175 "bufsize < 0");
3176 return;
3178 TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
3179 bool success =
3180 share_group_->program_info_manager()->GetTransformFeedbackVarying(
3181 this, program, index, bufsize, length, size, type, name);
3182 if (success) {
3183 if (size) {
3184 GPU_CLIENT_LOG(" size: " << *size);
3186 if (type) {
3187 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
3189 if (name) {
3190 GPU_CLIENT_LOG(" name: " << name);
3193 CheckGLError();
3196 void GLES2Implementation::GetUniformfv(
3197 GLuint program, GLint location, GLfloat* params) {
3198 GPU_CLIENT_SINGLE_THREAD_CHECK();
3199 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
3200 << program << ", " << location << ", "
3201 << static_cast<const void*>(params) << ")");
3202 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
3203 typedef cmds::GetUniformfv::Result Result;
3204 Result* result = GetResultAs<Result*>();
3205 if (!result) {
3206 return;
3208 result->SetNumResults(0);
3209 helper_->GetUniformfv(
3210 program, location, GetResultShmId(), GetResultShmOffset());
3211 WaitForCmd();
3212 result->CopyResult(params);
3213 GPU_CLIENT_LOG_CODE_BLOCK({
3214 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3215 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3218 CheckGLError();
3221 void GLES2Implementation::GetUniformiv(
3222 GLuint program, GLint location, GLint* params) {
3223 GPU_CLIENT_SINGLE_THREAD_CHECK();
3224 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
3225 << program << ", " << location << ", "
3226 << static_cast<const void*>(params) << ")");
3227 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
3228 typedef cmds::GetUniformiv::Result Result;
3229 Result* result = GetResultAs<Result*>();
3230 if (!result) {
3231 return;
3233 result->SetNumResults(0);
3234 helper_->GetUniformiv(
3235 program, location, GetResultShmId(), GetResultShmOffset());
3236 WaitForCmd();
3237 GetResultAs<cmds::GetUniformiv::Result*>()->CopyResult(params);
3238 GPU_CLIENT_LOG_CODE_BLOCK({
3239 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3240 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3243 CheckGLError();
3246 void GLES2Implementation::GetUniformuiv(
3247 GLuint program, GLint location, GLuint* params) {
3248 GPU_CLIENT_SINGLE_THREAD_CHECK();
3249 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformuiv("
3250 << program << ", " << location << ", "
3251 << static_cast<const void*>(params) << ")");
3252 TRACE_EVENT0("gpu", "GLES2::GetUniformuiv");
3253 typedef cmds::GetUniformuiv::Result Result;
3254 Result* result = GetResultAs<Result*>();
3255 if (!result) {
3256 return;
3258 result->SetNumResults(0);
3259 helper_->GetUniformuiv(
3260 program, location, GetResultShmId(), GetResultShmOffset());
3261 WaitForCmd();
3262 GetResultAs<cmds::GetUniformuiv::Result*>()->CopyResult(params);
3263 GPU_CLIENT_LOG_CODE_BLOCK({
3264 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3265 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3268 CheckGLError();
3271 void GLES2Implementation::ReadPixels(
3272 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
3273 GLenum type, void* pixels) {
3274 GPU_CLIENT_SINGLE_THREAD_CHECK();
3275 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
3276 << xoffset << ", " << yoffset << ", "
3277 << width << ", " << height << ", "
3278 << GLES2Util::GetStringReadPixelFormat(format) << ", "
3279 << GLES2Util::GetStringPixelType(type) << ", "
3280 << static_cast<const void*>(pixels) << ")");
3281 if (width < 0 || height < 0) {
3282 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
3283 return;
3285 if (width == 0 || height == 0) {
3286 return;
3289 // glReadPixel pads the size of each row of pixels by an amount specified by
3290 // glPixelStorei. So, we have to take that into account both in the fact that
3291 // the pixels returned from the ReadPixel command will include that padding
3292 // and that when we copy the results to the user's buffer we need to not
3293 // write those padding bytes but leave them as they are.
3295 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
3296 typedef cmds::ReadPixels::Result Result;
3298 int8* dest = reinterpret_cast<int8*>(pixels);
3299 uint32 temp_size;
3300 uint32 unpadded_row_size;
3301 uint32 padded_row_size;
3302 if (!GLES2Util::ComputeImageDataSizes(
3303 width, 2, 1, format, type, pack_alignment_, &temp_size,
3304 &unpadded_row_size, &padded_row_size)) {
3305 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
3306 return;
3309 if (bound_pixel_pack_transfer_buffer_id_) {
3310 GLuint offset = ToGLuint(pixels);
3311 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3312 bound_pixel_pack_transfer_buffer_id_,
3313 "glReadPixels", offset, padded_row_size * height);
3314 if (buffer && buffer->shm_id() != -1) {
3315 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
3316 buffer->shm_id(), buffer->shm_offset(),
3317 0, 0, true);
3318 CheckGLError();
3320 return;
3323 if (!pixels) {
3324 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
3325 return;
3328 // Transfer by rows.
3329 // The max rows we can transfer.
3330 while (height) {
3331 GLsizei desired_size = padded_row_size * (height - 1) + unpadded_row_size;
3332 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
3333 if (!buffer.valid()) {
3334 return;
3336 GLint num_rows = ComputeNumRowsThatFitInBuffer(
3337 padded_row_size, unpadded_row_size, buffer.size(), height);
3338 num_rows = std::min(num_rows, height);
3339 // NOTE: We must look up the address of the result area AFTER allocation
3340 // of the transfer buffer since the transfer buffer may be reallocated.
3341 Result* result = GetResultAs<Result*>();
3342 if (!result) {
3343 return;
3345 *result = 0; // mark as failed.
3346 helper_->ReadPixels(
3347 xoffset, yoffset, width, num_rows, format, type,
3348 buffer.shm_id(), buffer.offset(),
3349 GetResultShmId(), GetResultShmOffset(),
3350 false);
3351 WaitForCmd();
3352 if (*result != 0) {
3353 // when doing a y-flip we have to iterate through top-to-bottom chunks
3354 // of the dst. The service side handles reversing the rows within a
3355 // chunk.
3356 int8* rows_dst;
3357 if (pack_reverse_row_order_) {
3358 rows_dst = dest + (height - num_rows) * padded_row_size;
3359 } else {
3360 rows_dst = dest;
3362 // We have to copy 1 row at a time to avoid writing pad bytes.
3363 const int8* src = static_cast<const int8*>(buffer.address());
3364 for (GLint yy = 0; yy < num_rows; ++yy) {
3365 memcpy(rows_dst, src, unpadded_row_size);
3366 rows_dst += padded_row_size;
3367 src += padded_row_size;
3369 if (!pack_reverse_row_order_) {
3370 dest = rows_dst;
3373 // If it was not marked as successful exit.
3374 if (*result == 0) {
3375 return;
3377 yoffset += num_rows;
3378 height -= num_rows;
3380 CheckGLError();
3383 void GLES2Implementation::ActiveTexture(GLenum texture) {
3384 GPU_CLIENT_SINGLE_THREAD_CHECK();
3385 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
3386 << GLES2Util::GetStringEnum(texture) << ")");
3387 GLuint texture_index = texture - GL_TEXTURE0;
3388 if (texture_index >=
3389 static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
3390 SetGLErrorInvalidEnum(
3391 "glActiveTexture", texture, "texture");
3392 return;
3395 active_texture_unit_ = texture_index;
3396 helper_->ActiveTexture(texture);
3397 CheckGLError();
3400 void GLES2Implementation::GenBuffersHelper(
3401 GLsizei /* n */, const GLuint* /* buffers */) {
3404 void GLES2Implementation::GenFramebuffersHelper(
3405 GLsizei /* n */, const GLuint* /* framebuffers */) {
3408 void GLES2Implementation::GenRenderbuffersHelper(
3409 GLsizei /* n */, const GLuint* /* renderbuffers */) {
3412 void GLES2Implementation::GenTexturesHelper(
3413 GLsizei /* n */, const GLuint* /* textures */) {
3416 void GLES2Implementation::GenVertexArraysOESHelper(
3417 GLsizei n, const GLuint* arrays) {
3418 vertex_array_object_manager_->GenVertexArrays(n, arrays);
3421 void GLES2Implementation::GenQueriesEXTHelper(
3422 GLsizei /* n */, const GLuint* /* queries */) {
3425 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
3426 GLsizei /* n */,
3427 const GLuint* /* valuebuffers */) {
3430 void GLES2Implementation::GenSamplersHelper(
3431 GLsizei /* n */, const GLuint* /* samplers */) {
3434 void GLES2Implementation::GenTransformFeedbacksHelper(
3435 GLsizei /* n */, const GLuint* /* transformfeedbacks */) {
3438 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
3439 // generates a new resource. On newer versions of OpenGL they don't. The code
3440 // related to binding below will need to change if we switch to the new OpenGL
3441 // model. Specifically it assumes a bind will succeed which is always true in
3442 // the old model but possibly not true in the new model if another context has
3443 // deleted the resource.
3445 // NOTE #2: There is a bug in some BindXXXHelpers, that IDs might be marked as
3446 // used even when Bind has failed. However, the bug is minor compared to the
3447 // overhead & duplicated checking in client side.
3449 void GLES2Implementation::BindBufferHelper(
3450 GLenum target, GLuint buffer_id) {
3451 // TODO(gman): See note #1 above.
3452 bool changed = false;
3453 switch (target) {
3454 case GL_ARRAY_BUFFER:
3455 if (bound_array_buffer_ != buffer_id) {
3456 bound_array_buffer_ = buffer_id;
3457 changed = true;
3459 break;
3460 case GL_COPY_READ_BUFFER:
3461 if (bound_copy_read_buffer_ != buffer_id) {
3462 bound_copy_read_buffer_ = buffer_id;
3463 changed = true;
3465 break;
3466 case GL_COPY_WRITE_BUFFER:
3467 if (bound_copy_write_buffer_ != buffer_id) {
3468 bound_copy_write_buffer_ = buffer_id;
3469 changed = true;
3471 break;
3472 case GL_ELEMENT_ARRAY_BUFFER:
3473 changed = vertex_array_object_manager_->BindElementArray(buffer_id);
3474 break;
3475 case GL_PIXEL_PACK_BUFFER:
3476 if (bound_pixel_pack_buffer_ != buffer_id) {
3477 bound_pixel_pack_buffer_ = buffer_id;
3478 changed = true;
3480 break;
3481 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3482 bound_pixel_pack_transfer_buffer_id_ = buffer_id;
3483 break;
3484 case GL_PIXEL_UNPACK_BUFFER:
3485 if (bound_pixel_unpack_buffer_ != buffer_id) {
3486 bound_pixel_unpack_buffer_ = buffer_id;
3487 changed = true;
3489 break;
3490 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3491 bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
3492 break;
3493 case GL_TRANSFORM_FEEDBACK_BUFFER:
3494 if (bound_transform_feedback_buffer_ != buffer_id) {
3495 bound_transform_feedback_buffer_ = buffer_id;
3496 changed = true;
3498 break;
3499 case GL_UNIFORM_BUFFER:
3500 if (bound_uniform_buffer_ != buffer_id) {
3501 bound_uniform_buffer_ = buffer_id;
3502 changed = true;
3504 break;
3505 default:
3506 changed = true;
3507 break;
3509 // TODO(gman): See note #2 above.
3510 if (changed) {
3511 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3512 this, target, buffer_id, &GLES2Implementation::BindBufferStub);
3516 void GLES2Implementation::BindBufferStub(GLenum target, GLuint buffer) {
3517 helper_->BindBuffer(target, buffer);
3518 if (share_group_->bind_generates_resource())
3519 helper_->CommandBufferHelper::Flush();
3522 void GLES2Implementation::BindBufferBaseHelper(
3523 GLenum target, GLuint index, GLuint buffer_id) {
3524 // TODO(zmo): See note #1 above.
3525 // TODO(zmo): See note #2 above.
3526 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3527 this, target, index, buffer_id, &GLES2Implementation::BindBufferBaseStub);
3530 void GLES2Implementation::BindBufferBaseStub(
3531 GLenum target, GLuint index, GLuint buffer) {
3532 helper_->BindBufferBase(target, index, buffer);
3533 if (share_group_->bind_generates_resource())
3534 helper_->CommandBufferHelper::Flush();
3537 void GLES2Implementation::BindBufferRangeHelper(
3538 GLenum target, GLuint index, GLuint buffer_id,
3539 GLintptr offset, GLsizeiptr size) {
3540 // TODO(zmo): See note #1 above.
3541 // TODO(zmo): See note #2 above.
3542 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3543 this, target, index, buffer_id, offset, size,
3544 &GLES2Implementation::BindBufferRangeStub);
3547 void GLES2Implementation::BindBufferRangeStub(
3548 GLenum target, GLuint index, GLuint buffer,
3549 GLintptr offset, GLsizeiptr size) {
3550 helper_->BindBufferRange(target, index, buffer, offset, size);
3551 if (share_group_->bind_generates_resource())
3552 helper_->CommandBufferHelper::Flush();
3555 void GLES2Implementation::BindFramebufferHelper(
3556 GLenum target, GLuint framebuffer) {
3557 // TODO(gman): See note #1 above.
3558 bool changed = false;
3559 switch (target) {
3560 case GL_FRAMEBUFFER:
3561 if (bound_framebuffer_ != framebuffer ||
3562 bound_read_framebuffer_ != framebuffer) {
3563 bound_framebuffer_ = framebuffer;
3564 bound_read_framebuffer_ = framebuffer;
3565 changed = true;
3567 break;
3568 case GL_READ_FRAMEBUFFER:
3569 if (!IsChromiumFramebufferMultisampleAvailable()) {
3570 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3571 return;
3573 if (bound_read_framebuffer_ != framebuffer) {
3574 bound_read_framebuffer_ = framebuffer;
3575 changed = true;
3577 break;
3578 case GL_DRAW_FRAMEBUFFER:
3579 if (!IsChromiumFramebufferMultisampleAvailable()) {
3580 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3581 return;
3583 if (bound_framebuffer_ != framebuffer) {
3584 bound_framebuffer_ = framebuffer;
3585 changed = true;
3587 break;
3588 default:
3589 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3590 return;
3593 if (changed) {
3594 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(
3595 this, target, framebuffer, &GLES2Implementation::BindFramebufferStub);
3599 void GLES2Implementation::BindFramebufferStub(GLenum target,
3600 GLuint framebuffer) {
3601 helper_->BindFramebuffer(target, framebuffer);
3602 if (share_group_->bind_generates_resource())
3603 helper_->CommandBufferHelper::Flush();
3606 void GLES2Implementation::BindRenderbufferHelper(
3607 GLenum target, GLuint renderbuffer) {
3608 // TODO(gman): See note #1 above.
3609 bool changed = false;
3610 switch (target) {
3611 case GL_RENDERBUFFER:
3612 if (bound_renderbuffer_ != renderbuffer) {
3613 bound_renderbuffer_ = renderbuffer;
3614 changed = true;
3616 break;
3617 default:
3618 changed = true;
3619 break;
3621 // TODO(zmo): See note #2 above.
3622 if (changed) {
3623 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(
3624 this, target, renderbuffer,
3625 &GLES2Implementation::BindRenderbufferStub);
3629 void GLES2Implementation::BindRenderbufferStub(GLenum target,
3630 GLuint renderbuffer) {
3631 helper_->BindRenderbuffer(target, renderbuffer);
3632 if (share_group_->bind_generates_resource())
3633 helper_->CommandBufferHelper::Flush();
3636 void GLES2Implementation::BindSamplerHelper(GLuint unit,
3637 GLuint sampler) {
3638 helper_->BindSampler(unit, sampler);
3641 void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
3642 // TODO(gman): See note #1 above.
3643 // TODO(gman): Change this to false once we figure out why it's failing
3644 // on daisy.
3645 bool changed = true;
3646 TextureUnit& unit = texture_units_[active_texture_unit_];
3647 switch (target) {
3648 case GL_TEXTURE_2D:
3649 if (unit.bound_texture_2d != texture) {
3650 unit.bound_texture_2d = texture;
3651 changed = true;
3653 break;
3654 case GL_TEXTURE_CUBE_MAP:
3655 if (unit.bound_texture_cube_map != texture) {
3656 unit.bound_texture_cube_map = texture;
3657 changed = true;
3659 break;
3660 case GL_TEXTURE_EXTERNAL_OES:
3661 if (unit.bound_texture_external_oes != texture) {
3662 unit.bound_texture_external_oes = texture;
3663 changed = true;
3665 break;
3666 default:
3667 changed = true;
3668 break;
3670 // TODO(gman): See note #2 above.
3671 if (changed) {
3672 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(
3673 this, target, texture, &GLES2Implementation::BindTextureStub);
3677 void GLES2Implementation::BindTextureStub(GLenum target, GLuint texture) {
3678 helper_->BindTexture(target, texture);
3679 if (share_group_->bind_generates_resource())
3680 helper_->CommandBufferHelper::Flush();
3683 void GLES2Implementation::BindTransformFeedbackHelper(
3684 GLenum target, GLuint transformfeedback) {
3685 helper_->BindTransformFeedback(target, transformfeedback);
3688 void GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
3689 bool changed = false;
3690 if (vertex_array_object_manager_->BindVertexArray(array, &changed)) {
3691 if (changed) {
3692 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
3693 // because unlike other resources VertexArrayObject ids must
3694 // be generated by GenVertexArrays. A random id to Bind will not
3695 // generate a new object.
3696 helper_->BindVertexArrayOES(array);
3698 } else {
3699 SetGLError(
3700 GL_INVALID_OPERATION, "glBindVertexArrayOES",
3701 "id was not generated with glGenVertexArrayOES");
3705 void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
3706 GLuint valuebuffer) {
3707 bool changed = false;
3708 switch (target) {
3709 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
3710 if (bound_valuebuffer_ != valuebuffer) {
3711 bound_valuebuffer_ = valuebuffer;
3712 changed = true;
3714 break;
3715 default:
3716 changed = true;
3717 break;
3719 // TODO(gman): See note #2 above.
3720 if (changed) {
3721 GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(
3722 this, target, valuebuffer,
3723 &GLES2Implementation::BindValuebufferCHROMIUMStub);
3727 void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target,
3728 GLuint valuebuffer) {
3729 helper_->BindValuebufferCHROMIUM(target, valuebuffer);
3730 if (share_group_->bind_generates_resource())
3731 helper_->CommandBufferHelper::Flush();
3734 void GLES2Implementation::UseProgramHelper(GLuint program) {
3735 if (current_program_ != program) {
3736 current_program_ = program;
3737 helper_->UseProgram(program);
3741 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
3742 return vertex_array_object_manager_->IsReservedId(id);
3745 void GLES2Implementation::DeleteBuffersHelper(
3746 GLsizei n, const GLuint* buffers) {
3747 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
3748 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
3749 SetGLError(
3750 GL_INVALID_VALUE,
3751 "glDeleteBuffers", "id not created by this context.");
3752 return;
3754 for (GLsizei ii = 0; ii < n; ++ii) {
3755 if (buffers[ii] == bound_array_buffer_) {
3756 bound_array_buffer_ = 0;
3758 if (buffers[ii] == bound_copy_read_buffer_) {
3759 bound_copy_read_buffer_ = 0;
3761 if (buffers[ii] == bound_copy_write_buffer_) {
3762 bound_copy_write_buffer_ = 0;
3764 if (buffers[ii] == bound_pixel_pack_buffer_) {
3765 bound_pixel_pack_buffer_ = 0;
3767 if (buffers[ii] == bound_pixel_unpack_buffer_) {
3768 bound_pixel_unpack_buffer_ = 0;
3770 if (buffers[ii] == bound_transform_feedback_buffer_) {
3771 bound_transform_feedback_buffer_ = 0;
3773 if (buffers[ii] == bound_uniform_buffer_) {
3774 bound_uniform_buffer_ = 0;
3776 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
3778 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
3779 if (buffer)
3780 RemoveTransferBuffer(buffer);
3782 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
3783 bound_pixel_unpack_transfer_buffer_id_ = 0;
3786 RemoveMappedBufferRangeById(buffers[ii]);
3790 void GLES2Implementation::DeleteBuffersStub(
3791 GLsizei n, const GLuint* buffers) {
3792 helper_->DeleteBuffersImmediate(n, buffers);
3796 void GLES2Implementation::DeleteFramebuffersHelper(
3797 GLsizei n, const GLuint* framebuffers) {
3798 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
3799 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
3800 SetGLError(
3801 GL_INVALID_VALUE,
3802 "glDeleteFramebuffers", "id not created by this context.");
3803 return;
3805 for (GLsizei ii = 0; ii < n; ++ii) {
3806 if (framebuffers[ii] == bound_framebuffer_) {
3807 bound_framebuffer_ = 0;
3809 if (framebuffers[ii] == bound_read_framebuffer_) {
3810 bound_read_framebuffer_ = 0;
3815 void GLES2Implementation::DeleteFramebuffersStub(
3816 GLsizei n, const GLuint* framebuffers) {
3817 helper_->DeleteFramebuffersImmediate(n, framebuffers);
3820 void GLES2Implementation::DeleteRenderbuffersHelper(
3821 GLsizei n, const GLuint* renderbuffers) {
3822 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
3823 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
3824 SetGLError(
3825 GL_INVALID_VALUE,
3826 "glDeleteRenderbuffers", "id not created by this context.");
3827 return;
3829 for (GLsizei ii = 0; ii < n; ++ii) {
3830 if (renderbuffers[ii] == bound_renderbuffer_) {
3831 bound_renderbuffer_ = 0;
3836 void GLES2Implementation::DeleteRenderbuffersStub(
3837 GLsizei n, const GLuint* renderbuffers) {
3838 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
3841 void GLES2Implementation::DeleteTexturesHelper(
3842 GLsizei n, const GLuint* textures) {
3843 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
3844 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
3845 SetGLError(
3846 GL_INVALID_VALUE,
3847 "glDeleteTextures", "id not created by this context.");
3848 return;
3850 for (GLsizei ii = 0; ii < n; ++ii) {
3851 for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
3852 ++tt) {
3853 TextureUnit& unit = texture_units_[tt];
3854 if (textures[ii] == unit.bound_texture_2d) {
3855 unit.bound_texture_2d = 0;
3857 if (textures[ii] == unit.bound_texture_cube_map) {
3858 unit.bound_texture_cube_map = 0;
3860 if (textures[ii] == unit.bound_texture_external_oes) {
3861 unit.bound_texture_external_oes = 0;
3867 void GLES2Implementation::DeleteTexturesStub(GLsizei n,
3868 const GLuint* textures) {
3869 helper_->DeleteTexturesImmediate(n, textures);
3872 void GLES2Implementation::DeleteVertexArraysOESHelper(
3873 GLsizei n, const GLuint* arrays) {
3874 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
3875 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
3876 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
3877 SetGLError(
3878 GL_INVALID_VALUE,
3879 "glDeleteVertexArraysOES", "id not created by this context.");
3880 return;
3884 void GLES2Implementation::DeleteVertexArraysOESStub(
3885 GLsizei n, const GLuint* arrays) {
3886 helper_->DeleteVertexArraysOESImmediate(n, arrays);
3889 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
3890 GLsizei n,
3891 const GLuint* valuebuffers) {
3892 if (!GetIdHandler(id_namespaces::kValuebuffers)
3893 ->FreeIds(this, n, valuebuffers,
3894 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
3895 SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
3896 "id not created by this context.");
3897 return;
3899 for (GLsizei ii = 0; ii < n; ++ii) {
3900 if (valuebuffers[ii] == bound_valuebuffer_) {
3901 bound_valuebuffer_ = 0;
3906 void GLES2Implementation::DeleteSamplersStub(
3907 GLsizei n, const GLuint* samplers) {
3908 helper_->DeleteSamplersImmediate(n, samplers);
3911 void GLES2Implementation::DeleteSamplersHelper(
3912 GLsizei n, const GLuint* samplers) {
3913 if (!GetIdHandler(id_namespaces::kSamplers)->FreeIds(
3914 this, n, samplers, &GLES2Implementation::DeleteSamplersStub)) {
3915 SetGLError(
3916 GL_INVALID_VALUE,
3917 "glDeleteSamplers", "id not created by this context.");
3918 return;
3922 void GLES2Implementation::DeleteTransformFeedbacksStub(
3923 GLsizei n, const GLuint* transformfeedbacks) {
3924 helper_->DeleteTransformFeedbacksImmediate(n, transformfeedbacks);
3927 void GLES2Implementation::DeleteTransformFeedbacksHelper(
3928 GLsizei n, const GLuint* transformfeedbacks) {
3929 if (!GetIdHandler(id_namespaces::kTransformFeedbacks)->FreeIds(
3930 this, n, transformfeedbacks,
3931 &GLES2Implementation::DeleteTransformFeedbacksStub)) {
3932 SetGLError(
3933 GL_INVALID_VALUE,
3934 "glDeleteTransformFeedbacks", "id not created by this context.");
3935 return;
3939 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
3940 GLsizei n,
3941 const GLuint* valuebuffers) {
3942 helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
3945 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
3946 GPU_CLIENT_SINGLE_THREAD_CHECK();
3947 GPU_CLIENT_LOG(
3948 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
3949 vertex_array_object_manager_->SetAttribEnable(index, false);
3950 helper_->DisableVertexAttribArray(index);
3951 CheckGLError();
3954 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
3955 GPU_CLIENT_SINGLE_THREAD_CHECK();
3956 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
3957 << index << ")");
3958 vertex_array_object_manager_->SetAttribEnable(index, true);
3959 helper_->EnableVertexAttribArray(index);
3960 CheckGLError();
3963 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
3964 GPU_CLIENT_SINGLE_THREAD_CHECK();
3965 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
3966 << GLES2Util::GetStringDrawMode(mode) << ", "
3967 << first << ", " << count << ")");
3968 if (count < 0) {
3969 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
3970 return;
3972 bool simulated = false;
3973 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
3974 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
3975 return;
3977 helper_->DrawArrays(mode, first, count);
3978 RestoreArrayBuffer(simulated);
3979 CheckGLError();
3982 void GLES2Implementation::GetVertexAttribfv(
3983 GLuint index, GLenum pname, GLfloat* params) {
3984 GPU_CLIENT_SINGLE_THREAD_CHECK();
3985 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
3986 << index << ", "
3987 << GLES2Util::GetStringVertexAttribute(pname) << ", "
3988 << static_cast<const void*>(params) << ")");
3989 uint32 value = 0;
3990 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
3991 *params = static_cast<GLfloat>(value);
3992 return;
3994 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
3995 typedef cmds::GetVertexAttribfv::Result Result;
3996 Result* result = GetResultAs<Result*>();
3997 if (!result) {
3998 return;
4000 result->SetNumResults(0);
4001 helper_->GetVertexAttribfv(
4002 index, pname, GetResultShmId(), GetResultShmOffset());
4003 WaitForCmd();
4004 result->CopyResult(params);
4005 GPU_CLIENT_LOG_CODE_BLOCK({
4006 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4007 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4010 CheckGLError();
4013 void GLES2Implementation::GetVertexAttribiv(
4014 GLuint index, GLenum pname, GLint* params) {
4015 GPU_CLIENT_SINGLE_THREAD_CHECK();
4016 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
4017 << index << ", "
4018 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4019 << static_cast<const void*>(params) << ")");
4020 uint32 value = 0;
4021 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4022 *params = static_cast<GLint>(value);
4023 return;
4025 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
4026 typedef cmds::GetVertexAttribiv::Result Result;
4027 Result* result = GetResultAs<Result*>();
4028 if (!result) {
4029 return;
4031 result->SetNumResults(0);
4032 helper_->GetVertexAttribiv(
4033 index, pname, GetResultShmId(), GetResultShmOffset());
4034 WaitForCmd();
4035 result->CopyResult(params);
4036 GPU_CLIENT_LOG_CODE_BLOCK({
4037 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4038 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4041 CheckGLError();
4044 void GLES2Implementation::GetVertexAttribIiv(
4045 GLuint index, GLenum pname, GLint* params) {
4046 GPU_CLIENT_SINGLE_THREAD_CHECK();
4047 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIiv("
4048 << index << ", "
4049 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4050 << static_cast<const void*>(params) << ")");
4051 uint32 value = 0;
4052 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4053 *params = static_cast<GLint>(value);
4054 return;
4056 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIiv");
4057 typedef cmds::GetVertexAttribiv::Result Result;
4058 Result* result = GetResultAs<Result*>();
4059 if (!result) {
4060 return;
4062 result->SetNumResults(0);
4063 helper_->GetVertexAttribIiv(
4064 index, pname, GetResultShmId(), GetResultShmOffset());
4065 WaitForCmd();
4066 result->CopyResult(params);
4067 GPU_CLIENT_LOG_CODE_BLOCK({
4068 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4069 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4072 CheckGLError();
4075 void GLES2Implementation::GetVertexAttribIuiv(
4076 GLuint index, GLenum pname, GLuint* params) {
4077 GPU_CLIENT_SINGLE_THREAD_CHECK();
4078 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIuiv("
4079 << index << ", "
4080 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4081 << static_cast<const void*>(params) << ")");
4082 uint32 value = 0;
4083 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4084 *params = static_cast<GLuint>(value);
4085 return;
4087 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIuiv");
4088 typedef cmds::GetVertexAttribiv::Result Result;
4089 Result* result = GetResultAs<Result*>();
4090 if (!result) {
4091 return;
4093 result->SetNumResults(0);
4094 helper_->GetVertexAttribIuiv(
4095 index, pname, GetResultShmId(), GetResultShmOffset());
4096 WaitForCmd();
4097 result->CopyResult(params);
4098 GPU_CLIENT_LOG_CODE_BLOCK({
4099 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4100 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4103 CheckGLError();
4106 void GLES2Implementation::Swap() {
4107 SwapBuffers();
4110 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
4111 PostSubBufferCHROMIUM(
4112 sub_buffer.x(), sub_buffer.y(), sub_buffer.width(), sub_buffer.height());
4115 static GLenum GetGLESOverlayTransform(gfx::OverlayTransform plane_transform) {
4116 switch (plane_transform) {
4117 case gfx::OVERLAY_TRANSFORM_INVALID:
4118 break;
4119 case gfx::OVERLAY_TRANSFORM_NONE:
4120 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
4121 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
4122 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM;
4123 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
4124 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM;
4125 case gfx::OVERLAY_TRANSFORM_ROTATE_90:
4126 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM;
4127 case gfx::OVERLAY_TRANSFORM_ROTATE_180:
4128 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM;
4129 case gfx::OVERLAY_TRANSFORM_ROTATE_270:
4130 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM;
4132 NOTREACHED();
4133 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
4136 void GLES2Implementation::ScheduleOverlayPlane(
4137 int plane_z_order,
4138 gfx::OverlayTransform plane_transform,
4139 unsigned overlay_texture_id,
4140 const gfx::Rect& display_bounds,
4141 const gfx::RectF& uv_rect) {
4142 ScheduleOverlayPlaneCHROMIUM(plane_z_order,
4143 GetGLESOverlayTransform(plane_transform),
4144 overlay_texture_id,
4145 display_bounds.x(),
4146 display_bounds.y(),
4147 display_bounds.width(),
4148 display_bounds.height(),
4149 uv_rect.x(),
4150 uv_rect.y(),
4151 uv_rect.width(),
4152 uv_rect.height());
4155 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
4156 const char* feature) {
4157 GPU_CLIENT_SINGLE_THREAD_CHECK();
4158 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
4159 << feature << ")");
4160 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
4161 typedef cmds::EnableFeatureCHROMIUM::Result Result;
4162 Result* result = GetResultAs<Result*>();
4163 if (!result) {
4164 return false;
4166 *result = 0;
4167 SetBucketAsCString(kResultBucketId, feature);
4168 helper_->EnableFeatureCHROMIUM(
4169 kResultBucketId, GetResultShmId(), GetResultShmOffset());
4170 WaitForCmd();
4171 helper_->SetBucketSize(kResultBucketId, 0);
4172 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
4173 return *result != 0;
4176 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
4177 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
4178 GPU_CLIENT_SINGLE_THREAD_CHECK();
4179 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
4180 << target << ", " << offset << ", " << size << ", "
4181 << GLES2Util::GetStringEnum(access) << ")");
4182 // NOTE: target is NOT checked because the service will check it
4183 // and we don't know what targets are valid.
4184 if (access != GL_WRITE_ONLY) {
4185 SetGLErrorInvalidEnum(
4186 "glMapBufferSubDataCHROMIUM", access, "access");
4187 return NULL;
4189 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
4190 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
4191 return NULL;
4194 int32 shm_id;
4195 unsigned int shm_offset;
4196 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4197 if (!mem) {
4198 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
4199 return NULL;
4202 std::pair<MappedBufferMap::iterator, bool> result =
4203 mapped_buffers_.insert(std::make_pair(
4204 mem,
4205 MappedBuffer(
4206 access, shm_id, mem, shm_offset, target, offset, size)));
4207 DCHECK(result.second);
4208 GPU_CLIENT_LOG(" returned " << mem);
4209 return mem;
4212 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
4213 GPU_CLIENT_SINGLE_THREAD_CHECK();
4214 GPU_CLIENT_LOG(
4215 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
4216 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
4217 if (it == mapped_buffers_.end()) {
4218 SetGLError(
4219 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
4220 return;
4222 const MappedBuffer& mb = it->second;
4223 helper_->BufferSubData(
4224 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
4225 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
4226 mapped_buffers_.erase(it);
4227 CheckGLError();
4230 GLuint GLES2Implementation::GetBoundBufferHelper(GLenum target) {
4231 GLenum binding = GLES2Util::MapBufferTargetToBindingEnum(target);
4232 GLint id = 0;
4233 bool cached = GetHelper(binding, &id);
4234 DCHECK(cached);
4235 return static_cast<GLuint>(id);
4238 void GLES2Implementation::RemoveMappedBufferRangeByTarget(GLenum target) {
4239 GLuint buffer = GetBoundBufferHelper(target);
4240 RemoveMappedBufferRangeById(buffer);
4243 void GLES2Implementation::RemoveMappedBufferRangeById(GLuint buffer) {
4244 if (buffer > 0) {
4245 auto iter = mapped_buffer_range_map_.find(buffer);
4246 if (iter != mapped_buffer_range_map_.end() && iter->second.shm_memory) {
4247 mapped_memory_->FreePendingToken(
4248 iter->second.shm_memory, helper_->InsertToken());
4249 mapped_buffer_range_map_.erase(iter);
4254 void GLES2Implementation::ClearMappedBufferRangeMap() {
4255 for (auto& buffer_range : mapped_buffer_range_map_) {
4256 if (buffer_range.second.shm_memory) {
4257 mapped_memory_->FreePendingToken(
4258 buffer_range.second.shm_memory, helper_->InsertToken());
4261 mapped_buffer_range_map_.clear();
4264 void* GLES2Implementation::MapBufferRange(
4265 GLenum target, GLintptr offset, GLsizeiptr size, GLbitfield access) {
4266 GPU_CLIENT_SINGLE_THREAD_CHECK();
4267 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferRange("
4268 << GLES2Util::GetStringEnum(target) << ", " << offset << ", "
4269 << size << ", " << access << ")");
4270 if (!ValidateSize("glMapBufferRange", size) ||
4271 !ValidateOffset("glMapBufferRange", offset)) {
4272 return nullptr;
4275 int32 shm_id;
4276 unsigned int shm_offset;
4277 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4278 if (!mem) {
4279 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferRange", "out of memory");
4280 return nullptr;
4283 typedef cmds::MapBufferRange::Result Result;
4284 Result* result = GetResultAs<Result*>();
4285 *result = 0;
4286 helper_->MapBufferRange(target, offset, size, access, shm_id, shm_offset,
4287 GetResultShmId(), GetResultShmOffset());
4288 // TODO(zmo): For write only mode with MAP_INVALID_*_BIT, we should
4289 // consider an early return without WaitForCmd(). crbug.com/465804.
4290 WaitForCmd();
4291 if (*result) {
4292 const GLbitfield kInvalidateBits =
4293 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
4294 if ((access & kInvalidateBits) != 0) {
4295 // We do not read back from the buffer, therefore, we set the client
4296 // side memory to zero to avoid uninitialized data.
4297 memset(mem, 0, size);
4299 GLuint buffer = GetBoundBufferHelper(target);
4300 DCHECK_NE(0u, buffer);
4301 // glMapBufferRange fails on an already mapped buffer.
4302 DCHECK(mapped_buffer_range_map_.find(buffer) ==
4303 mapped_buffer_range_map_.end());
4304 auto iter = mapped_buffer_range_map_.insert(std::make_pair(
4305 buffer,
4306 MappedBuffer(access, shm_id, mem, shm_offset, target, offset, size)));
4307 DCHECK(iter.second);
4308 } else {
4309 mapped_memory_->Free(mem);
4310 mem = nullptr;
4313 GPU_CLIENT_LOG(" returned " << mem);
4314 CheckGLError();
4315 return mem;
4318 GLboolean GLES2Implementation::UnmapBuffer(GLenum target) {
4319 GPU_CLIENT_SINGLE_THREAD_CHECK();
4320 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapBuffer("
4321 << GLES2Util::GetStringEnum(target) << ")");
4322 switch (target) {
4323 case GL_ARRAY_BUFFER:
4324 case GL_ELEMENT_ARRAY_BUFFER:
4325 case GL_COPY_READ_BUFFER:
4326 case GL_COPY_WRITE_BUFFER:
4327 case GL_PIXEL_PACK_BUFFER:
4328 case GL_PIXEL_UNPACK_BUFFER:
4329 case GL_TRANSFORM_FEEDBACK_BUFFER:
4330 case GL_UNIFORM_BUFFER:
4331 break;
4332 default:
4333 SetGLError(GL_INVALID_ENUM, "glUnmapBuffer", "invalid target");
4334 return GL_FALSE;
4336 GLuint buffer = GetBoundBufferHelper(target);
4337 if (buffer == 0) {
4338 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "no buffer bound");
4339 return GL_FALSE;
4341 auto iter = mapped_buffer_range_map_.find(buffer);
4342 if (iter == mapped_buffer_range_map_.end()) {
4343 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "buffer is unmapped");
4344 return GL_FALSE;
4347 helper_->UnmapBuffer(target);
4348 RemoveMappedBufferRangeById(buffer);
4349 // TODO(zmo): There is a rare situation that data might be corrupted and
4350 // GL_FALSE should be returned. We lose context on that sitatuon, so we
4351 // don't have to WaitForCmd().
4352 GPU_CLIENT_LOG(" returned " << GL_TRUE);
4353 CheckGLError();
4354 return GL_TRUE;
4357 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
4358 GLenum target,
4359 GLint level,
4360 GLint xoffset,
4361 GLint yoffset,
4362 GLsizei width,
4363 GLsizei height,
4364 GLenum format,
4365 GLenum type,
4366 GLenum access) {
4367 GPU_CLIENT_SINGLE_THREAD_CHECK();
4368 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
4369 << target << ", " << level << ", "
4370 << xoffset << ", " << yoffset << ", "
4371 << width << ", " << height << ", "
4372 << GLES2Util::GetStringTextureFormat(format) << ", "
4373 << GLES2Util::GetStringPixelType(type) << ", "
4374 << GLES2Util::GetStringEnum(access) << ")");
4375 if (access != GL_WRITE_ONLY) {
4376 SetGLErrorInvalidEnum(
4377 "glMapTexSubImage2DCHROMIUM", access, "access");
4378 return NULL;
4380 // NOTE: target is NOT checked because the service will check it
4381 // and we don't know what targets are valid.
4382 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
4383 SetGLError(
4384 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
4385 return NULL;
4387 uint32 size;
4388 if (!GLES2Util::ComputeImageDataSizes(
4389 width, height, 1, format, type, unpack_alignment_, &size, NULL, NULL)) {
4390 SetGLError(
4391 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
4392 return NULL;
4394 int32 shm_id;
4395 unsigned int shm_offset;
4396 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4397 if (!mem) {
4398 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
4399 return NULL;
4402 std::pair<MappedTextureMap::iterator, bool> result =
4403 mapped_textures_.insert(std::make_pair(
4404 mem,
4405 MappedTexture(
4406 access, shm_id, mem, shm_offset,
4407 target, level, xoffset, yoffset, width, height, format, type)));
4408 DCHECK(result.second);
4409 GPU_CLIENT_LOG(" returned " << mem);
4410 return mem;
4413 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
4414 GPU_CLIENT_SINGLE_THREAD_CHECK();
4415 GPU_CLIENT_LOG(
4416 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
4417 MappedTextureMap::iterator it = mapped_textures_.find(mem);
4418 if (it == mapped_textures_.end()) {
4419 SetGLError(
4420 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
4421 return;
4423 const MappedTexture& mt = it->second;
4424 helper_->TexSubImage2D(
4425 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
4426 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
4427 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
4428 mapped_textures_.erase(it);
4429 CheckGLError();
4432 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
4433 float scale_factor) {
4434 GPU_CLIENT_SINGLE_THREAD_CHECK();
4435 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
4436 << width << ", " << height << ", " << scale_factor << ")");
4437 helper_->ResizeCHROMIUM(width, height, scale_factor);
4438 CheckGLError();
4441 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
4442 GPU_CLIENT_SINGLE_THREAD_CHECK();
4443 GPU_CLIENT_LOG("[" << GetLogPrefix()
4444 << "] glGetRequestableExtensionsCHROMIUM()");
4445 TRACE_EVENT0("gpu",
4446 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
4447 const char* result = NULL;
4448 // Clear the bucket so if the command fails nothing will be in it.
4449 helper_->SetBucketSize(kResultBucketId, 0);
4450 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
4451 std::string str;
4452 if (GetBucketAsString(kResultBucketId, &str)) {
4453 // The set of requestable extensions shrinks as we enable
4454 // them. Because we don't know when the client will stop referring
4455 // to a previous one it queries (see GetString) we need to cache
4456 // the unique results.
4457 std::set<std::string>::const_iterator sit =
4458 requestable_extensions_set_.find(str);
4459 if (sit != requestable_extensions_set_.end()) {
4460 result = sit->c_str();
4461 } else {
4462 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
4463 requestable_extensions_set_.insert(str);
4464 DCHECK(insert_result.second);
4465 result = insert_result.first->c_str();
4468 GPU_CLIENT_LOG(" returned " << result);
4469 return reinterpret_cast<const GLchar*>(result);
4472 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
4473 // with VirtualGL contexts.
4474 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
4475 GPU_CLIENT_SINGLE_THREAD_CHECK();
4476 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
4477 << extension << ")");
4478 SetBucketAsCString(kResultBucketId, extension);
4479 helper_->RequestExtensionCHROMIUM(kResultBucketId);
4480 helper_->SetBucketSize(kResultBucketId, 0);
4482 struct ExtensionCheck {
4483 const char* extension;
4484 ExtensionStatus* status;
4486 const ExtensionCheck checks[] = {
4488 "GL_ANGLE_pack_reverse_row_order",
4489 &angle_pack_reverse_row_order_status_,
4492 "GL_CHROMIUM_framebuffer_multisample",
4493 &chromium_framebuffer_multisample_,
4496 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
4497 for (size_t ii = 0; ii < kNumChecks; ++ii) {
4498 const ExtensionCheck& check = checks[ii];
4499 if (*check.status == kUnavailableExtensionStatus &&
4500 !strcmp(extension, check.extension)) {
4501 *check.status = kUnknownExtensionStatus;
4506 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
4507 GPU_CLIENT_SINGLE_THREAD_CHECK();
4508 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
4509 // Wait if this would add too many rate limit tokens.
4510 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
4511 helper_->WaitForToken(rate_limit_tokens_.front());
4512 rate_limit_tokens_.pop();
4514 rate_limit_tokens_.push(helper_->InsertToken());
4517 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
4518 GLuint program, std::vector<int8>* result) {
4519 DCHECK(result);
4520 // Clear the bucket so if the command fails nothing will be in it.
4521 helper_->SetBucketSize(kResultBucketId, 0);
4522 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
4523 GetBucketContents(kResultBucketId, result);
4526 void GLES2Implementation::GetProgramInfoCHROMIUM(
4527 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4528 GPU_CLIENT_SINGLE_THREAD_CHECK();
4529 if (bufsize < 0) {
4530 SetGLError(
4531 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
4532 return;
4534 if (size == NULL) {
4535 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
4536 return;
4538 // Make sure they've set size to 0 else the value will be undefined on
4539 // lost context.
4540 DCHECK_EQ(0, *size);
4541 std::vector<int8> result;
4542 GetProgramInfoCHROMIUMHelper(program, &result);
4543 if (result.empty()) {
4544 return;
4546 *size = result.size();
4547 if (!info) {
4548 return;
4550 if (static_cast<size_t>(bufsize) < result.size()) {
4551 SetGLError(GL_INVALID_OPERATION,
4552 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
4553 return;
4555 memcpy(info, &result[0], result.size());
4558 void GLES2Implementation::GetUniformBlocksCHROMIUMHelper(
4559 GLuint program, std::vector<int8>* result) {
4560 DCHECK(result);
4561 // Clear the bucket so if the command fails nothing will be in it.
4562 helper_->SetBucketSize(kResultBucketId, 0);
4563 helper_->GetUniformBlocksCHROMIUM(program, kResultBucketId);
4564 GetBucketContents(kResultBucketId, result);
4567 void GLES2Implementation::GetUniformBlocksCHROMIUM(
4568 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4569 GPU_CLIENT_SINGLE_THREAD_CHECK();
4570 if (bufsize < 0) {
4571 SetGLError(
4572 GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "bufsize less than 0.");
4573 return;
4575 if (size == NULL) {
4576 SetGLError(GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "size is null.");
4577 return;
4579 // Make sure they've set size to 0 else the value will be undefined on
4580 // lost context.
4581 DCHECK_EQ(0, *size);
4582 std::vector<int8> result;
4583 GetUniformBlocksCHROMIUMHelper(program, &result);
4584 if (result.empty()) {
4585 return;
4587 *size = result.size();
4588 if (!info) {
4589 return;
4591 if (static_cast<size_t>(bufsize) < result.size()) {
4592 SetGLError(GL_INVALID_OPERATION, "glGetUniformBlocksCHROMIUM",
4593 "bufsize is too small for result.");
4594 return;
4596 memcpy(info, &result[0], result.size());
4599 void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
4600 GLuint program, std::vector<int8>* result) {
4601 DCHECK(result);
4602 // Clear the bucket so if the command fails nothing will be in it.
4603 helper_->SetBucketSize(kResultBucketId, 0);
4604 helper_->GetUniformsES3CHROMIUM(program, kResultBucketId);
4605 GetBucketContents(kResultBucketId, result);
4608 void GLES2Implementation::GetUniformsES3CHROMIUM(
4609 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4610 GPU_CLIENT_SINGLE_THREAD_CHECK();
4611 if (bufsize < 0) {
4612 SetGLError(
4613 GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "bufsize less than 0.");
4614 return;
4616 if (size == NULL) {
4617 SetGLError(GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "size is null.");
4618 return;
4620 // Make sure they've set size to 0 else the value will be undefined on
4621 // lost context.
4622 DCHECK_EQ(0, *size);
4623 std::vector<int8> result;
4624 GetUniformsES3CHROMIUMHelper(program, &result);
4625 if (result.empty()) {
4626 return;
4628 *size = result.size();
4629 if (!info) {
4630 return;
4632 if (static_cast<size_t>(bufsize) < result.size()) {
4633 SetGLError(GL_INVALID_OPERATION,
4634 "glGetUniformsES3CHROMIUM", "bufsize is too small for result.");
4635 return;
4637 memcpy(info, &result[0], result.size());
4640 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
4641 GLuint program, std::vector<int8>* result) {
4642 DCHECK(result);
4643 // Clear the bucket so if the command fails nothing will be in it.
4644 helper_->SetBucketSize(kResultBucketId, 0);
4645 helper_->GetTransformFeedbackVaryingsCHROMIUM(program, kResultBucketId);
4646 GetBucketContents(kResultBucketId, result);
4649 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(
4650 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4651 GPU_CLIENT_SINGLE_THREAD_CHECK();
4652 if (bufsize < 0) {
4653 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4654 "bufsize less than 0.");
4655 return;
4657 if (size == NULL) {
4658 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4659 "size is null.");
4660 return;
4662 // Make sure they've set size to 0 else the value will be undefined on
4663 // lost context.
4664 DCHECK_EQ(0, *size);
4665 std::vector<int8> result;
4666 GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
4667 if (result.empty()) {
4668 return;
4670 *size = result.size();
4671 if (!info) {
4672 return;
4674 if (static_cast<size_t>(bufsize) < result.size()) {
4675 SetGLError(GL_INVALID_OPERATION, "glGetTransformFeedbackVaryingsCHROMIUM",
4676 "bufsize is too small for result.");
4677 return;
4679 memcpy(info, &result[0], result.size());
4682 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
4683 GPU_CLIENT_SINGLE_THREAD_CHECK();
4684 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
4685 << texture << ")");
4686 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
4687 helper_->CommandBufferHelper::Flush();
4688 return gpu_control_->CreateStreamTexture(texture);
4691 void GLES2Implementation::PostSubBufferCHROMIUM(
4692 GLint x, GLint y, GLint width, GLint height) {
4693 GPU_CLIENT_SINGLE_THREAD_CHECK();
4694 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
4695 << x << ", " << y << ", " << width << ", " << height << ")");
4696 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
4697 "width", width, "height", height);
4699 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
4700 swap_buffers_tokens_.push(helper_->InsertToken());
4701 helper_->PostSubBufferCHROMIUM(x, y, width, height);
4702 helper_->CommandBufferHelper::Flush();
4703 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
4704 helper_->WaitForToken(swap_buffers_tokens_.front());
4705 swap_buffers_tokens_.pop();
4709 void GLES2Implementation::DeleteQueriesEXTHelper(
4710 GLsizei n, const GLuint* queries) {
4711 for (GLsizei ii = 0; ii < n; ++ii) {
4712 query_tracker_->RemoveQuery(queries[ii]);
4713 query_id_allocator_->FreeID(queries[ii]);
4716 helper_->DeleteQueriesEXTImmediate(n, queries);
4719 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
4720 GPU_CLIENT_SINGLE_THREAD_CHECK();
4721 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
4723 // TODO(gman): To be spec compliant IDs from other contexts sharing
4724 // resources need to return true here even though you can't share
4725 // queries across contexts?
4726 return query_tracker_->GetQuery(id) != NULL;
4729 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
4730 GPU_CLIENT_SINGLE_THREAD_CHECK();
4731 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
4732 << GLES2Util::GetStringQueryTarget(target)
4733 << ", " << id << ")");
4735 // if any outstanding queries INV_OP
4736 QueryMap::iterator it = current_queries_.find(target);
4737 if (it != current_queries_.end()) {
4738 SetGLError(
4739 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
4740 return;
4743 // id = 0 INV_OP
4744 if (id == 0) {
4745 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
4746 return;
4749 // if not GENned INV_OPERATION
4750 if (!query_id_allocator_->InUse(id)) {
4751 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "invalid id");
4752 return;
4755 // if id does not have an object
4756 QueryTracker::Query* query = query_tracker_->GetQuery(id);
4757 if (!query) {
4758 query = query_tracker_->CreateQuery(id, target);
4759 if (!query) {
4760 SetGLError(GL_OUT_OF_MEMORY,
4761 "glBeginQueryEXT",
4762 "transfer buffer allocation failed");
4763 return;
4765 } else if (query->target() != target) {
4766 SetGLError(
4767 GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
4768 return;
4771 current_queries_[target] = query;
4773 query->Begin(this);
4774 CheckGLError();
4777 void GLES2Implementation::EndQueryEXT(GLenum target) {
4778 GPU_CLIENT_SINGLE_THREAD_CHECK();
4779 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
4780 << GLES2Util::GetStringQueryTarget(target) << ")");
4781 // Don't do anything if the context is lost.
4782 if (helper_->IsContextLost()) {
4783 return;
4786 QueryMap::iterator it = current_queries_.find(target);
4787 if (it == current_queries_.end()) {
4788 SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
4789 return;
4792 QueryTracker::Query* query = it->second;
4793 query->End(this);
4794 current_queries_.erase(it);
4795 CheckGLError();
4798 void GLES2Implementation::GetQueryivEXT(
4799 GLenum target, GLenum pname, GLint* params) {
4800 GPU_CLIENT_SINGLE_THREAD_CHECK();
4801 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
4802 << GLES2Util::GetStringQueryTarget(target) << ", "
4803 << GLES2Util::GetStringQueryParameter(pname) << ", "
4804 << static_cast<const void*>(params) << ")");
4806 if (pname != GL_CURRENT_QUERY_EXT) {
4807 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
4808 return;
4810 QueryMap::iterator it = current_queries_.find(target);
4811 if (it != current_queries_.end()) {
4812 QueryTracker::Query* query = it->second;
4813 *params = query->id();
4814 } else {
4815 *params = 0;
4817 GPU_CLIENT_LOG(" " << *params);
4818 CheckGLError();
4821 void GLES2Implementation::GetQueryObjectuivEXT(
4822 GLuint id, GLenum pname, GLuint* params) {
4823 GPU_CLIENT_SINGLE_THREAD_CHECK();
4824 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
4825 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
4826 << static_cast<const void*>(params) << ")");
4828 QueryTracker::Query* query = query_tracker_->GetQuery(id);
4829 if (!query) {
4830 SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
4831 return;
4834 QueryMap::iterator it = current_queries_.find(query->target());
4835 if (it != current_queries_.end()) {
4836 SetGLError(
4837 GL_INVALID_OPERATION,
4838 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
4839 return;
4842 if (query->NeverUsed()) {
4843 SetGLError(
4844 GL_INVALID_OPERATION,
4845 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
4846 return;
4849 switch (pname) {
4850 case GL_QUERY_RESULT_EXT:
4851 if (!query->CheckResultsAvailable(helper_)) {
4852 helper_->WaitForToken(query->token());
4853 if (!query->CheckResultsAvailable(helper_)) {
4854 FinishHelper();
4855 CHECK(query->CheckResultsAvailable(helper_));
4858 *params = query->GetResult();
4859 break;
4860 case GL_QUERY_RESULT_AVAILABLE_EXT:
4861 *params = query->CheckResultsAvailable(helper_);
4862 break;
4863 default:
4864 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
4865 break;
4867 GPU_CLIENT_LOG(" " << *params);
4868 CheckGLError();
4871 void GLES2Implementation::DrawArraysInstancedANGLE(
4872 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
4873 GPU_CLIENT_SINGLE_THREAD_CHECK();
4874 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
4875 << GLES2Util::GetStringDrawMode(mode) << ", "
4876 << first << ", " << count << ", " << primcount << ")");
4877 if (count < 0) {
4878 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
4879 return;
4881 if (primcount < 0) {
4882 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
4883 return;
4885 if (primcount == 0) {
4886 return;
4888 bool simulated = false;
4889 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
4890 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
4891 &simulated)) {
4892 return;
4894 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
4895 RestoreArrayBuffer(simulated);
4896 CheckGLError();
4899 void GLES2Implementation::DrawElementsInstancedANGLE(
4900 GLenum mode, GLsizei count, GLenum type, const void* indices,
4901 GLsizei primcount) {
4902 GPU_CLIENT_SINGLE_THREAD_CHECK();
4903 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
4904 << GLES2Util::GetStringDrawMode(mode) << ", "
4905 << count << ", "
4906 << GLES2Util::GetStringIndexType(type) << ", "
4907 << static_cast<const void*>(indices) << ", "
4908 << primcount << ")");
4909 if (count < 0) {
4910 SetGLError(GL_INVALID_VALUE,
4911 "glDrawElementsInstancedANGLE", "count less than 0.");
4912 return;
4914 if (count == 0) {
4915 return;
4917 if (primcount < 0) {
4918 SetGLError(GL_INVALID_VALUE,
4919 "glDrawElementsInstancedANGLE", "primcount < 0");
4920 return;
4922 if (primcount == 0) {
4923 return;
4925 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
4926 !ValidateOffset("glDrawElementsInstancedANGLE",
4927 reinterpret_cast<GLintptr>(indices))) {
4928 return;
4930 GLuint offset = 0;
4931 bool simulated = false;
4932 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
4933 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
4934 indices, &offset, &simulated)) {
4935 return;
4937 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
4938 RestoreElementAndArrayBuffers(simulated);
4939 CheckGLError();
4942 void GLES2Implementation::GenMailboxCHROMIUM(
4943 GLbyte* mailbox) {
4944 GPU_CLIENT_SINGLE_THREAD_CHECK();
4945 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
4946 << static_cast<const void*>(mailbox) << ")");
4947 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
4949 gpu::Mailbox result = gpu::Mailbox::Generate();
4950 memcpy(mailbox, result.name, sizeof(result.name));
4953 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target,
4954 const GLbyte* data) {
4955 GPU_CLIENT_SINGLE_THREAD_CHECK();
4956 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
4957 << static_cast<const void*>(data) << ")");
4958 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4959 DCHECK(mailbox.Verify()) << "ProduceTextureCHROMIUM was passed a "
4960 "mailbox that was not generated by "
4961 "GenMailboxCHROMIUM.";
4962 helper_->ProduceTextureCHROMIUMImmediate(target, data);
4963 CheckGLError();
4966 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
4967 GLuint texture, GLenum target, const GLbyte* data) {
4968 GPU_CLIENT_SINGLE_THREAD_CHECK();
4969 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
4970 << static_cast<const void*>(data) << ")");
4971 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4972 DCHECK(mailbox.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
4973 "mailbox that was not generated by "
4974 "GenMailboxCHROMIUM.";
4975 helper_->ProduceTextureDirectCHROMIUMImmediate(texture, target, data);
4976 CheckGLError();
4979 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target,
4980 const GLbyte* data) {
4981 GPU_CLIENT_SINGLE_THREAD_CHECK();
4982 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
4983 << static_cast<const void*>(data) << ")");
4984 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4985 DCHECK(mailbox.Verify()) << "ConsumeTextureCHROMIUM was passed a "
4986 "mailbox that was not generated by "
4987 "GenMailboxCHROMIUM.";
4988 helper_->ConsumeTextureCHROMIUMImmediate(target, data);
4989 CheckGLError();
4992 GLuint GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
4993 GLenum target, const GLbyte* data) {
4994 GPU_CLIENT_SINGLE_THREAD_CHECK();
4995 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
4996 << static_cast<const void*>(data) << ")");
4997 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4998 DCHECK(mailbox.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
4999 "mailbox that was not generated by "
5000 "GenMailboxCHROMIUM.";
5001 GLuint client_id;
5002 GetIdHandler(id_namespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
5003 helper_->CreateAndConsumeTextureCHROMIUMImmediate(target,
5004 client_id, data);
5005 if (share_group_->bind_generates_resource())
5006 helper_->CommandBufferHelper::Flush();
5007 CheckGLError();
5008 return client_id;
5011 void GLES2Implementation::PushGroupMarkerEXT(
5012 GLsizei length, const GLchar* marker) {
5013 GPU_CLIENT_SINGLE_THREAD_CHECK();
5014 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
5015 << length << ", " << marker << ")");
5016 if (!marker) {
5017 marker = "";
5019 SetBucketAsString(
5020 kResultBucketId,
5021 (length ? std::string(marker, length) : std::string(marker)));
5022 helper_->PushGroupMarkerEXT(kResultBucketId);
5023 helper_->SetBucketSize(kResultBucketId, 0);
5024 debug_marker_manager_.PushGroup(
5025 length ? std::string(marker, length) : std::string(marker));
5028 void GLES2Implementation::InsertEventMarkerEXT(
5029 GLsizei length, const GLchar* marker) {
5030 GPU_CLIENT_SINGLE_THREAD_CHECK();
5031 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
5032 << length << ", " << marker << ")");
5033 if (!marker) {
5034 marker = "";
5036 SetBucketAsString(
5037 kResultBucketId,
5038 (length ? std::string(marker, length) : std::string(marker)));
5039 helper_->InsertEventMarkerEXT(kResultBucketId);
5040 helper_->SetBucketSize(kResultBucketId, 0);
5041 debug_marker_manager_.SetMarker(
5042 length ? std::string(marker, length) : std::string(marker));
5045 void GLES2Implementation::PopGroupMarkerEXT() {
5046 GPU_CLIENT_SINGLE_THREAD_CHECK();
5047 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
5048 helper_->PopGroupMarkerEXT();
5049 debug_marker_manager_.PopGroup();
5052 void GLES2Implementation::TraceBeginCHROMIUM(
5053 const char* category_name, const char* trace_name) {
5054 GPU_CLIENT_SINGLE_THREAD_CHECK();
5055 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
5056 << category_name << ", " << trace_name << ")");
5057 SetBucketAsCString(kResultBucketId, category_name);
5058 SetBucketAsCString(kResultBucketId + 1, trace_name);
5059 helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1);
5060 helper_->SetBucketSize(kResultBucketId, 0);
5061 helper_->SetBucketSize(kResultBucketId + 1, 0);
5062 current_trace_stack_++;
5065 void GLES2Implementation::TraceEndCHROMIUM() {
5066 GPU_CLIENT_SINGLE_THREAD_CHECK();
5067 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
5068 if (current_trace_stack_ == 0) {
5069 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
5070 "missing begin trace");
5071 return;
5073 helper_->TraceEndCHROMIUM();
5074 current_trace_stack_--;
5077 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
5078 GPU_CLIENT_SINGLE_THREAD_CHECK();
5079 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
5080 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
5081 switch (target) {
5082 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
5083 if (access != GL_READ_ONLY) {
5084 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
5085 return NULL;
5087 break;
5088 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
5089 if (access != GL_WRITE_ONLY) {
5090 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
5091 return NULL;
5093 break;
5094 default:
5095 SetGLError(
5096 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
5097 return NULL;
5099 GLuint buffer_id;
5100 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
5101 if (!buffer_id) {
5102 return NULL;
5104 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
5105 if (!buffer) {
5106 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
5107 return NULL;
5109 if (buffer->mapped()) {
5110 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
5111 return NULL;
5113 // Here we wait for previous transfer operations to be finished.
5114 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
5115 // with this method of synchronization. Until this is fixed,
5116 // MapBufferCHROMIUM will not block even if the transfer is not ready
5117 // for these calls.
5118 if (buffer->last_usage_token()) {
5119 helper_->WaitForToken(buffer->last_usage_token());
5120 buffer->set_last_usage_token(0);
5122 buffer->set_mapped(true);
5124 GPU_CLIENT_LOG(" returned " << buffer->address());
5125 CheckGLError();
5126 return buffer->address();
5129 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
5130 GPU_CLIENT_SINGLE_THREAD_CHECK();
5131 GPU_CLIENT_LOG(
5132 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
5133 GLuint buffer_id;
5134 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
5135 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
5137 if (!buffer_id) {
5138 return false;
5140 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
5141 if (!buffer) {
5142 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
5143 return false;
5145 if (!buffer->mapped()) {
5146 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
5147 return false;
5149 buffer->set_mapped(false);
5150 CheckGLError();
5151 return true;
5154 bool GLES2Implementation::EnsureAsyncUploadSync() {
5155 if (async_upload_sync_)
5156 return true;
5158 int32 shm_id;
5159 unsigned int shm_offset;
5160 void* mem = mapped_memory_->Alloc(sizeof(AsyncUploadSync),
5161 &shm_id,
5162 &shm_offset);
5163 if (!mem)
5164 return false;
5166 async_upload_sync_shm_id_ = shm_id;
5167 async_upload_sync_shm_offset_ = shm_offset;
5168 async_upload_sync_ = static_cast<AsyncUploadSync*>(mem);
5169 async_upload_sync_->Reset();
5171 return true;
5174 uint32 GLES2Implementation::NextAsyncUploadToken() {
5175 async_upload_token_++;
5176 if (async_upload_token_ == 0)
5177 async_upload_token_++;
5178 return async_upload_token_;
5181 void GLES2Implementation::PollAsyncUploads() {
5182 if (!async_upload_sync_)
5183 return;
5185 if (helper_->IsContextLost()) {
5186 DetachedAsyncUploadMemoryList::iterator it =
5187 detached_async_upload_memory_.begin();
5188 while (it != detached_async_upload_memory_.end()) {
5189 mapped_memory_->Free(it->first);
5190 it = detached_async_upload_memory_.erase(it);
5192 return;
5195 DetachedAsyncUploadMemoryList::iterator it =
5196 detached_async_upload_memory_.begin();
5197 while (it != detached_async_upload_memory_.end()) {
5198 if (HasAsyncUploadTokenPassed(it->second)) {
5199 mapped_memory_->Free(it->first);
5200 it = detached_async_upload_memory_.erase(it);
5201 } else {
5202 break;
5207 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
5208 // Free all completed unmanaged async uploads buffers.
5209 PollAsyncUploads();
5211 // Synchronously free rest of the unmanaged async upload buffers.
5212 if (!detached_async_upload_memory_.empty()) {
5213 WaitAllAsyncTexImage2DCHROMIUM();
5214 WaitForCmd();
5215 PollAsyncUploads();
5219 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
5220 GLenum target, GLint level, GLenum internalformat, GLsizei width,
5221 GLsizei height, GLint border, GLenum format, GLenum type,
5222 const void* pixels) {
5223 GPU_CLIENT_SINGLE_THREAD_CHECK();
5224 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
5225 << GLES2Util::GetStringTextureTarget(target) << ", "
5226 << level << ", "
5227 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
5228 << width << ", " << height << ", " << border << ", "
5229 << GLES2Util::GetStringTextureFormat(format) << ", "
5230 << GLES2Util::GetStringPixelType(type) << ", "
5231 << static_cast<const void*>(pixels) << ")");
5232 if (level < 0 || height < 0 || width < 0) {
5233 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
5234 return;
5236 if (border != 0) {
5237 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
5238 return;
5240 uint32 size;
5241 uint32 unpadded_row_size;
5242 uint32 padded_row_size;
5243 if (!GLES2Util::ComputeImageDataSizes(
5244 width, height, 1, format, type, unpack_alignment_, &size,
5245 &unpadded_row_size, &padded_row_size)) {
5246 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
5247 return;
5250 // If there's no data/buffer just issue the AsyncTexImage2D
5251 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
5252 helper_->AsyncTexImage2DCHROMIUM(
5253 target, level, internalformat, width, height, format, type,
5254 0, 0, 0, 0, 0);
5255 return;
5258 if (!EnsureAsyncUploadSync()) {
5259 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
5260 return;
5263 // Otherwise, async uploads require a transfer buffer to be bound.
5264 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
5265 // the buffer before the transfer is finished. (Currently such
5266 // synchronization has to be handled manually.)
5267 GLuint offset = ToGLuint(pixels);
5268 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
5269 bound_pixel_unpack_transfer_buffer_id_,
5270 "glAsyncTexImage2DCHROMIUM", offset, size);
5271 if (buffer && buffer->shm_id() != -1) {
5272 uint32 async_token = NextAsyncUploadToken();
5273 buffer->set_last_async_upload_token(async_token);
5274 helper_->AsyncTexImage2DCHROMIUM(
5275 target, level, internalformat, width, height, format, type,
5276 buffer->shm_id(), buffer->shm_offset() + offset,
5277 async_token,
5278 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
5282 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
5283 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
5284 GLsizei height, GLenum format, GLenum type, const void* pixels) {
5285 GPU_CLIENT_SINGLE_THREAD_CHECK();
5286 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
5287 << GLES2Util::GetStringTextureTarget(target) << ", "
5288 << level << ", "
5289 << xoffset << ", " << yoffset << ", "
5290 << width << ", " << height << ", "
5291 << GLES2Util::GetStringTextureFormat(format) << ", "
5292 << GLES2Util::GetStringPixelType(type) << ", "
5293 << static_cast<const void*>(pixels) << ")");
5294 if (level < 0 || height < 0 || width < 0) {
5295 SetGLError(
5296 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
5297 return;
5300 uint32 size;
5301 uint32 unpadded_row_size;
5302 uint32 padded_row_size;
5303 if (!GLES2Util::ComputeImageDataSizes(
5304 width, height, 1, format, type, unpack_alignment_, &size,
5305 &unpadded_row_size, &padded_row_size)) {
5306 SetGLError(
5307 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
5308 return;
5311 if (!EnsureAsyncUploadSync()) {
5312 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
5313 return;
5316 // Async uploads require a transfer buffer to be bound.
5317 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
5318 // the buffer before the transfer is finished. (Currently such
5319 // synchronization has to be handled manually.)
5320 GLuint offset = ToGLuint(pixels);
5321 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
5322 bound_pixel_unpack_transfer_buffer_id_,
5323 "glAsyncTexSubImage2DCHROMIUM", offset, size);
5324 if (buffer && buffer->shm_id() != -1) {
5325 uint32 async_token = NextAsyncUploadToken();
5326 buffer->set_last_async_upload_token(async_token);
5327 helper_->AsyncTexSubImage2DCHROMIUM(
5328 target, level, xoffset, yoffset, width, height, format, type,
5329 buffer->shm_id(), buffer->shm_offset() + offset,
5330 async_token,
5331 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
5335 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
5336 GPU_CLIENT_SINGLE_THREAD_CHECK();
5337 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
5338 << GLES2Util::GetStringTextureTarget(target) << ")");
5339 helper_->WaitAsyncTexImage2DCHROMIUM(target);
5340 CheckGLError();
5343 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
5344 GPU_CLIENT_SINGLE_THREAD_CHECK();
5345 GPU_CLIENT_LOG("[" << GetLogPrefix()
5346 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
5347 helper_->WaitAllAsyncTexImage2DCHROMIUM();
5348 CheckGLError();
5351 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
5352 GPU_CLIENT_SINGLE_THREAD_CHECK();
5353 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
5354 helper_->CommandBufferHelper::Flush();
5355 return gpu_control_->InsertSyncPoint();
5358 GLuint GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
5359 GPU_CLIENT_SINGLE_THREAD_CHECK();
5360 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
5361 DCHECK(capabilities_.future_sync_points);
5362 return gpu_control_->InsertFutureSyncPoint();
5365 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point) {
5366 GPU_CLIENT_SINGLE_THREAD_CHECK();
5367 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
5368 << sync_point << ")");
5369 DCHECK(capabilities_.future_sync_points);
5370 helper_->CommandBufferHelper::Flush();
5371 gpu_control_->RetireSyncPoint(sync_point);
5374 namespace {
5376 bool ValidImageFormat(GLenum internalformat,
5377 const Capabilities& capabilities) {
5378 switch (internalformat) {
5379 case GL_ATC_RGB_AMD:
5380 case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
5381 return capabilities.texture_format_atc;
5382 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
5383 return capabilities.texture_format_dxt1;
5384 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
5385 return capabilities.texture_format_dxt5;
5386 case GL_ETC1_RGB8_OES:
5387 return capabilities.texture_format_etc1;
5388 case GL_R8:
5389 case GL_RGB:
5390 case GL_RGBA:
5391 case GL_BGRA_EXT:
5392 return true;
5393 default:
5394 return false;
5398 bool ValidImageUsage(GLenum usage) {
5399 switch (usage) {
5400 case GL_MAP_CHROMIUM:
5401 case GL_SCANOUT_CHROMIUM:
5402 return true;
5403 default:
5404 return false;
5408 } // namespace
5410 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer,
5411 GLsizei width,
5412 GLsizei height,
5413 GLenum internalformat) {
5414 if (width <= 0) {
5415 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
5416 return 0;
5419 if (height <= 0) {
5420 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
5421 return 0;
5424 if (!ValidImageFormat(internalformat, capabilities_)) {
5425 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "invalid format");
5426 return 0;
5429 int32_t image_id =
5430 gpu_control_->CreateImage(buffer, width, height, internalformat);
5431 if (image_id < 0) {
5432 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "image_id < 0");
5433 return 0;
5435 return image_id;
5438 GLuint GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer,
5439 GLsizei width,
5440 GLsizei height,
5441 GLenum internalformat) {
5442 GPU_CLIENT_SINGLE_THREAD_CHECK();
5443 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
5444 << ", " << height << ", "
5445 << GLES2Util::GetStringImageInternalFormat(internalformat)
5446 << ")");
5447 GLuint image_id =
5448 CreateImageCHROMIUMHelper(buffer, width, height, internalformat);
5449 CheckGLError();
5450 return image_id;
5453 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
5454 // Flush the command stream to make sure all pending commands
5455 // that may refer to the image_id are executed on the service side.
5456 helper_->CommandBufferHelper::Flush();
5457 gpu_control_->DestroyImage(image_id);
5460 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
5461 GPU_CLIENT_SINGLE_THREAD_CHECK();
5462 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
5463 << image_id << ")");
5464 DestroyImageCHROMIUMHelper(image_id);
5465 CheckGLError();
5468 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
5469 GLsizei width,
5470 GLsizei height,
5471 GLenum internalformat,
5472 GLenum usage) {
5473 if (width <= 0) {
5474 SetGLError(
5475 GL_INVALID_VALUE, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
5476 return 0;
5479 if (height <= 0) {
5480 SetGLError(GL_INVALID_VALUE,
5481 "glCreateGpuMemoryBufferImageCHROMIUM",
5482 "height <= 0");
5483 return 0;
5486 if (!ValidImageFormat(internalformat, capabilities_)) {
5487 SetGLError(GL_INVALID_VALUE,
5488 "glCreateGpuMemoryBufferImageCHROMIUM",
5489 "invalid format");
5490 return 0;
5493 if (!ValidImageUsage(usage)) {
5494 SetGLError(GL_INVALID_VALUE,
5495 "glCreateGpuMemoryBufferImageCHROMIUM",
5496 "invalid usage");
5497 return 0;
5500 // Flush the command stream to ensure ordering in case the newly
5501 // returned image_id has recently been in use with a different buffer.
5502 helper_->CommandBufferHelper::Flush();
5503 int32_t image_id = gpu_control_->CreateGpuMemoryBufferImage(
5504 width, height, internalformat, usage);
5505 if (image_id < 0) {
5506 SetGLError(GL_OUT_OF_MEMORY,
5507 "glCreateGpuMemoryBufferImageCHROMIUM",
5508 "image_id < 0");
5509 return 0;
5511 return image_id;
5514 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
5515 GLsizei width,
5516 GLsizei height,
5517 GLenum internalformat,
5518 GLenum usage) {
5519 GPU_CLIENT_SINGLE_THREAD_CHECK();
5520 GPU_CLIENT_LOG("[" << GetLogPrefix()
5521 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
5522 << ", " << height << ", "
5523 << GLES2Util::GetStringImageInternalFormat(internalformat)
5524 << ", " << GLES2Util::GetStringImageUsage(usage) << ")");
5525 GLuint image_id = CreateGpuMemoryBufferImageCHROMIUMHelper(
5526 width, height, internalformat, usage);
5527 CheckGLError();
5528 return image_id;
5531 bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
5532 if (size < 0) {
5533 SetGLError(GL_INVALID_VALUE, func, "size < 0");
5534 return false;
5536 if (!base::IsValueInRangeForNumericType<int32_t>(size)) {
5537 SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
5538 return false;
5540 return true;
5543 bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
5544 if (offset < 0) {
5545 SetGLError(GL_INVALID_VALUE, func, "offset < 0");
5546 return false;
5548 if (!base::IsValueInRangeForNumericType<int32_t>(offset)) {
5549 SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
5550 return false;
5552 return true;
5555 bool GLES2Implementation::GetSamplerParameterfvHelper(
5556 GLuint /* sampler */, GLenum /* pname */, GLfloat* /* params */) {
5557 // TODO(zmo): Implement client side caching.
5558 return false;
5561 bool GLES2Implementation::GetSamplerParameterivHelper(
5562 GLuint /* sampler */, GLenum /* pname */, GLint* /* params */) {
5563 // TODO(zmo): Implement client side caching.
5564 return false;
5567 bool GLES2Implementation::PackStringsToBucket(GLsizei count,
5568 const char* const* str,
5569 const GLint* length,
5570 const char* func_name) {
5571 DCHECK_LE(0, count);
5572 // Compute the total size.
5573 base::CheckedNumeric<size_t> total_size = count;
5574 total_size += 1;
5575 total_size *= sizeof(GLint);
5576 if (!total_size.IsValid()) {
5577 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5578 return false;
5580 size_t header_size = total_size.ValueOrDefault(0);
5581 std::vector<GLint> header(count + 1);
5582 header[0] = static_cast<GLint>(count);
5583 for (GLsizei ii = 0; ii < count; ++ii) {
5584 GLint len = 0;
5585 if (str[ii]) {
5586 len = (length && length[ii] >= 0)
5587 ? length[ii]
5588 : base::checked_cast<GLint>(strlen(str[ii]));
5590 total_size += len;
5591 total_size += 1; // NULL at the end of each char array.
5592 if (!total_size.IsValid()) {
5593 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5594 return false;
5596 header[ii + 1] = len;
5598 // Pack data into a bucket on the service.
5599 helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
5600 size_t offset = 0;
5601 for (GLsizei ii = 0; ii <= count; ++ii) {
5602 const char* src =
5603 (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
5604 base::CheckedNumeric<size_t> checked_size =
5605 (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
5606 if (ii > 0) {
5607 checked_size += 1; // NULL in the end.
5609 if (!checked_size.IsValid()) {
5610 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5611 return false;
5613 size_t size = checked_size.ValueOrDefault(0);
5614 while (size) {
5615 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
5616 if (!buffer.valid() || buffer.size() == 0) {
5617 SetGLError(GL_OUT_OF_MEMORY, func_name, "too large");
5618 return false;
5620 size_t copy_size = buffer.size();
5621 if (ii > 0 && buffer.size() == size)
5622 --copy_size;
5623 if (copy_size)
5624 memcpy(buffer.address(), src, copy_size);
5625 if (copy_size < buffer.size()) {
5626 // Append NULL in the end.
5627 DCHECK(copy_size + 1 == buffer.size());
5628 char* str = reinterpret_cast<char*>(buffer.address());
5629 str[copy_size] = 0;
5631 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
5632 buffer.shm_id(), buffer.offset());
5633 offset += buffer.size();
5634 src += buffer.size();
5635 size -= buffer.size();
5638 DCHECK_EQ(total_size.ValueOrDefault(0), offset);
5639 return true;
5642 void GLES2Implementation::UniformBlockBinding(GLuint program,
5643 GLuint index,
5644 GLuint binding) {
5645 GPU_CLIENT_SINGLE_THREAD_CHECK();
5646 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
5647 << ", " << index << ", " << binding << ")");
5648 share_group_->program_info_manager()->UniformBlockBinding(
5649 this, program, index, binding);
5650 helper_->UniformBlockBinding(program, index, binding);
5651 CheckGLError();
5654 GLenum GLES2Implementation::ClientWaitSync(
5655 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5656 GPU_CLIENT_SINGLE_THREAD_CHECK();
5657 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync
5658 << ", " << flags << ", " << timeout << ")");
5659 typedef cmds::ClientWaitSync::Result Result;
5660 Result* result = GetResultAs<Result*>();
5661 if (!result) {
5662 SetGLError(GL_OUT_OF_MEMORY, "ClientWaitSync", "");
5663 return GL_WAIT_FAILED;
5665 *result = GL_WAIT_FAILED;
5666 uint32_t v32_0 = 0, v32_1 = 0;
5667 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5668 helper_->ClientWaitSync(
5669 ToGLuint(sync), flags, v32_0, v32_1,
5670 GetResultShmId(), GetResultShmOffset());
5671 WaitForCmd();
5672 GPU_CLIENT_LOG("returned " << *result);
5673 CheckGLError();
5674 return *result;
5677 void GLES2Implementation::WaitSync(
5678 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5679 GPU_CLIENT_SINGLE_THREAD_CHECK();
5680 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync << ", "
5681 << flags << ", " << timeout << ")");
5682 uint32_t v32_0 = 0, v32_1 = 0;
5683 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5684 helper_->WaitSync(ToGLuint(sync), flags, v32_0, v32_1);
5685 CheckGLError();
5688 // Include the auto-generated part of this file. We split this because it means
5689 // we can easily edit the non-auto generated parts right here in this file
5690 // instead of having to edit some template or the code generator.
5691 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
5693 } // namespace gles2
5694 } // namespace gpu