Reland "Non-SFI mode: Switch to newlib. (patchset #4 id:60001 of https://codereview...
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blob8d408fad39120e7cc14a58a683fa176463e6b195
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 aggressively_free_resources_(false),
117 weak_ptr_factory_(this) {
118 DCHECK(helper);
119 DCHECK(transfer_buffer);
120 DCHECK(gpu_control);
122 std::stringstream ss;
123 ss << std::hex << this;
124 this_in_hex_ = ss.str();
126 GPU_CLIENT_LOG_CODE_BLOCK({
127 debug_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
128 switches::kEnableGPUClientLogging);
131 share_group_ =
132 (share_group ? share_group : new ShareGroup(bind_generates_resource));
133 DCHECK(share_group_->bind_generates_resource() == bind_generates_resource);
135 memset(&reserved_ids_, 0, sizeof(reserved_ids_));
138 bool GLES2Implementation::Initialize(
139 unsigned int starting_transfer_buffer_size,
140 unsigned int min_transfer_buffer_size,
141 unsigned int max_transfer_buffer_size,
142 unsigned int mapped_memory_limit) {
143 TRACE_EVENT0("gpu", "GLES2Implementation::Initialize");
144 DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
145 DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
146 DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
148 if (!transfer_buffer_->Initialize(
149 starting_transfer_buffer_size,
150 kStartingOffset,
151 min_transfer_buffer_size,
152 max_transfer_buffer_size,
153 kAlignment,
154 kSizeToFlush)) {
155 return false;
158 mapped_memory_.reset(
159 new MappedMemoryManager(
160 helper_,
161 base::Bind(&GLES2Implementation::PollAsyncUploads,
162 // The mapped memory manager is owned by |this| here, and
163 // since its destroyed before before we destroy ourselves
164 // we don't need extra safety measures for this closure.
165 base::Unretained(this)),
166 mapped_memory_limit));
168 unsigned chunk_size = 2 * 1024 * 1024;
169 if (mapped_memory_limit != kNoLimit) {
170 // Use smaller chunks if the client is very memory conscientious.
171 chunk_size = std::min(mapped_memory_limit / 4, chunk_size);
173 mapped_memory_->set_chunk_size_multiple(chunk_size);
175 GLStaticState::ShaderPrecisionMap* shader_precisions =
176 &static_state_.shader_precisions;
177 capabilities_.VisitPrecisions([shader_precisions](
178 GLenum shader, GLenum type, Capabilities::ShaderPrecision* result) {
179 const GLStaticState::ShaderPrecisionKey key(shader, type);
180 cmds::GetShaderPrecisionFormat::Result cached_result = {
181 true, result->min_range, result->max_range, result->precision};
182 shader_precisions->insert(std::make_pair(key, cached_result));
185 util_.set_num_compressed_texture_formats(
186 capabilities_.num_compressed_texture_formats);
187 util_.set_num_shader_binary_formats(capabilities_.num_shader_binary_formats);
189 texture_units_.reset(
190 new TextureUnit[capabilities_.max_combined_texture_image_units]);
192 query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
193 buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
195 query_id_allocator_.reset(new IdAllocator());
196 if (support_client_side_arrays_) {
197 GetIdHandler(id_namespaces::kBuffers)->MakeIds(
198 this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
201 vertex_array_object_manager_.reset(new VertexArrayObjectManager(
202 capabilities_.max_vertex_attribs, reserved_ids_[0], reserved_ids_[1],
203 support_client_side_arrays_));
205 // GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
206 // on Client & Service.
207 if (capabilities_.bind_generates_resource_chromium !=
208 (share_group_->bind_generates_resource() ? 1 : 0)) {
209 SetGLError(GL_INVALID_OPERATION,
210 "Initialize",
211 "Service bind_generates_resource mismatch.");
212 return false;
215 return true;
218 GLES2Implementation::~GLES2Implementation() {
219 // Make sure the queries are finished otherwise we'll delete the
220 // shared memory (mapped_memory_) which will free the memory used
221 // by the queries. The GPU process when validating that memory is still
222 // shared will fail and abort (ie, it will stop running).
223 WaitForCmd();
224 query_tracker_.reset();
226 // GLES2Implementation::Initialize() could fail before allocating
227 // reserved_ids_, so we need delete them carefully.
228 if (support_client_side_arrays_ && reserved_ids_[0]) {
229 DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
232 // Release remaining BufferRange mem; This is when a MapBufferRange() is
233 // called but not the UnmapBuffer() pair.
234 ClearMappedBufferRangeMap();
236 // Release any per-context data in share group.
237 share_group_->FreeContext(this);
239 buffer_tracker_.reset();
241 FreeAllAsyncUploadBuffers();
243 if (async_upload_sync_) {
244 mapped_memory_->Free(async_upload_sync_);
245 async_upload_sync_ = NULL;
248 // Make sure the commands make it the service.
249 WaitForCmd();
252 GLES2CmdHelper* GLES2Implementation::helper() const {
253 return helper_;
256 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
257 return share_group_->GetIdHandler(namespace_id);
260 IdAllocator* GLES2Implementation::GetIdAllocator(int namespace_id) const {
261 if (namespace_id == id_namespaces::kQueries)
262 return query_id_allocator_.get();
263 NOTREACHED();
264 return NULL;
267 void* GLES2Implementation::GetResultBuffer() {
268 return transfer_buffer_->GetResultBuffer();
271 int32 GLES2Implementation::GetResultShmId() {
272 return transfer_buffer_->GetShmId();
275 uint32 GLES2Implementation::GetResultShmOffset() {
276 return transfer_buffer_->GetResultOffset();
279 void GLES2Implementation::FreeUnusedSharedMemory() {
280 mapped_memory_->FreeUnused();
283 void GLES2Implementation::FreeEverything() {
284 FreeAllAsyncUploadBuffers();
285 WaitForCmd();
286 query_tracker_->Shrink();
287 FreeUnusedSharedMemory();
288 transfer_buffer_->Free();
289 helper_->FreeRingBuffer();
292 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
293 if (!helper_->IsContextLost())
294 callback.Run();
297 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
298 const base::Closure& callback) {
299 gpu_control_->SignalSyncPoint(
300 sync_point,
301 base::Bind(&GLES2Implementation::RunIfContextNotLost,
302 weak_ptr_factory_.GetWeakPtr(),
303 callback));
306 void GLES2Implementation::SignalQuery(uint32 query,
307 const base::Closure& callback) {
308 // Flush previously entered commands to ensure ordering with any
309 // glBeginQueryEXT() calls that may have been put into the context.
310 ShallowFlushCHROMIUM();
311 gpu_control_->SignalQuery(
312 query,
313 base::Bind(&GLES2Implementation::RunIfContextNotLost,
314 weak_ptr_factory_.GetWeakPtr(),
315 callback));
318 void GLES2Implementation::SetSurfaceVisible(bool visible) {
319 TRACE_EVENT1(
320 "gpu", "GLES2Implementation::SetSurfaceVisible", "visible", visible);
321 ShallowFlushCHROMIUM();
322 gpu_control_->SetSurfaceVisible(visible);
325 void GLES2Implementation::SetAggressivelyFreeResources(
326 bool aggressively_free_resources) {
327 TRACE_EVENT1("gpu", "GLES2Implementation::SetAggressivelyFreeResources",
328 "aggressively_free_resources", aggressively_free_resources);
329 aggressively_free_resources_ = aggressively_free_resources;
331 // ShallowFlushCHROMIUM will free resources if |aggressively_free_resources_|
332 // is false.
333 ShallowFlushCHROMIUM();
336 void GLES2Implementation::WaitForCmd() {
337 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
338 helper_->CommandBufferHelper::Finish();
341 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
342 const char* extensions =
343 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
344 if (!extensions)
345 return false;
347 int length = strlen(ext);
348 while (true) {
349 int n = strcspn(extensions, " ");
350 if (n == length && 0 == strncmp(ext, extensions, length)) {
351 return true;
353 if ('\0' == extensions[n]) {
354 return false;
356 extensions += n + 1;
360 bool GLES2Implementation::IsExtensionAvailableHelper(
361 const char* extension, ExtensionStatus* status) {
362 switch (*status) {
363 case kAvailableExtensionStatus:
364 return true;
365 case kUnavailableExtensionStatus:
366 return false;
367 default: {
368 bool available = IsExtensionAvailable(extension);
369 *status = available ? kAvailableExtensionStatus :
370 kUnavailableExtensionStatus;
371 return available;
376 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
377 return IsExtensionAvailableHelper(
378 "GL_ANGLE_pack_reverse_row_order",
379 &angle_pack_reverse_row_order_status_);
382 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
383 return IsExtensionAvailableHelper(
384 "GL_CHROMIUM_framebuffer_multisample",
385 &chromium_framebuffer_multisample_);
388 const std::string& GLES2Implementation::GetLogPrefix() const {
389 const std::string& prefix(debug_marker_manager_.GetMarker());
390 return prefix.empty() ? this_in_hex_ : prefix;
393 GLenum GLES2Implementation::GetError() {
394 GPU_CLIENT_SINGLE_THREAD_CHECK();
395 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
396 GLenum err = GetGLError();
397 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
398 return err;
401 GLenum GLES2Implementation::GetClientSideGLError() {
402 if (error_bits_ == 0) {
403 return GL_NO_ERROR;
406 GLenum error = GL_NO_ERROR;
407 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
408 if ((error_bits_ & mask) != 0) {
409 error = GLES2Util::GLErrorBitToGLError(mask);
410 break;
413 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
414 return error;
417 GLenum GLES2Implementation::GetGLError() {
418 TRACE_EVENT0("gpu", "GLES2::GetGLError");
419 // Check the GL error first, then our wrapped error.
420 typedef cmds::GetError::Result Result;
421 Result* result = GetResultAs<Result*>();
422 // If we couldn't allocate a result the context is lost.
423 if (!result) {
424 return GL_NO_ERROR;
426 *result = GL_NO_ERROR;
427 helper_->GetError(GetResultShmId(), GetResultShmOffset());
428 WaitForCmd();
429 GLenum error = *result;
430 if (error == GL_NO_ERROR) {
431 error = GetClientSideGLError();
432 } else {
433 // There was an error, clear the corresponding wrapped error.
434 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
436 return error;
439 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
440 void GLES2Implementation::FailGLError(GLenum error) {
441 if (error != GL_NO_ERROR) {
442 NOTREACHED() << "Error";
445 // NOTE: Calling GetGLError overwrites data in the result buffer.
446 void GLES2Implementation::CheckGLError() {
447 FailGLError(GetGLError());
449 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
451 void GLES2Implementation::SetGLError(
452 GLenum error, const char* function_name, const char* msg) {
453 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
454 << GLES2Util::GetStringError(error) << ": "
455 << function_name << ": " << msg);
456 FailGLError(error);
457 if (msg) {
458 last_error_ = msg;
460 if (error_message_callback_) {
461 std::string temp(GLES2Util::GetStringError(error) + " : " +
462 function_name + ": " + (msg ? msg : ""));
463 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
465 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
467 if (error == GL_OUT_OF_MEMORY && lose_context_when_out_of_memory_) {
468 helper_->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
469 GL_UNKNOWN_CONTEXT_RESET_ARB);
473 void GLES2Implementation::SetGLErrorInvalidEnum(
474 const char* function_name, GLenum value, const char* label) {
475 SetGLError(GL_INVALID_ENUM, function_name,
476 (std::string(label) + " was " +
477 GLES2Util::GetStringEnum(value)).c_str());
480 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
481 std::vector<int8>* data) {
482 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
483 DCHECK(data);
484 const uint32 kStartSize = 32 * 1024;
485 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
486 if (!buffer.valid()) {
487 return false;
489 typedef cmd::GetBucketStart::Result Result;
490 Result* result = GetResultAs<Result*>();
491 if (!result) {
492 return false;
494 *result = 0;
495 helper_->GetBucketStart(
496 bucket_id, GetResultShmId(), GetResultShmOffset(),
497 buffer.size(), buffer.shm_id(), buffer.offset());
498 WaitForCmd();
499 uint32 size = *result;
500 data->resize(size);
501 if (size > 0u) {
502 uint32 offset = 0;
503 while (size) {
504 if (!buffer.valid()) {
505 buffer.Reset(size);
506 if (!buffer.valid()) {
507 return false;
509 helper_->GetBucketData(
510 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
511 WaitForCmd();
513 uint32 size_to_copy = std::min(size, buffer.size());
514 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
515 offset += size_to_copy;
516 size -= size_to_copy;
517 buffer.Release();
519 // Free the bucket. This is not required but it does free up the memory.
520 // and we don't have to wait for the result so from the client's perspective
521 // it's cheap.
522 helper_->SetBucketSize(bucket_id, 0);
524 return true;
527 void GLES2Implementation::SetBucketContents(
528 uint32 bucket_id, const void* data, size_t size) {
529 DCHECK(data);
530 helper_->SetBucketSize(bucket_id, size);
531 if (size > 0u) {
532 uint32 offset = 0;
533 while (size) {
534 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
535 if (!buffer.valid()) {
536 return;
538 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
539 buffer.size());
540 helper_->SetBucketData(
541 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
542 offset += buffer.size();
543 size -= buffer.size();
548 void GLES2Implementation::SetBucketAsCString(
549 uint32 bucket_id, const char* str) {
550 // NOTE: strings are passed NULL terminated. That means the empty
551 // string will have a size of 1 and no-string will have a size of 0
552 if (str) {
553 SetBucketContents(bucket_id, str, strlen(str) + 1);
554 } else {
555 helper_->SetBucketSize(bucket_id, 0);
559 bool GLES2Implementation::GetBucketAsString(
560 uint32 bucket_id, std::string* str) {
561 DCHECK(str);
562 std::vector<int8> data;
563 // NOTE: strings are passed NULL terminated. That means the empty
564 // string will have a size of 1 and no-string will have a size of 0
565 if (!GetBucketContents(bucket_id, &data)) {
566 return false;
568 if (data.empty()) {
569 return false;
571 str->assign(&data[0], &data[0] + data.size() - 1);
572 return true;
575 void GLES2Implementation::SetBucketAsString(
576 uint32 bucket_id, const std::string& str) {
577 // NOTE: strings are passed NULL terminated. That means the empty
578 // string will have a size of 1 and no-string will have a size of 0
579 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
582 void GLES2Implementation::Disable(GLenum cap) {
583 GPU_CLIENT_SINGLE_THREAD_CHECK();
584 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
585 << GLES2Util::GetStringCapability(cap) << ")");
586 bool changed = false;
587 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
588 helper_->Disable(cap);
590 CheckGLError();
593 void GLES2Implementation::Enable(GLenum cap) {
594 GPU_CLIENT_SINGLE_THREAD_CHECK();
595 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
596 << GLES2Util::GetStringCapability(cap) << ")");
597 bool changed = false;
598 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
599 helper_->Enable(cap);
601 CheckGLError();
604 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
605 GPU_CLIENT_SINGLE_THREAD_CHECK();
606 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
607 << GLES2Util::GetStringCapability(cap) << ")");
608 bool state = false;
609 if (!state_.GetEnabled(cap, &state)) {
610 typedef cmds::IsEnabled::Result Result;
611 Result* result = GetResultAs<Result*>();
612 if (!result) {
613 return GL_FALSE;
615 *result = 0;
616 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
617 WaitForCmd();
618 state = (*result) != 0;
621 GPU_CLIENT_LOG("returned " << state);
622 CheckGLError();
623 return state;
626 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
627 // TODO(zmo): For all the BINDING points, there is a possibility where
628 // resources are shared among multiple contexts, that the cached points
629 // are invalid. It is not a problem for now, but once we allow resource
630 // sharing in WebGL, we need to implement a mechanism to allow correct
631 // client side binding points tracking. crbug.com/465562.
633 // ES2 parameters.
634 switch (pname) {
635 case GL_ACTIVE_TEXTURE:
636 *params = active_texture_unit_ + GL_TEXTURE0;
637 return true;
638 case GL_ARRAY_BUFFER_BINDING:
639 *params = bound_array_buffer_;
640 return true;
641 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
642 *params =
643 vertex_array_object_manager_->bound_element_array_buffer();
644 return true;
645 case GL_FRAMEBUFFER_BINDING:
646 *params = bound_framebuffer_;
647 return true;
648 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
649 *params = capabilities_.max_combined_texture_image_units;
650 return true;
651 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
652 *params = capabilities_.max_cube_map_texture_size;
653 return true;
654 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
655 *params = capabilities_.max_fragment_uniform_vectors;
656 return true;
657 case GL_MAX_RENDERBUFFER_SIZE:
658 *params = capabilities_.max_renderbuffer_size;
659 return true;
660 case GL_MAX_TEXTURE_IMAGE_UNITS:
661 *params = capabilities_.max_texture_image_units;
662 return true;
663 case GL_MAX_TEXTURE_SIZE:
664 *params = capabilities_.max_texture_size;
665 return true;
666 case GL_MAX_VARYING_VECTORS:
667 *params = capabilities_.max_varying_vectors;
668 return true;
669 case GL_MAX_VERTEX_ATTRIBS:
670 *params = capabilities_.max_vertex_attribs;
671 return true;
672 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
673 *params = capabilities_.max_vertex_texture_image_units;
674 return true;
675 case GL_MAX_VERTEX_UNIFORM_VECTORS:
676 *params = capabilities_.max_vertex_uniform_vectors;
677 return true;
678 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
679 *params = capabilities_.num_compressed_texture_formats;
680 return true;
681 case GL_NUM_SHADER_BINARY_FORMATS:
682 *params = capabilities_.num_shader_binary_formats;
683 return true;
684 case GL_RENDERBUFFER_BINDING:
685 *params = bound_renderbuffer_;
686 return true;
687 case GL_TEXTURE_BINDING_2D:
688 *params = texture_units_[active_texture_unit_].bound_texture_2d;
689 return true;
690 case GL_TEXTURE_BINDING_CUBE_MAP:
691 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
692 return true;
694 // Non-standard parameters.
695 case GL_TEXTURE_BINDING_EXTERNAL_OES:
696 *params =
697 texture_units_[active_texture_unit_].bound_texture_external_oes;
698 return true;
699 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
700 *params = bound_pixel_pack_transfer_buffer_id_;
701 return true;
702 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
703 *params = bound_pixel_unpack_transfer_buffer_id_;
704 return true;
705 case GL_READ_FRAMEBUFFER_BINDING:
706 if (IsChromiumFramebufferMultisampleAvailable()) {
707 *params = bound_read_framebuffer_;
708 return true;
710 break;
712 // Non-cached parameters.
713 case GL_ALIASED_LINE_WIDTH_RANGE:
714 case GL_ALIASED_POINT_SIZE_RANGE:
715 case GL_ALPHA_BITS:
716 case GL_BLEND:
717 case GL_BLEND_COLOR:
718 case GL_BLEND_DST_ALPHA:
719 case GL_BLEND_DST_RGB:
720 case GL_BLEND_EQUATION_ALPHA:
721 case GL_BLEND_EQUATION_RGB:
722 case GL_BLEND_SRC_ALPHA:
723 case GL_BLEND_SRC_RGB:
724 case GL_BLUE_BITS:
725 case GL_COLOR_CLEAR_VALUE:
726 case GL_COLOR_WRITEMASK:
727 case GL_COMPRESSED_TEXTURE_FORMATS:
728 case GL_CULL_FACE:
729 case GL_CULL_FACE_MODE:
730 case GL_CURRENT_PROGRAM:
731 case GL_DEPTH_BITS:
732 case GL_DEPTH_CLEAR_VALUE:
733 case GL_DEPTH_FUNC:
734 case GL_DEPTH_RANGE:
735 case GL_DEPTH_TEST:
736 case GL_DEPTH_WRITEMASK:
737 case GL_DITHER:
738 case GL_FRONT_FACE:
739 case GL_GENERATE_MIPMAP_HINT:
740 case GL_GREEN_BITS:
741 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
742 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
743 case GL_LINE_WIDTH:
744 case GL_MAX_VIEWPORT_DIMS:
745 case GL_PACK_ALIGNMENT:
746 case GL_POLYGON_OFFSET_FACTOR:
747 case GL_POLYGON_OFFSET_FILL:
748 case GL_POLYGON_OFFSET_UNITS:
749 case GL_RED_BITS:
750 case GL_SAMPLE_ALPHA_TO_COVERAGE:
751 case GL_SAMPLE_BUFFERS:
752 case GL_SAMPLE_COVERAGE:
753 case GL_SAMPLE_COVERAGE_INVERT:
754 case GL_SAMPLE_COVERAGE_VALUE:
755 case GL_SAMPLES:
756 case GL_SCISSOR_BOX:
757 case GL_SCISSOR_TEST:
758 case GL_SHADER_BINARY_FORMATS:
759 case GL_SHADER_COMPILER:
760 case GL_STENCIL_BACK_FAIL:
761 case GL_STENCIL_BACK_FUNC:
762 case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
763 case GL_STENCIL_BACK_PASS_DEPTH_PASS:
764 case GL_STENCIL_BACK_REF:
765 case GL_STENCIL_BACK_VALUE_MASK:
766 case GL_STENCIL_BACK_WRITEMASK:
767 case GL_STENCIL_BITS:
768 case GL_STENCIL_CLEAR_VALUE:
769 case GL_STENCIL_FAIL:
770 case GL_STENCIL_FUNC:
771 case GL_STENCIL_PASS_DEPTH_FAIL:
772 case GL_STENCIL_PASS_DEPTH_PASS:
773 case GL_STENCIL_REF:
774 case GL_STENCIL_TEST:
775 case GL_STENCIL_VALUE_MASK:
776 case GL_STENCIL_WRITEMASK:
777 case GL_SUBPIXEL_BITS:
778 case GL_UNPACK_ALIGNMENT:
779 case GL_VIEWPORT:
780 return false;
781 default:
782 break;
785 if (capabilities_.major_version < 3) {
786 return false;
789 // ES3 parameters.
790 switch (pname) {
791 case GL_COPY_READ_BUFFER_BINDING:
792 *params = bound_copy_read_buffer_;
793 return true;
794 case GL_COPY_WRITE_BUFFER_BINDING:
795 *params = bound_copy_write_buffer_;
796 return true;
797 case GL_MAJOR_VERSION:
798 *params = capabilities_.major_version;
799 return true;
800 case GL_MAX_3D_TEXTURE_SIZE:
801 *params = capabilities_.max_3d_texture_size;
802 return true;
803 case GL_MAX_ARRAY_TEXTURE_LAYERS:
804 *params = capabilities_.max_array_texture_layers;
805 return true;
806 case GL_MAX_COLOR_ATTACHMENTS:
807 *params = capabilities_.max_color_attachments;
808 return true;
809 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
810 *params = static_cast<GLint>(
811 capabilities_.max_combined_fragment_uniform_components);
812 return true;
813 case GL_MAX_COMBINED_UNIFORM_BLOCKS:
814 *params = capabilities_.max_combined_uniform_blocks;
815 return true;
816 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
817 *params = static_cast<GLint>(
818 capabilities_.max_combined_vertex_uniform_components);
819 return true;
820 case GL_MAX_DRAW_BUFFERS:
821 *params = capabilities_.max_draw_buffers;
822 return true;
823 case GL_MAX_ELEMENT_INDEX:
824 *params = static_cast<GLint>(capabilities_.max_element_index);
825 return true;
826 case GL_MAX_ELEMENTS_INDICES:
827 *params = capabilities_.max_elements_indices;
828 return true;
829 case GL_MAX_ELEMENTS_VERTICES:
830 *params = capabilities_.max_elements_vertices;
831 return true;
832 case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
833 *params = capabilities_.max_fragment_input_components;
834 return true;
835 case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
836 *params = capabilities_.max_fragment_uniform_blocks;
837 return true;
838 case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
839 *params = capabilities_.max_fragment_uniform_components;
840 return true;
841 case GL_MAX_PROGRAM_TEXEL_OFFSET:
842 *params = capabilities_.max_program_texel_offset;
843 return true;
844 case GL_MAX_SAMPLES:
845 *params = capabilities_.max_samples;
846 return true;
847 case GL_MAX_SERVER_WAIT_TIMEOUT:
848 *params = static_cast<GLint>(capabilities_.max_server_wait_timeout);
849 return true;
850 case GL_MAX_TEXTURE_LOD_BIAS:
851 *params = static_cast<GLint>(capabilities_.max_texture_lod_bias);
852 return true;
853 case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
854 *params = capabilities_.max_transform_feedback_interleaved_components;
855 return true;
856 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
857 *params = capabilities_.max_transform_feedback_separate_attribs;
858 return true;
859 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
860 *params = capabilities_.max_transform_feedback_separate_components;
861 return true;
862 case GL_MAX_UNIFORM_BLOCK_SIZE:
863 *params = static_cast<GLint>(capabilities_.max_uniform_block_size);
864 return true;
865 case GL_MAX_UNIFORM_BUFFER_BINDINGS:
866 *params = capabilities_.max_uniform_buffer_bindings;
867 return true;
868 case GL_MAX_VARYING_COMPONENTS:
869 *params = capabilities_.max_varying_components;
870 return true;
871 case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
872 *params = capabilities_.max_vertex_output_components;
873 return true;
874 case GL_MAX_VERTEX_UNIFORM_BLOCKS:
875 *params = capabilities_.max_vertex_uniform_blocks;
876 return true;
877 case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
878 *params = capabilities_.max_vertex_uniform_components;
879 return true;
880 case GL_MIN_PROGRAM_TEXEL_OFFSET:
881 *params = capabilities_.min_program_texel_offset;
882 return true;
883 case GL_MINOR_VERSION:
884 *params = capabilities_.minor_version;
885 return true;
886 case GL_NUM_EXTENSIONS:
887 *params = capabilities_.num_extensions;
888 return true;
889 case GL_NUM_PROGRAM_BINARY_FORMATS:
890 *params = capabilities_.num_program_binary_formats;
891 return true;
892 case GL_PIXEL_PACK_BUFFER_BINDING:
893 *params = bound_pixel_pack_buffer_;
894 return true;
895 case GL_PIXEL_UNPACK_BUFFER_BINDING:
896 *params = bound_pixel_unpack_buffer_;
897 return true;
898 case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
899 *params = bound_transform_feedback_buffer_;
900 return true;
901 case GL_UNIFORM_BUFFER_BINDING:
902 *params = bound_uniform_buffer_;
903 return true;
904 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
905 *params = capabilities_.uniform_buffer_offset_alignment;
906 return true;
908 // Non-cached ES3 parameters.
909 case GL_DRAW_BUFFER0:
910 case GL_DRAW_BUFFER1:
911 case GL_DRAW_BUFFER2:
912 case GL_DRAW_BUFFER3:
913 case GL_DRAW_BUFFER4:
914 case GL_DRAW_BUFFER5:
915 case GL_DRAW_BUFFER6:
916 case GL_DRAW_BUFFER7:
917 case GL_DRAW_BUFFER8:
918 case GL_DRAW_BUFFER9:
919 case GL_DRAW_BUFFER10:
920 case GL_DRAW_BUFFER11:
921 case GL_DRAW_BUFFER12:
922 case GL_DRAW_BUFFER13:
923 case GL_DRAW_BUFFER14:
924 case GL_DRAW_BUFFER15:
925 case GL_DRAW_FRAMEBUFFER_BINDING:
926 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
927 case GL_PACK_ROW_LENGTH:
928 case GL_PACK_SKIP_PIXELS:
929 case GL_PACK_SKIP_ROWS:
930 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
931 case GL_PROGRAM_BINARY_FORMATS:
932 case GL_RASTERIZER_DISCARD:
933 case GL_READ_BUFFER:
934 case GL_READ_FRAMEBUFFER_BINDING:
935 case GL_SAMPLER_BINDING:
936 case GL_TEXTURE_BINDING_2D_ARRAY:
937 case GL_TEXTURE_BINDING_3D:
938 case GL_TRANSFORM_FEEDBACK_BINDING:
939 case GL_TRANSFORM_FEEDBACK_ACTIVE:
940 case GL_TRANSFORM_FEEDBACK_PAUSED:
941 case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
942 case GL_TRANSFORM_FEEDBACK_BUFFER_START:
943 case GL_UNIFORM_BUFFER_SIZE:
944 case GL_UNIFORM_BUFFER_START:
945 case GL_UNPACK_IMAGE_HEIGHT:
946 case GL_UNPACK_ROW_LENGTH:
947 case GL_UNPACK_SKIP_IMAGES:
948 case GL_UNPACK_SKIP_PIXELS:
949 case GL_UNPACK_SKIP_ROWS:
950 case GL_VERTEX_ARRAY_BINDING:
951 return false;
952 default:
953 return false;
957 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
958 // TODO(gman): Make this handle pnames that return more than 1 value.
959 GLint value;
960 if (!GetHelper(pname, &value)) {
961 return false;
963 *params = static_cast<GLboolean>(value);
964 return true;
967 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
968 // TODO(gman): Make this handle pnames that return more than 1 value.
969 switch (pname) {
970 case GL_MAX_TEXTURE_LOD_BIAS:
971 *params = capabilities_.max_texture_lod_bias;
972 return true;
973 default:
974 break;
976 GLint value;
977 if (!GetHelper(pname, &value)) {
978 return false;
980 *params = static_cast<GLfloat>(value);
981 return true;
984 bool GLES2Implementation::GetInteger64vHelper(GLenum pname, GLint64* params) {
985 switch (pname) {
986 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
987 *params = capabilities_.max_combined_fragment_uniform_components;
988 return true;
989 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
990 *params = capabilities_.max_combined_vertex_uniform_components;
991 return true;
992 case GL_MAX_ELEMENT_INDEX:
993 *params = capabilities_.max_element_index;
994 return true;
995 case GL_MAX_SERVER_WAIT_TIMEOUT:
996 *params = capabilities_.max_server_wait_timeout;
997 return true;
998 case GL_MAX_UNIFORM_BLOCK_SIZE:
999 *params = capabilities_.max_uniform_block_size;
1000 return true;
1001 default:
1002 break;
1004 GLint value;
1005 if (!GetHelper(pname, &value)) {
1006 return false;
1008 *params = static_cast<GLint64>(value);
1009 return true;
1012 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
1013 return GetHelper(pname, params);
1016 bool GLES2Implementation::GetIntegeri_vHelper(
1017 GLenum pname, GLuint index, GLint* data) {
1018 // TODO(zmo): Implement client side caching.
1019 return false;
1022 bool GLES2Implementation::GetInteger64i_vHelper(
1023 GLenum pname, GLuint index, GLint64* data) {
1024 // TODO(zmo): Implement client side caching.
1025 return false;
1028 bool GLES2Implementation::GetInternalformativHelper(
1029 GLenum target, GLenum format, GLenum pname, GLsizei bufSize,
1030 GLint* params) {
1031 // TODO(zmo): Implement the client side caching.
1032 return false;
1035 bool GLES2Implementation::GetSyncivHelper(
1036 GLsync sync, GLenum pname, GLsizei bufsize, GLsizei* length,
1037 GLint* values) {
1038 GLint value = 0;
1039 switch (pname) {
1040 case GL_OBJECT_TYPE:
1041 value = GL_SYNC_FENCE;
1042 break;
1043 case GL_SYNC_CONDITION:
1044 value = GL_SYNC_GPU_COMMANDS_COMPLETE;
1045 break;
1046 case GL_SYNC_FLAGS:
1047 value = 0;
1048 break;
1049 default:
1050 return false;
1052 if (bufsize > 0) {
1053 DCHECK(values);
1054 *values = value;
1056 if (length) {
1057 *length = 1;
1059 return true;
1062 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
1063 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1064 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
1065 Result* result = GetResultAs<Result*>();
1066 if (!result) {
1067 return 0;
1069 *result = 0;
1070 helper_->GetMaxValueInBufferCHROMIUM(
1071 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
1072 WaitForCmd();
1073 return *result;
1076 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
1077 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1078 GPU_CLIENT_SINGLE_THREAD_CHECK();
1079 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
1080 << buffer_id << ", " << count << ", "
1081 << GLES2Util::GetStringGetMaxIndexType(type)
1082 << ", " << offset << ")");
1083 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
1084 buffer_id, count, type, offset);
1085 GPU_CLIENT_LOG("returned " << result);
1086 CheckGLError();
1087 return result;
1090 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
1091 if (restore) {
1092 RestoreArrayBuffer(restore);
1093 // Restore the element array binding.
1094 // We only need to restore it if it wasn't a client side array.
1095 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
1096 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1101 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
1102 if (restore) {
1103 // Restore the user's current binding.
1104 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_);
1108 void GLES2Implementation::DrawElements(
1109 GLenum mode, GLsizei count, GLenum type, const void* indices) {
1110 GPU_CLIENT_SINGLE_THREAD_CHECK();
1111 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
1112 << GLES2Util::GetStringDrawMode(mode) << ", "
1113 << count << ", "
1114 << GLES2Util::GetStringIndexType(type) << ", "
1115 << static_cast<const void*>(indices) << ")");
1116 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1119 void GLES2Implementation::DrawRangeElements(
1120 GLenum mode, GLuint start, GLuint end,
1121 GLsizei count, GLenum type, const void* indices) {
1122 GPU_CLIENT_SINGLE_THREAD_CHECK();
1123 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawRangeElements("
1124 << GLES2Util::GetStringDrawMode(mode) << ", "
1125 << start << ", " << end << ", " << count << ", "
1126 << GLES2Util::GetStringIndexType(type) << ", "
1127 << static_cast<const void*>(indices) << ")");
1128 if (end < start) {
1129 SetGLError(GL_INVALID_VALUE, "glDrawRangeElements", "end < start");
1130 return;
1132 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1135 void GLES2Implementation::DrawElementsImpl(
1136 GLenum mode, GLsizei count, GLenum type, const void* indices,
1137 const char* func_name) {
1138 if (count < 0) {
1139 SetGLError(GL_INVALID_VALUE, func_name, "count < 0");
1140 return;
1142 bool simulated = false;
1143 GLuint offset = ToGLuint(indices);
1144 if (count > 0) {
1145 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
1146 !ValidateOffset(func_name, reinterpret_cast<GLintptr>(indices))) {
1147 return;
1149 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
1150 func_name, this, helper_, count, type, 0, indices,
1151 &offset, &simulated)) {
1152 return;
1155 helper_->DrawElements(mode, count, type, offset);
1156 RestoreElementAndArrayBuffers(simulated);
1157 CheckGLError();
1160 void GLES2Implementation::Flush() {
1161 GPU_CLIENT_SINGLE_THREAD_CHECK();
1162 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
1163 // Insert the cmd to call glFlush
1164 helper_->Flush();
1165 FlushHelper();
1168 void GLES2Implementation::ShallowFlushCHROMIUM() {
1169 GPU_CLIENT_SINGLE_THREAD_CHECK();
1170 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
1171 FlushHelper();
1174 void GLES2Implementation::FlushHelper() {
1175 // Flush our command buffer
1176 // (tell the service to execute up to the flush cmd.)
1177 helper_->CommandBufferHelper::Flush();
1179 if (aggressively_free_resources_)
1180 FreeEverything();
1183 void GLES2Implementation::OrderingBarrierCHROMIUM() {
1184 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOrderingBarrierCHROMIUM");
1185 // Flush command buffer at the GPU channel level. May be implemented as
1186 // Flush().
1187 helper_->CommandBufferHelper::OrderingBarrier();
1190 void GLES2Implementation::Finish() {
1191 GPU_CLIENT_SINGLE_THREAD_CHECK();
1192 FinishHelper();
1195 void GLES2Implementation::ShallowFinishCHROMIUM() {
1196 GPU_CLIENT_SINGLE_THREAD_CHECK();
1197 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
1198 // Flush our command buffer (tell the service to execute up to the flush cmd
1199 // and don't return until it completes).
1200 helper_->CommandBufferHelper::Finish();
1202 if (aggressively_free_resources_)
1203 FreeEverything();
1206 void GLES2Implementation::FinishHelper() {
1207 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
1208 TRACE_EVENT0("gpu", "GLES2::Finish");
1209 // Insert the cmd to call glFinish
1210 helper_->Finish();
1211 // Finish our command buffer
1212 // (tell the service to execute up to the Finish cmd and wait for it to
1213 // execute.)
1214 helper_->CommandBufferHelper::Finish();
1216 if (aggressively_free_resources_)
1217 FreeEverything();
1220 void GLES2Implementation::SwapBuffers() {
1221 GPU_CLIENT_SINGLE_THREAD_CHECK();
1222 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
1223 // TODO(piman): Strictly speaking we'd want to insert the token after the
1224 // swap, but the state update with the updated token might not have happened
1225 // by the time the SwapBuffer callback gets called, forcing us to synchronize
1226 // with the GPU process more than needed. So instead, make it happen before.
1227 // All it means is that we could be slightly looser on the kMaxSwapBuffers
1228 // semantics if the client doesn't use the callback mechanism, and by chance
1229 // the scheduler yields between the InsertToken and the SwapBuffers.
1230 swap_buffers_tokens_.push(helper_->InsertToken());
1231 helper_->SwapBuffers();
1232 helper_->CommandBufferHelper::Flush();
1233 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
1234 // compensate for TODO above.
1235 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
1236 helper_->WaitForToken(swap_buffers_tokens_.front());
1237 swap_buffers_tokens_.pop();
1241 void GLES2Implementation::SwapInterval(int interval) {
1242 GPU_CLIENT_SINGLE_THREAD_CHECK();
1243 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapInterval("
1244 << interval << ")");
1245 helper_->SwapInterval(interval);
1248 void GLES2Implementation::BindAttribLocation(
1249 GLuint program, GLuint index, const char* name) {
1250 GPU_CLIENT_SINGLE_THREAD_CHECK();
1251 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
1252 << program << ", " << index << ", " << name << ")");
1253 SetBucketAsString(kResultBucketId, name);
1254 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
1255 helper_->SetBucketSize(kResultBucketId, 0);
1256 CheckGLError();
1259 void GLES2Implementation::BindUniformLocationCHROMIUM(
1260 GLuint program, GLint location, const char* name) {
1261 GPU_CLIENT_SINGLE_THREAD_CHECK();
1262 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1263 << program << ", " << location << ", " << name << ")");
1264 SetBucketAsString(kResultBucketId, name);
1265 helper_->BindUniformLocationCHROMIUMBucket(
1266 program, location, kResultBucketId);
1267 helper_->SetBucketSize(kResultBucketId, 0);
1268 CheckGLError();
1271 void GLES2Implementation::GetVertexAttribPointerv(
1272 GLuint index, GLenum pname, void** ptr) {
1273 GPU_CLIENT_SINGLE_THREAD_CHECK();
1274 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1275 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1276 << static_cast<void*>(ptr) << ")");
1277 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
1278 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1279 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1280 typedef cmds::GetVertexAttribPointerv::Result Result;
1281 Result* result = GetResultAs<Result*>();
1282 if (!result) {
1283 return;
1285 result->SetNumResults(0);
1286 helper_->GetVertexAttribPointerv(
1287 index, pname, GetResultShmId(), GetResultShmOffset());
1288 WaitForCmd();
1289 result->CopyResult(ptr);
1290 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1292 GPU_CLIENT_LOG_CODE_BLOCK({
1293 for (int32 i = 0; i < num_results; ++i) {
1294 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
1297 CheckGLError();
1300 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1301 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1302 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
1303 SetGLError(
1304 GL_INVALID_VALUE,
1305 "glDeleteProgram", "id not created by this context.");
1306 return false;
1308 if (program == current_program_) {
1309 current_program_ = 0;
1311 return true;
1314 void GLES2Implementation::DeleteProgramStub(
1315 GLsizei n, const GLuint* programs) {
1316 DCHECK_EQ(1, n);
1317 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1318 helper_->DeleteProgram(programs[0]);
1321 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1322 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1323 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1324 SetGLError(
1325 GL_INVALID_VALUE,
1326 "glDeleteShader", "id not created by this context.");
1327 return false;
1329 return true;
1332 void GLES2Implementation::DeleteShaderStub(
1333 GLsizei n, const GLuint* shaders) {
1334 DCHECK_EQ(1, n);
1335 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1336 helper_->DeleteShader(shaders[0]);
1339 void GLES2Implementation::DeleteSyncHelper(GLsync sync) {
1340 GLuint sync_uint = ToGLuint(sync);
1341 if (!GetIdHandler(id_namespaces::kSyncs)->FreeIds(
1342 this, 1, &sync_uint, &GLES2Implementation::DeleteSyncStub)) {
1343 SetGLError(
1344 GL_INVALID_VALUE,
1345 "glDeleteSync", "id not created by this context.");
1349 void GLES2Implementation::DeleteSyncStub(GLsizei n, const GLuint* syncs) {
1350 DCHECK_EQ(1, n);
1351 helper_->DeleteSync(syncs[0]);
1354 GLint GLES2Implementation::GetAttribLocationHelper(
1355 GLuint program, const char* name) {
1356 typedef cmds::GetAttribLocation::Result Result;
1357 Result* result = GetResultAs<Result*>();
1358 if (!result) {
1359 return -1;
1361 *result = -1;
1362 SetBucketAsCString(kResultBucketId, name);
1363 helper_->GetAttribLocation(
1364 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1365 WaitForCmd();
1366 helper_->SetBucketSize(kResultBucketId, 0);
1367 return *result;
1370 GLint GLES2Implementation::GetAttribLocation(
1371 GLuint program, const char* name) {
1372 GPU_CLIENT_SINGLE_THREAD_CHECK();
1373 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1374 << ", " << name << ")");
1375 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1376 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1377 this, program, name);
1378 GPU_CLIENT_LOG("returned " << loc);
1379 CheckGLError();
1380 return loc;
1383 GLint GLES2Implementation::GetUniformLocationHelper(
1384 GLuint program, const char* name) {
1385 typedef cmds::GetUniformLocation::Result Result;
1386 Result* result = GetResultAs<Result*>();
1387 if (!result) {
1388 return -1;
1390 *result = -1;
1391 SetBucketAsCString(kResultBucketId, name);
1392 helper_->GetUniformLocation(program, kResultBucketId,
1393 GetResultShmId(), GetResultShmOffset());
1394 WaitForCmd();
1395 helper_->SetBucketSize(kResultBucketId, 0);
1396 return *result;
1399 GLint GLES2Implementation::GetUniformLocation(
1400 GLuint program, const char* name) {
1401 GPU_CLIENT_SINGLE_THREAD_CHECK();
1402 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1403 << ", " << name << ")");
1404 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1405 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1406 this, program, name);
1407 GPU_CLIENT_LOG("returned " << loc);
1408 CheckGLError();
1409 return loc;
1412 bool GLES2Implementation::GetUniformIndicesHelper(
1413 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1414 typedef cmds::GetUniformIndices::Result Result;
1415 Result* result = GetResultAs<Result*>();
1416 if (!result) {
1417 return false;
1419 result->SetNumResults(0);
1420 if (!PackStringsToBucket(count, names, NULL, "glGetUniformIndices")) {
1421 return false;
1423 helper_->GetUniformIndices(program, kResultBucketId,
1424 GetResultShmId(), GetResultShmOffset());
1425 WaitForCmd();
1426 if (result->GetNumResults() != count) {
1427 return false;
1429 result->CopyResult(indices);
1430 return true;
1433 void GLES2Implementation::GetUniformIndices(
1434 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1435 GPU_CLIENT_SINGLE_THREAD_CHECK();
1436 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
1437 << ", " << count << ", " << names << ", " << indices << ")");
1438 TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
1439 if (count < 0) {
1440 SetGLError(GL_INVALID_VALUE, "glGetUniformIndices", "count < 0");
1441 return;
1443 if (count == 0) {
1444 return;
1446 bool success = share_group_->program_info_manager()->GetUniformIndices(
1447 this, program, count, names, indices);
1448 if (success) {
1449 GPU_CLIENT_LOG_CODE_BLOCK({
1450 for (GLsizei ii = 0; ii < count; ++ii) {
1451 GPU_CLIENT_LOG(" " << ii << ": " << indices[ii]);
1455 CheckGLError();
1458 bool GLES2Implementation::GetProgramivHelper(
1459 GLuint program, GLenum pname, GLint* params) {
1460 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1461 this, program, pname, params);
1462 GPU_CLIENT_LOG_CODE_BLOCK({
1463 if (got_value) {
1464 GPU_CLIENT_LOG(" 0: " << *params);
1467 return got_value;
1470 GLint GLES2Implementation::GetFragDataLocationHelper(
1471 GLuint program, const char* name) {
1472 typedef cmds::GetFragDataLocation::Result Result;
1473 Result* result = GetResultAs<Result*>();
1474 if (!result) {
1475 return -1;
1477 *result = -1;
1478 SetBucketAsCString(kResultBucketId, name);
1479 helper_->GetFragDataLocation(
1480 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1481 WaitForCmd();
1482 helper_->SetBucketSize(kResultBucketId, 0);
1483 return *result;
1486 GLint GLES2Implementation::GetFragDataLocation(
1487 GLuint program, const char* name) {
1488 GPU_CLIENT_SINGLE_THREAD_CHECK();
1489 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataLocation("
1490 << program << ", " << name << ")");
1491 TRACE_EVENT0("gpu", "GLES2::GetFragDataLocation");
1492 GLint loc = share_group_->program_info_manager()->GetFragDataLocation(
1493 this, program, name);
1494 GPU_CLIENT_LOG("returned " << loc);
1495 CheckGLError();
1496 return loc;
1499 GLuint GLES2Implementation::GetUniformBlockIndexHelper(
1500 GLuint program, const char* name) {
1501 typedef cmds::GetUniformBlockIndex::Result Result;
1502 Result* result = GetResultAs<Result*>();
1503 if (!result) {
1504 return GL_INVALID_INDEX;
1506 *result = GL_INVALID_INDEX;
1507 SetBucketAsCString(kResultBucketId, name);
1508 helper_->GetUniformBlockIndex(
1509 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1510 WaitForCmd();
1511 helper_->SetBucketSize(kResultBucketId, 0);
1512 return *result;
1515 GLuint GLES2Implementation::GetUniformBlockIndex(
1516 GLuint program, const char* name) {
1517 GPU_CLIENT_SINGLE_THREAD_CHECK();
1518 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformBlockIndex("
1519 << program << ", " << name << ")");
1520 TRACE_EVENT0("gpu", "GLES2::GetUniformBlockIndex");
1521 GLuint index = share_group_->program_info_manager()->GetUniformBlockIndex(
1522 this, program, name);
1523 GPU_CLIENT_LOG("returned " << index);
1524 CheckGLError();
1525 return index;
1528 void GLES2Implementation::LinkProgram(GLuint program) {
1529 GPU_CLIENT_SINGLE_THREAD_CHECK();
1530 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1531 helper_->LinkProgram(program);
1532 share_group_->program_info_manager()->CreateInfo(program);
1533 CheckGLError();
1536 void GLES2Implementation::ShaderBinary(
1537 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1538 GLsizei length) {
1539 GPU_CLIENT_SINGLE_THREAD_CHECK();
1540 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1541 << static_cast<const void*>(shaders) << ", "
1542 << GLES2Util::GetStringEnum(binaryformat) << ", "
1543 << static_cast<const void*>(binary) << ", "
1544 << length << ")");
1545 if (n < 0) {
1546 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1547 return;
1549 if (length < 0) {
1550 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1551 return;
1553 // TODO(gman): ShaderBinary should use buckets.
1554 unsigned int shader_id_size = n * sizeof(*shaders);
1555 ScopedTransferBufferArray<GLint> buffer(
1556 shader_id_size + length, helper_, transfer_buffer_);
1557 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1558 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1559 return;
1561 void* shader_ids = buffer.elements();
1562 void* shader_data = buffer.elements() + shader_id_size;
1563 memcpy(shader_ids, shaders, shader_id_size);
1564 memcpy(shader_data, binary, length);
1565 helper_->ShaderBinary(
1567 buffer.shm_id(),
1568 buffer.offset(),
1569 binaryformat,
1570 buffer.shm_id(),
1571 buffer.offset() + shader_id_size,
1572 length);
1573 CheckGLError();
1576 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1577 GPU_CLIENT_SINGLE_THREAD_CHECK();
1578 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1579 << GLES2Util::GetStringPixelStore(pname) << ", "
1580 << param << ")");
1581 switch (pname) {
1582 case GL_PACK_ALIGNMENT:
1583 pack_alignment_ = param;
1584 break;
1585 case GL_UNPACK_ALIGNMENT:
1586 unpack_alignment_ = param;
1587 break;
1588 case GL_UNPACK_ROW_LENGTH_EXT:
1589 unpack_row_length_ = param;
1590 return;
1591 case GL_UNPACK_IMAGE_HEIGHT:
1592 unpack_image_height_ = param;
1593 return;
1594 case GL_UNPACK_SKIP_ROWS_EXT:
1595 unpack_skip_rows_ = param;
1596 return;
1597 case GL_UNPACK_SKIP_PIXELS_EXT:
1598 unpack_skip_pixels_ = param;
1599 return;
1600 case GL_UNPACK_SKIP_IMAGES:
1601 unpack_skip_images_ = param;
1602 return;
1603 case GL_UNPACK_FLIP_Y_CHROMIUM:
1604 unpack_flip_y_ = (param != 0);
1605 break;
1606 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1607 pack_reverse_row_order_ =
1608 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1609 break;
1610 default:
1611 break;
1613 helper_->PixelStorei(pname, param);
1614 CheckGLError();
1617 void GLES2Implementation::VertexAttribIPointer(
1618 GLuint index, GLint size, GLenum type, GLsizei stride, const void* ptr) {
1619 GPU_CLIENT_SINGLE_THREAD_CHECK();
1620 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribIPointer("
1621 << index << ", "
1622 << size << ", "
1623 << GLES2Util::GetStringVertexAttribIType(type) << ", "
1624 << stride << ", "
1625 << ptr << ")");
1626 // Record the info on the client side.
1627 if (!vertex_array_object_manager_->SetAttribPointer(bound_array_buffer_,
1628 index,
1629 size,
1630 type,
1631 GL_FALSE,
1632 stride,
1633 ptr,
1634 GL_TRUE)) {
1635 SetGLError(GL_INVALID_OPERATION, "glVertexAttribIPointer",
1636 "client side arrays are not allowed in vertex array objects.");
1637 return;
1639 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
1640 // Only report NON client side buffers to the service.
1641 if (!ValidateOffset("glVertexAttribIPointer",
1642 reinterpret_cast<GLintptr>(ptr))) {
1643 return;
1645 helper_->VertexAttribIPointer(index, size, type, stride, ToGLuint(ptr));
1647 CheckGLError();
1650 void GLES2Implementation::VertexAttribPointer(
1651 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1652 const void* ptr) {
1653 GPU_CLIENT_SINGLE_THREAD_CHECK();
1654 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1655 << index << ", "
1656 << size << ", "
1657 << GLES2Util::GetStringVertexAttribType(type) << ", "
1658 << GLES2Util::GetStringBool(normalized) << ", "
1659 << stride << ", "
1660 << ptr << ")");
1661 // Record the info on the client side.
1662 if (!vertex_array_object_manager_->SetAttribPointer(bound_array_buffer_,
1663 index,
1664 size,
1665 type,
1666 normalized,
1667 stride,
1668 ptr,
1669 GL_FALSE)) {
1670 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1671 "client side arrays are not allowed in vertex array objects.");
1672 return;
1674 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
1675 // Only report NON client side buffers to the service.
1676 if (!ValidateOffset("glVertexAttribPointer",
1677 reinterpret_cast<GLintptr>(ptr))) {
1678 return;
1680 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1681 ToGLuint(ptr));
1683 CheckGLError();
1686 void GLES2Implementation::VertexAttribDivisorANGLE(
1687 GLuint index, GLuint divisor) {
1688 GPU_CLIENT_SINGLE_THREAD_CHECK();
1689 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1690 << index << ", "
1691 << divisor << ") ");
1692 // Record the info on the client side.
1693 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1694 helper_->VertexAttribDivisorANGLE(index, divisor);
1695 CheckGLError();
1698 void GLES2Implementation::BufferDataHelper(
1699 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1700 if (!ValidateSize("glBufferData", size))
1701 return;
1703 #if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
1704 // Do not upload uninitialized data. Even if it's not a bug, it can cause a
1705 // bogus MSan report during a readback later. This is because MSan doesn't
1706 // understand shared memory and would assume we were reading back the same
1707 // unintialized data.
1708 if (data) __msan_check_mem_is_initialized(data, size);
1709 #endif
1711 GLuint buffer_id;
1712 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1713 if (!buffer_id) {
1714 return;
1717 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1718 if (buffer)
1719 RemoveTransferBuffer(buffer);
1721 // Create new buffer.
1722 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1723 DCHECK(buffer);
1724 if (buffer->address() && data)
1725 memcpy(buffer->address(), data, size);
1726 return;
1729 RemoveMappedBufferRangeByTarget(target);
1731 // If there is no data just send BufferData
1732 if (size == 0 || !data) {
1733 helper_->BufferData(target, size, 0, 0, usage);
1734 return;
1737 // See if we can send all at once.
1738 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1739 if (!buffer.valid()) {
1740 return;
1743 if (buffer.size() >= static_cast<unsigned int>(size)) {
1744 memcpy(buffer.address(), data, size);
1745 helper_->BufferData(
1746 target,
1747 size,
1748 buffer.shm_id(),
1749 buffer.offset(),
1750 usage);
1751 return;
1754 // Make the buffer with BufferData then send via BufferSubData
1755 helper_->BufferData(target, size, 0, 0, usage);
1756 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1757 CheckGLError();
1760 void GLES2Implementation::BufferData(
1761 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1762 GPU_CLIENT_SINGLE_THREAD_CHECK();
1763 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1764 << GLES2Util::GetStringBufferTarget(target) << ", "
1765 << size << ", "
1766 << static_cast<const void*>(data) << ", "
1767 << GLES2Util::GetStringBufferUsage(usage) << ")");
1768 BufferDataHelper(target, size, data, usage);
1769 CheckGLError();
1772 void GLES2Implementation::BufferSubDataHelper(
1773 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1774 if (size == 0) {
1775 return;
1778 if (!ValidateSize("glBufferSubData", size) ||
1779 !ValidateOffset("glBufferSubData", offset)) {
1780 return;
1783 GLuint buffer_id;
1784 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1785 if (!buffer_id) {
1786 return;
1788 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1789 if (!buffer) {
1790 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1791 return;
1794 int32 end = 0;
1795 int32 buffer_size = buffer->size();
1796 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1797 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1798 return;
1801 if (buffer->address() && data)
1802 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1803 return;
1806 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1807 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1810 void GLES2Implementation::BufferSubDataHelperImpl(
1811 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1812 ScopedTransferBufferPtr* buffer) {
1813 DCHECK(buffer);
1814 DCHECK_GT(size, 0);
1816 const int8* source = static_cast<const int8*>(data);
1817 while (size) {
1818 if (!buffer->valid() || buffer->size() == 0) {
1819 buffer->Reset(size);
1820 if (!buffer->valid()) {
1821 return;
1824 memcpy(buffer->address(), source, buffer->size());
1825 helper_->BufferSubData(
1826 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1827 offset += buffer->size();
1828 source += buffer->size();
1829 size -= buffer->size();
1830 buffer->Release();
1834 void GLES2Implementation::BufferSubData(
1835 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1836 GPU_CLIENT_SINGLE_THREAD_CHECK();
1837 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1838 << GLES2Util::GetStringBufferTarget(target) << ", "
1839 << offset << ", " << size << ", "
1840 << static_cast<const void*>(data) << ")");
1841 BufferSubDataHelper(target, offset, size, data);
1842 CheckGLError();
1845 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
1846 int32 token = buffer->last_usage_token();
1847 uint32 async_token = buffer->last_async_upload_token();
1849 if (async_token) {
1850 if (HasAsyncUploadTokenPassed(async_token)) {
1851 buffer_tracker_->Free(buffer);
1852 } else {
1853 detached_async_upload_memory_.push_back(
1854 std::make_pair(buffer->address(), async_token));
1855 buffer_tracker_->Unmanage(buffer);
1857 } else if (token) {
1858 if (helper_->HasTokenPassed(token))
1859 buffer_tracker_->Free(buffer);
1860 else
1861 buffer_tracker_->FreePendingToken(buffer, token);
1862 } else {
1863 buffer_tracker_->Free(buffer);
1866 buffer_tracker_->RemoveBuffer(buffer->id());
1869 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1870 GLenum target,
1871 const char* function_name,
1872 GLuint* buffer_id) {
1873 *buffer_id = 0;
1875 switch (target) {
1876 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1877 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1878 break;
1879 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1880 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1881 break;
1882 default:
1883 // Unknown target
1884 return false;
1886 if (!*buffer_id) {
1887 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1889 return true;
1892 BufferTracker::Buffer*
1893 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1894 GLuint buffer_id,
1895 const char* function_name,
1896 GLuint offset, GLsizei size) {
1897 DCHECK(buffer_id);
1898 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1899 if (!buffer) {
1900 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1901 return NULL;
1903 if (buffer->mapped()) {
1904 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1905 return NULL;
1907 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1908 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1909 return NULL;
1911 return buffer;
1914 void GLES2Implementation::CompressedTexImage2D(
1915 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1916 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1917 GPU_CLIENT_SINGLE_THREAD_CHECK();
1918 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1919 << GLES2Util::GetStringTextureTarget(target) << ", "
1920 << level << ", "
1921 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1922 << width << ", " << height << ", " << border << ", "
1923 << image_size << ", "
1924 << static_cast<const void*>(data) << ")");
1925 if (width < 0 || height < 0 || level < 0) {
1926 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1927 return;
1929 if (border != 0) {
1930 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "border != 0");
1931 return;
1933 if (height == 0 || width == 0) {
1934 return;
1936 // If there's a pixel unpack buffer bound use it when issuing
1937 // CompressedTexImage2D.
1938 if (bound_pixel_unpack_transfer_buffer_id_) {
1939 GLuint offset = ToGLuint(data);
1940 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1941 bound_pixel_unpack_transfer_buffer_id_,
1942 "glCompressedTexImage2D", offset, image_size);
1943 if (buffer && buffer->shm_id() != -1) {
1944 helper_->CompressedTexImage2D(
1945 target, level, internalformat, width, height, image_size,
1946 buffer->shm_id(), buffer->shm_offset() + offset);
1947 buffer->set_last_usage_token(helper_->InsertToken());
1949 return;
1951 SetBucketContents(kResultBucketId, data, image_size);
1952 helper_->CompressedTexImage2DBucket(
1953 target, level, internalformat, width, height, kResultBucketId);
1954 // Free the bucket. This is not required but it does free up the memory.
1955 // and we don't have to wait for the result so from the client's perspective
1956 // it's cheap.
1957 helper_->SetBucketSize(kResultBucketId, 0);
1958 CheckGLError();
1961 void GLES2Implementation::CompressedTexSubImage2D(
1962 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1963 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1964 GPU_CLIENT_SINGLE_THREAD_CHECK();
1965 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1966 << GLES2Util::GetStringTextureTarget(target) << ", "
1967 << level << ", "
1968 << xoffset << ", " << yoffset << ", "
1969 << width << ", " << height << ", "
1970 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1971 << image_size << ", "
1972 << static_cast<const void*>(data) << ")");
1973 if (width < 0 || height < 0 || level < 0) {
1974 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1975 return;
1977 // If there's a pixel unpack buffer bound use it when issuing
1978 // CompressedTexSubImage2D.
1979 if (bound_pixel_unpack_transfer_buffer_id_) {
1980 GLuint offset = ToGLuint(data);
1981 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1982 bound_pixel_unpack_transfer_buffer_id_,
1983 "glCompressedTexSubImage2D", offset, image_size);
1984 if (buffer && buffer->shm_id() != -1) {
1985 helper_->CompressedTexSubImage2D(
1986 target, level, xoffset, yoffset, width, height, format, image_size,
1987 buffer->shm_id(), buffer->shm_offset() + offset);
1988 buffer->set_last_usage_token(helper_->InsertToken());
1989 CheckGLError();
1991 return;
1993 SetBucketContents(kResultBucketId, data, image_size);
1994 helper_->CompressedTexSubImage2DBucket(
1995 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1996 // Free the bucket. This is not required but it does free up the memory.
1997 // and we don't have to wait for the result so from the client's perspective
1998 // it's cheap.
1999 helper_->SetBucketSize(kResultBucketId, 0);
2000 CheckGLError();
2003 void GLES2Implementation::CompressedTexImage3D(
2004 GLenum target, GLint level, GLenum internalformat, GLsizei width,
2005 GLsizei height, GLsizei depth, GLint border, GLsizei image_size,
2006 const void* data) {
2007 GPU_CLIENT_SINGLE_THREAD_CHECK();
2008 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage3D("
2009 << GLES2Util::GetStringTexture3DTarget(target) << ", " << level << ", "
2010 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
2011 << width << ", " << height << ", " << depth << ", " << border << ", "
2012 << image_size << ", " << static_cast<const void*>(data) << ")");
2013 if (width < 0 || height < 0 || depth < 0 || level < 0) {
2014 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "dimension < 0");
2015 return;
2017 if (border != 0) {
2018 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "border != 0");
2019 return;
2021 if (height == 0 || width == 0 || depth == 0) {
2022 return;
2024 // If there's a pixel unpack buffer bound use it when issuing
2025 // CompressedTexImage3D.
2026 if (bound_pixel_unpack_transfer_buffer_id_) {
2027 GLuint offset = ToGLuint(data);
2028 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2029 bound_pixel_unpack_transfer_buffer_id_,
2030 "glCompressedTexImage3D", offset, image_size);
2031 if (buffer && buffer->shm_id() != -1) {
2032 helper_->CompressedTexImage3D(
2033 target, level, internalformat, width, height, depth, image_size,
2034 buffer->shm_id(), buffer->shm_offset() + offset);
2035 buffer->set_last_usage_token(helper_->InsertToken());
2037 return;
2039 SetBucketContents(kResultBucketId, data, image_size);
2040 helper_->CompressedTexImage3DBucket(
2041 target, level, internalformat, width, height, depth, kResultBucketId);
2042 // Free the bucket. This is not required but it does free up the memory.
2043 // and we don't have to wait for the result so from the client's perspective
2044 // it's cheap.
2045 helper_->SetBucketSize(kResultBucketId, 0);
2046 CheckGLError();
2049 void GLES2Implementation::CompressedTexSubImage3D(
2050 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2051 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2052 GLsizei image_size, const void* data) {
2053 GPU_CLIENT_SINGLE_THREAD_CHECK();
2054 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage3D("
2055 << GLES2Util::GetStringTextureTarget(target) << ", "
2056 << level << ", "
2057 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2058 << width << ", " << height << ", " << depth << ", "
2059 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
2060 << image_size << ", "
2061 << static_cast<const void*>(data) << ")");
2062 if (width < 0 || height < 0 || depth < 0 || level < 0) {
2063 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage3D", "dimension < 0");
2064 return;
2066 // If there's a pixel unpack buffer bound use it when issuing
2067 // CompressedTexSubImage3D.
2068 if (bound_pixel_unpack_transfer_buffer_id_) {
2069 GLuint offset = ToGLuint(data);
2070 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2071 bound_pixel_unpack_transfer_buffer_id_,
2072 "glCompressedTexSubImage3D", offset, image_size);
2073 if (buffer && buffer->shm_id() != -1) {
2074 helper_->CompressedTexSubImage3D(
2075 target, level, xoffset, yoffset, zoffset,
2076 width, height, depth, format, image_size,
2077 buffer->shm_id(), buffer->shm_offset() + offset);
2078 buffer->set_last_usage_token(helper_->InsertToken());
2079 CheckGLError();
2081 return;
2083 SetBucketContents(kResultBucketId, data, image_size);
2084 helper_->CompressedTexSubImage3DBucket(
2085 target, level, xoffset, yoffset, zoffset, width, height, depth, format,
2086 kResultBucketId);
2087 // Free the bucket. This is not required but it does free up the memory.
2088 // and we don't have to wait for the result so from the client's perspective
2089 // it's cheap.
2090 helper_->SetBucketSize(kResultBucketId, 0);
2091 CheckGLError();
2094 namespace {
2096 void CopyRectToBuffer(
2097 const void* pixels,
2098 uint32 height,
2099 uint32 unpadded_row_size,
2100 uint32 pixels_padded_row_size,
2101 bool flip_y,
2102 void* buffer,
2103 uint32 buffer_padded_row_size) {
2104 const int8* source = static_cast<const int8*>(pixels);
2105 int8* dest = static_cast<int8*>(buffer);
2106 if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
2107 if (flip_y) {
2108 dest += buffer_padded_row_size * (height - 1);
2110 // the last row is copied unpadded at the end
2111 for (; height > 1; --height) {
2112 memcpy(dest, source, buffer_padded_row_size);
2113 if (flip_y) {
2114 dest -= buffer_padded_row_size;
2115 } else {
2116 dest += buffer_padded_row_size;
2118 source += pixels_padded_row_size;
2120 memcpy(dest, source, unpadded_row_size);
2121 } else {
2122 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
2123 memcpy(dest, source, size);
2127 } // anonymous namespace
2129 void GLES2Implementation::TexImage2D(
2130 GLenum target, GLint level, GLint internalformat, GLsizei width,
2131 GLsizei height, GLint border, GLenum format, GLenum type,
2132 const void* pixels) {
2133 GPU_CLIENT_SINGLE_THREAD_CHECK();
2134 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
2135 << GLES2Util::GetStringTextureTarget(target) << ", "
2136 << level << ", "
2137 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2138 << width << ", " << height << ", " << border << ", "
2139 << GLES2Util::GetStringTextureFormat(format) << ", "
2140 << GLES2Util::GetStringPixelType(type) << ", "
2141 << static_cast<const void*>(pixels) << ")");
2142 if (level < 0 || height < 0 || width < 0) {
2143 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
2144 return;
2146 if (border != 0) {
2147 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
2148 return;
2150 uint32 size;
2151 uint32 unpadded_row_size;
2152 uint32 padded_row_size;
2153 if (!GLES2Util::ComputeImageDataSizes(
2154 width, height, 1, format, type, unpack_alignment_, &size,
2155 &unpadded_row_size, &padded_row_size)) {
2156 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
2157 return;
2160 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
2161 if (bound_pixel_unpack_transfer_buffer_id_) {
2162 GLuint offset = ToGLuint(pixels);
2163 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2164 bound_pixel_unpack_transfer_buffer_id_,
2165 "glTexImage2D", offset, size);
2166 if (buffer && buffer->shm_id() != -1) {
2167 helper_->TexImage2D(
2168 target, level, internalformat, width, height, format, type,
2169 buffer->shm_id(), buffer->shm_offset() + offset);
2170 buffer->set_last_usage_token(helper_->InsertToken());
2171 CheckGLError();
2173 return;
2176 // If there's no data just issue TexImage2D
2177 if (!pixels) {
2178 helper_->TexImage2D(
2179 target, level, internalformat, width, height, format, type,
2180 0, 0);
2181 CheckGLError();
2182 return;
2185 // compute the advance bytes per row for the src pixels
2186 uint32 src_padded_row_size;
2187 if (unpack_row_length_ > 0) {
2188 if (!GLES2Util::ComputeImagePaddedRowSize(
2189 unpack_row_length_, format, type, unpack_alignment_,
2190 &src_padded_row_size)) {
2191 SetGLError(
2192 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2193 return;
2195 } else {
2196 src_padded_row_size = padded_row_size;
2199 // advance pixels pointer past the skip rows and skip pixels
2200 pixels = reinterpret_cast<const int8*>(pixels) +
2201 unpack_skip_rows_ * src_padded_row_size;
2202 if (unpack_skip_pixels_) {
2203 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2204 pixels = reinterpret_cast<const int8*>(pixels) +
2205 unpack_skip_pixels_ * group_size;
2208 // Check if we can send it all at once.
2209 int32_t shm_id = 0;
2210 uint32_t shm_offset = 0;
2211 void* buffer_pointer = nullptr;
2213 ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
2214 ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
2216 if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
2217 shm_id = transfer_alloc.shm_id();
2218 shm_offset = transfer_alloc.offset();
2219 buffer_pointer = transfer_alloc.address();
2220 } else {
2221 mapped_alloc.Reset(size);
2222 if (mapped_alloc.valid()) {
2223 transfer_alloc.Discard();
2225 mapped_alloc.SetFlushAfterRelease(true);
2226 shm_id = mapped_alloc.shm_id();
2227 shm_offset = mapped_alloc.offset();
2228 buffer_pointer = mapped_alloc.address();
2232 if (buffer_pointer) {
2233 CopyRectToBuffer(
2234 pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
2235 buffer_pointer, padded_row_size);
2236 helper_->TexImage2D(
2237 target, level, internalformat, width, height, format, type,
2238 shm_id, shm_offset);
2239 CheckGLError();
2240 return;
2243 // No, so send it using TexSubImage2D.
2244 helper_->TexImage2D(
2245 target, level, internalformat, width, height, format, type,
2246 0, 0);
2247 TexSubImage2DImpl(
2248 target, level, 0, 0, width, height, format, type, unpadded_row_size,
2249 pixels, src_padded_row_size, GL_TRUE, &transfer_alloc, padded_row_size);
2250 CheckGLError();
2253 void GLES2Implementation::TexImage3D(
2254 GLenum target, GLint level, GLint internalformat, GLsizei width,
2255 GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type,
2256 const void* pixels) {
2257 GPU_CLIENT_SINGLE_THREAD_CHECK();
2258 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D("
2259 << GLES2Util::GetStringTextureTarget(target) << ", "
2260 << level << ", "
2261 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2262 << width << ", " << height << ", " << depth << ", " << border << ", "
2263 << GLES2Util::GetStringTextureFormat(format) << ", "
2264 << GLES2Util::GetStringPixelType(type) << ", "
2265 << static_cast<const void*>(pixels) << ")");
2266 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2267 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "dimension < 0");
2268 return;
2270 if (border != 0) {
2271 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "border != 0");
2272 return;
2274 uint32 size;
2275 uint32 unpadded_row_size;
2276 uint32 padded_row_size;
2277 if (!GLES2Util::ComputeImageDataSizes(
2278 width, height, depth, format, type, unpack_alignment_, &size,
2279 &unpadded_row_size, &padded_row_size)) {
2280 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large");
2281 return;
2284 // If there's a pixel unpack buffer bound use it when issuing TexImage3D.
2285 if (bound_pixel_unpack_transfer_buffer_id_) {
2286 GLuint offset = ToGLuint(pixels);
2287 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2288 bound_pixel_unpack_transfer_buffer_id_,
2289 "glTexImage3D", offset, size);
2290 if (buffer && buffer->shm_id() != -1) {
2291 helper_->TexImage3D(
2292 target, level, internalformat, width, height, depth, format, type,
2293 buffer->shm_id(), buffer->shm_offset() + offset);
2294 buffer->set_last_usage_token(helper_->InsertToken());
2295 CheckGLError();
2297 return;
2300 // If there's no data just issue TexImage3D
2301 if (!pixels) {
2302 helper_->TexImage3D(
2303 target, level, internalformat, width, height, depth, format, type,
2304 0, 0);
2305 CheckGLError();
2306 return;
2309 // compute the advance bytes per row for the src pixels
2310 uint32 src_padded_row_size;
2311 if (unpack_row_length_ > 0) {
2312 if (!GLES2Util::ComputeImagePaddedRowSize(
2313 unpack_row_length_, format, type, unpack_alignment_,
2314 &src_padded_row_size)) {
2315 SetGLError(
2316 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2317 return;
2319 } else {
2320 src_padded_row_size = padded_row_size;
2322 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2324 // advance pixels pointer past the skip images/rows/pixels
2325 pixels = reinterpret_cast<const int8*>(pixels) +
2326 unpack_skip_images_ * src_padded_row_size * src_height +
2327 unpack_skip_rows_ * src_padded_row_size;
2328 if (unpack_skip_pixels_) {
2329 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2330 pixels = reinterpret_cast<const int8*>(pixels) +
2331 unpack_skip_pixels_ * group_size;
2334 // Check if we can send it all at once.
2335 int32_t shm_id = 0;
2336 uint32_t shm_offset = 0;
2337 void* buffer_pointer = nullptr;
2339 ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
2340 ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
2342 if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
2343 shm_id = transfer_alloc.shm_id();
2344 shm_offset = transfer_alloc.offset();
2345 buffer_pointer = transfer_alloc.address();
2346 } else {
2347 mapped_alloc.Reset(size);
2348 if (mapped_alloc.valid()) {
2349 transfer_alloc.Discard();
2351 mapped_alloc.SetFlushAfterRelease(true);
2352 shm_id = mapped_alloc.shm_id();
2353 shm_offset = mapped_alloc.offset();
2354 buffer_pointer = mapped_alloc.address();
2358 if (buffer_pointer) {
2359 for (GLsizei z = 0; z < depth; ++z) {
2360 // Only the last row of the last image is unpadded.
2361 uint32 src_unpadded_row_size =
2362 (z == depth - 1) ? unpadded_row_size : src_padded_row_size;
2363 // TODO(zmo): Ignore flip_y flag for now.
2364 CopyRectToBuffer(
2365 pixels, height, src_unpadded_row_size, src_padded_row_size, false,
2366 buffer_pointer, padded_row_size);
2367 pixels = reinterpret_cast<const int8*>(pixels) +
2368 src_padded_row_size * src_height;
2369 buffer_pointer = reinterpret_cast<int8*>(buffer_pointer) +
2370 padded_row_size * height;
2372 helper_->TexImage3D(
2373 target, level, internalformat, width, height, depth, format, type,
2374 shm_id, shm_offset);
2375 CheckGLError();
2376 return;
2379 // No, so send it using TexSubImage3D.
2380 helper_->TexImage3D(
2381 target, level, internalformat, width, height, depth, format, type,
2382 0, 0);
2383 TexSubImage3DImpl(
2384 target, level, 0, 0, 0, width, height, depth, format, type,
2385 unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &transfer_alloc,
2386 padded_row_size);
2387 CheckGLError();
2390 void GLES2Implementation::TexSubImage2D(
2391 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2392 GLsizei height, GLenum format, GLenum type, const void* pixels) {
2393 GPU_CLIENT_SINGLE_THREAD_CHECK();
2394 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
2395 << GLES2Util::GetStringTextureTarget(target) << ", "
2396 << level << ", "
2397 << xoffset << ", " << yoffset << ", "
2398 << width << ", " << height << ", "
2399 << GLES2Util::GetStringTextureFormat(format) << ", "
2400 << GLES2Util::GetStringPixelType(type) << ", "
2401 << static_cast<const void*>(pixels) << ")");
2403 if (level < 0 || height < 0 || width < 0) {
2404 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
2405 return;
2407 if (height == 0 || width == 0) {
2408 return;
2411 uint32 temp_size;
2412 uint32 unpadded_row_size;
2413 uint32 padded_row_size;
2414 if (!GLES2Util::ComputeImageDataSizes(
2415 width, height, 1, format, type, unpack_alignment_, &temp_size,
2416 &unpadded_row_size, &padded_row_size)) {
2417 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
2418 return;
2421 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2422 if (bound_pixel_unpack_transfer_buffer_id_) {
2423 GLuint offset = ToGLuint(pixels);
2424 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2425 bound_pixel_unpack_transfer_buffer_id_,
2426 "glTexSubImage2D", offset, temp_size);
2427 if (buffer && buffer->shm_id() != -1) {
2428 helper_->TexSubImage2D(
2429 target, level, xoffset, yoffset, width, height, format, type,
2430 buffer->shm_id(), buffer->shm_offset() + offset, false);
2431 buffer->set_last_usage_token(helper_->InsertToken());
2432 CheckGLError();
2434 return;
2437 // compute the advance bytes per row for the src pixels
2438 uint32 src_padded_row_size;
2439 if (unpack_row_length_ > 0) {
2440 if (!GLES2Util::ComputeImagePaddedRowSize(
2441 unpack_row_length_, format, type, unpack_alignment_,
2442 &src_padded_row_size)) {
2443 SetGLError(
2444 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2445 return;
2447 } else {
2448 src_padded_row_size = padded_row_size;
2451 // advance pixels pointer past the skip rows and skip pixels
2452 pixels = reinterpret_cast<const int8*>(pixels) +
2453 unpack_skip_rows_ * src_padded_row_size;
2454 if (unpack_skip_pixels_) {
2455 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2456 pixels = reinterpret_cast<const int8*>(pixels) +
2457 unpack_skip_pixels_ * group_size;
2460 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2461 TexSubImage2DImpl(
2462 target, level, xoffset, yoffset, width, height, format, type,
2463 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
2464 padded_row_size);
2465 CheckGLError();
2468 void GLES2Implementation::TexSubImage3D(
2469 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2470 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2471 const void* pixels) {
2472 GPU_CLIENT_SINGLE_THREAD_CHECK();
2473 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D("
2474 << GLES2Util::GetStringTextureTarget(target) << ", "
2475 << level << ", "
2476 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2477 << width << ", " << height << ", " << depth << ", "
2478 << GLES2Util::GetStringTextureFormat(format) << ", "
2479 << GLES2Util::GetStringPixelType(type) << ", "
2480 << static_cast<const void*>(pixels) << ")");
2482 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2483 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "dimension < 0");
2484 return;
2486 if (height == 0 || width == 0 || depth == 0) {
2487 return;
2490 uint32 temp_size;
2491 uint32 unpadded_row_size;
2492 uint32 padded_row_size;
2493 if (!GLES2Util::ComputeImageDataSizes(
2494 width, height, depth, format, type, unpack_alignment_, &temp_size,
2495 &unpadded_row_size, &padded_row_size)) {
2496 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "size to large");
2497 return;
2500 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2501 if (bound_pixel_unpack_transfer_buffer_id_) {
2502 GLuint offset = ToGLuint(pixels);
2503 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2504 bound_pixel_unpack_transfer_buffer_id_,
2505 "glTexSubImage3D", offset, temp_size);
2506 if (buffer && buffer->shm_id() != -1) {
2507 helper_->TexSubImage3D(
2508 target, level, xoffset, yoffset, zoffset, width, height, depth,
2509 format, type, buffer->shm_id(), buffer->shm_offset() + offset, false);
2510 buffer->set_last_usage_token(helper_->InsertToken());
2511 CheckGLError();
2513 return;
2516 // compute the advance bytes per row for the src pixels
2517 uint32 src_padded_row_size;
2518 if (unpack_row_length_ > 0) {
2519 if (!GLES2Util::ComputeImagePaddedRowSize(
2520 unpack_row_length_, format, type, unpack_alignment_,
2521 &src_padded_row_size)) {
2522 SetGLError(
2523 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2524 return;
2526 } else {
2527 src_padded_row_size = padded_row_size;
2529 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2531 // advance pixels pointer past the skip images/rows/pixels
2532 pixels = reinterpret_cast<const int8*>(pixels) +
2533 unpack_skip_images_ * src_padded_row_size * src_height +
2534 unpack_skip_rows_ * src_padded_row_size;
2535 if (unpack_skip_pixels_) {
2536 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2537 pixels = reinterpret_cast<const int8*>(pixels) +
2538 unpack_skip_pixels_ * group_size;
2541 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2542 TexSubImage3DImpl(
2543 target, level, xoffset, yoffset, zoffset, width, height, depth,
2544 format, type, unpadded_row_size, pixels, src_padded_row_size, GL_FALSE,
2545 &buffer, padded_row_size);
2546 CheckGLError();
2549 static GLint ComputeNumRowsThatFitInBuffer(
2550 uint32 padded_row_size, uint32 unpadded_row_size,
2551 unsigned int size, GLsizei remaining_rows) {
2552 DCHECK_GE(unpadded_row_size, 0u);
2553 if (padded_row_size == 0) {
2554 return 1;
2556 GLint num_rows = size / padded_row_size;
2557 if (num_rows + 1 == remaining_rows &&
2558 size - num_rows * padded_row_size >= unpadded_row_size) {
2559 num_rows++;
2561 return num_rows;
2564 void GLES2Implementation::TexSubImage2DImpl(
2565 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2566 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
2567 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
2568 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
2569 DCHECK(buffer);
2570 DCHECK_GE(level, 0);
2571 DCHECK_GT(height, 0);
2572 DCHECK_GT(width, 0);
2574 const int8* source = reinterpret_cast<const int8*>(pixels);
2575 GLint original_yoffset = yoffset;
2576 // Transfer by rows.
2577 while (height) {
2578 unsigned int desired_size =
2579 buffer_padded_row_size * (height - 1) + unpadded_row_size;
2580 if (!buffer->valid() || buffer->size() == 0) {
2581 buffer->Reset(desired_size);
2582 if (!buffer->valid()) {
2583 return;
2587 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2588 buffer_padded_row_size, unpadded_row_size, buffer->size(), height);
2589 num_rows = std::min(num_rows, height);
2590 CopyRectToBuffer(
2591 source, num_rows, unpadded_row_size, pixels_padded_row_size,
2592 unpack_flip_y_, buffer->address(), buffer_padded_row_size);
2593 GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
2594 helper_->TexSubImage2D(
2595 target, level, xoffset, y, width, num_rows, format, type,
2596 buffer->shm_id(), buffer->offset(), internal);
2597 buffer->Release();
2598 yoffset += num_rows;
2599 source += num_rows * pixels_padded_row_size;
2600 height -= num_rows;
2604 void GLES2Implementation::TexSubImage3DImpl(
2605 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei zoffset,
2606 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2607 uint32 unpadded_row_size, const void* pixels, uint32 pixels_padded_row_size,
2608 GLboolean internal, ScopedTransferBufferPtr* buffer,
2609 uint32 buffer_padded_row_size) {
2610 DCHECK(buffer);
2611 DCHECK_GE(level, 0);
2612 DCHECK_GT(height, 0);
2613 DCHECK_GT(width, 0);
2614 DCHECK_GT(depth, 0);
2615 const int8* source = reinterpret_cast<const int8*>(pixels);
2616 GLsizei total_rows = height * depth;
2617 GLint row_index = 0, depth_index = 0;
2618 while (total_rows) {
2619 // Each time, we either copy one or more images, or copy one or more rows
2620 // within a single image, depending on the buffer size limit.
2621 GLsizei max_rows;
2622 unsigned int desired_size;
2623 if (row_index > 0) {
2624 // We are in the middle of an image. Send the remaining of the image.
2625 max_rows = height - row_index;
2626 if (total_rows <= height) {
2627 // Last image, so last row is unpadded.
2628 desired_size = buffer_padded_row_size * (max_rows - 1) +
2629 unpadded_row_size;
2630 } else {
2631 desired_size = buffer_padded_row_size * max_rows;
2633 } else {
2634 // Send all the remaining data if possible.
2635 max_rows = total_rows;
2636 desired_size =
2637 buffer_padded_row_size * (max_rows - 1) + unpadded_row_size;
2639 if (!buffer->valid() || buffer->size() == 0) {
2640 buffer->Reset(desired_size);
2641 if (!buffer->valid()) {
2642 return;
2645 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2646 buffer_padded_row_size, unpadded_row_size, buffer->size(), total_rows);
2647 num_rows = std::min(num_rows, max_rows);
2648 GLint num_images = num_rows / height;
2649 GLsizei my_height, my_depth;
2650 if (num_images > 0) {
2651 num_rows = num_images * height;
2652 my_height = height;
2653 my_depth = num_images;
2654 } else {
2655 my_height = num_rows;
2656 my_depth = 1;
2659 // TODO(zmo): Ignore flip_y flag for now.
2660 if (num_images > 0) {
2661 int8* buffer_pointer = reinterpret_cast<int8*>(buffer->address());
2662 uint32 src_height =
2663 unpack_image_height_ > 0 ? unpack_image_height_ : height;
2664 uint32 image_size_dst = buffer_padded_row_size * height;
2665 uint32 image_size_src = pixels_padded_row_size * src_height;
2666 for (GLint ii = 0; ii < num_images; ++ii) {
2667 uint32 my_unpadded_row_size;
2668 if (total_rows == num_rows && ii + 1 == num_images)
2669 my_unpadded_row_size = unpadded_row_size;
2670 else
2671 my_unpadded_row_size = pixels_padded_row_size;
2672 CopyRectToBuffer(
2673 source + ii * image_size_src, my_height, my_unpadded_row_size,
2674 pixels_padded_row_size, false, buffer_pointer + ii * image_size_dst,
2675 buffer_padded_row_size);
2677 } else {
2678 uint32 my_unpadded_row_size;
2679 if (total_rows == num_rows)
2680 my_unpadded_row_size = unpadded_row_size;
2681 else
2682 my_unpadded_row_size = pixels_padded_row_size;
2683 CopyRectToBuffer(
2684 source, my_height, my_unpadded_row_size, pixels_padded_row_size,
2685 false, buffer->address(), buffer_padded_row_size);
2687 helper_->TexSubImage3D(
2688 target, level, xoffset, yoffset + row_index, zoffset + depth_index,
2689 width, my_height, my_depth,
2690 format, type, buffer->shm_id(), buffer->offset(), internal);
2691 buffer->Release();
2693 total_rows -= num_rows;
2694 if (total_rows > 0) {
2695 GLint num_image_paddings;
2696 if (num_images > 0) {
2697 DCHECK_EQ(row_index, 0);
2698 depth_index += num_images;
2699 num_image_paddings = num_images;
2700 } else {
2701 row_index = (row_index + my_height) % height;
2702 num_image_paddings = 0;
2703 if (my_height > 0 && row_index == 0) {
2704 depth_index++;
2705 num_image_paddings++;
2708 source += num_rows * pixels_padded_row_size;
2709 if (unpack_image_height_ > height && num_image_paddings > 0) {
2710 source += num_image_paddings * (unpack_image_height_ - height) *
2711 pixels_padded_row_size;
2717 bool GLES2Implementation::GetActiveAttribHelper(
2718 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2719 GLenum* type, char* name) {
2720 // Clear the bucket so if the command fails nothing will be in it.
2721 helper_->SetBucketSize(kResultBucketId, 0);
2722 typedef cmds::GetActiveAttrib::Result Result;
2723 Result* result = GetResultAs<Result*>();
2724 if (!result) {
2725 return false;
2727 // Set as failed so if the command fails we'll recover.
2728 result->success = false;
2729 helper_->GetActiveAttrib(program, index, kResultBucketId,
2730 GetResultShmId(), GetResultShmOffset());
2731 WaitForCmd();
2732 if (result->success) {
2733 if (size) {
2734 *size = result->size;
2736 if (type) {
2737 *type = result->type;
2739 if (length || name) {
2740 std::vector<int8> str;
2741 GetBucketContents(kResultBucketId, &str);
2742 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2743 std::max(static_cast<size_t>(0),
2744 str.size() - 1));
2745 if (length) {
2746 *length = max_size;
2748 if (name && bufsize > 0) {
2749 memcpy(name, &str[0], max_size);
2750 name[max_size] = '\0';
2754 return result->success != 0;
2757 void GLES2Implementation::GetActiveAttrib(
2758 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2759 GLenum* type, char* name) {
2760 GPU_CLIENT_SINGLE_THREAD_CHECK();
2761 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2762 << program << ", " << index << ", " << bufsize << ", "
2763 << static_cast<const void*>(length) << ", "
2764 << static_cast<const void*>(size) << ", "
2765 << static_cast<const void*>(type) << ", "
2766 << static_cast<const void*>(name) << ", ");
2767 if (bufsize < 0) {
2768 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
2769 return;
2771 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2772 bool success = share_group_->program_info_manager()->GetActiveAttrib(
2773 this, program, index, bufsize, length, size, type, name);
2774 if (success) {
2775 if (size) {
2776 GPU_CLIENT_LOG(" size: " << *size);
2778 if (type) {
2779 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2781 if (name) {
2782 GPU_CLIENT_LOG(" name: " << name);
2785 CheckGLError();
2788 bool GLES2Implementation::GetActiveUniformHelper(
2789 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2790 GLenum* type, char* name) {
2791 // Clear the bucket so if the command fails nothing will be in it.
2792 helper_->SetBucketSize(kResultBucketId, 0);
2793 typedef cmds::GetActiveUniform::Result Result;
2794 Result* result = GetResultAs<Result*>();
2795 if (!result) {
2796 return false;
2798 // Set as failed so if the command fails we'll recover.
2799 result->success = false;
2800 helper_->GetActiveUniform(program, index, kResultBucketId,
2801 GetResultShmId(), GetResultShmOffset());
2802 WaitForCmd();
2803 if (result->success) {
2804 if (size) {
2805 *size = result->size;
2807 if (type) {
2808 *type = result->type;
2810 if (length || name) {
2811 std::vector<int8> str;
2812 GetBucketContents(kResultBucketId, &str);
2813 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2814 std::max(static_cast<size_t>(0),
2815 str.size() - 1));
2816 if (length) {
2817 *length = max_size;
2819 if (name && bufsize > 0) {
2820 memcpy(name, &str[0], max_size);
2821 name[max_size] = '\0';
2825 return result->success != 0;
2828 void GLES2Implementation::GetActiveUniform(
2829 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2830 GLenum* type, char* name) {
2831 GPU_CLIENT_SINGLE_THREAD_CHECK();
2832 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2833 << program << ", " << index << ", " << bufsize << ", "
2834 << static_cast<const void*>(length) << ", "
2835 << static_cast<const void*>(size) << ", "
2836 << static_cast<const void*>(type) << ", "
2837 << static_cast<const void*>(name) << ", ");
2838 if (bufsize < 0) {
2839 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2840 return;
2842 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2843 bool success = share_group_->program_info_manager()->GetActiveUniform(
2844 this, program, index, bufsize, length, size, type, name);
2845 if (success) {
2846 if (size) {
2847 GPU_CLIENT_LOG(" size: " << *size);
2849 if (type) {
2850 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2852 if (name) {
2853 GPU_CLIENT_LOG(" name: " << name);
2856 CheckGLError();
2859 bool GLES2Implementation::GetActiveUniformBlockNameHelper(
2860 GLuint program, GLuint index, GLsizei bufsize,
2861 GLsizei* length, char* name) {
2862 DCHECK_LE(0, bufsize);
2863 // Clear the bucket so if the command fails nothing will be in it.
2864 helper_->SetBucketSize(kResultBucketId, 0);
2865 typedef cmds::GetActiveUniformBlockName::Result Result;
2866 Result* result = GetResultAs<Result*>();
2867 if (!result) {
2868 return false;
2870 // Set as failed so if the command fails we'll recover.
2871 *result = 0;
2872 helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
2873 GetResultShmId(), GetResultShmOffset());
2874 WaitForCmd();
2875 if (*result) {
2876 if (bufsize == 0) {
2877 if (length) {
2878 *length = 0;
2880 } else if (length || name) {
2881 std::vector<int8> str;
2882 GetBucketContents(kResultBucketId, &str);
2883 DCHECK_GT(str.size(), 0u);
2884 GLsizei max_size =
2885 std::min(bufsize, static_cast<GLsizei>(str.size())) - 1;
2886 if (length) {
2887 *length = max_size;
2889 if (name) {
2890 memcpy(name, &str[0], max_size);
2891 name[max_size] = '\0';
2895 return *result != 0;
2898 void GLES2Implementation::GetActiveUniformBlockName(
2899 GLuint program, GLuint index, GLsizei bufsize,
2900 GLsizei* length, char* name) {
2901 GPU_CLIENT_SINGLE_THREAD_CHECK();
2902 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
2903 << program << ", " << index << ", " << bufsize << ", "
2904 << static_cast<const void*>(length) << ", "
2905 << static_cast<const void*>(name) << ")");
2906 if (bufsize < 0) {
2907 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformBlockName", "bufsize < 0");
2908 return;
2910 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockName");
2911 bool success =
2912 share_group_->program_info_manager()->GetActiveUniformBlockName(
2913 this, program, index, bufsize, length, name);
2914 if (success) {
2915 if (name) {
2916 GPU_CLIENT_LOG(" name: " << name);
2919 CheckGLError();
2922 bool GLES2Implementation::GetActiveUniformBlockivHelper(
2923 GLuint program, GLuint index, GLenum pname, GLint* params) {
2924 typedef cmds::GetActiveUniformBlockiv::Result Result;
2925 Result* result = GetResultAs<Result*>();
2926 if (!result) {
2927 return false;
2929 result->SetNumResults(0);
2930 helper_->GetActiveUniformBlockiv(
2931 program, index, pname, GetResultShmId(), GetResultShmOffset());
2932 WaitForCmd();
2933 if (result->GetNumResults() > 0) {
2934 if (params) {
2935 result->CopyResult(params);
2937 GPU_CLIENT_LOG_CODE_BLOCK({
2938 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
2939 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2942 return true;
2944 return false;
2947 void GLES2Implementation::GetActiveUniformBlockiv(
2948 GLuint program, GLuint index, GLenum pname, GLint* params) {
2949 GPU_CLIENT_SINGLE_THREAD_CHECK();
2950 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
2951 << program << ", " << index << ", "
2952 << GLES2Util::GetStringUniformBlockParameter(pname) << ", "
2953 << static_cast<const void*>(params) << ")");
2954 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
2955 bool success =
2956 share_group_->program_info_manager()->GetActiveUniformBlockiv(
2957 this, program, index, pname, params);
2958 if (success) {
2959 if (params) {
2960 // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
2961 // be more than one value returned in params.
2962 GPU_CLIENT_LOG(" params: " << params[0]);
2965 CheckGLError();
2968 bool GLES2Implementation::GetActiveUniformsivHelper(
2969 GLuint program, GLsizei count, const GLuint* indices,
2970 GLenum pname, GLint* params) {
2971 typedef cmds::GetActiveUniformsiv::Result Result;
2972 Result* result = GetResultAs<Result*>();
2973 if (!result) {
2974 return false;
2976 result->SetNumResults(0);
2977 base::CheckedNumeric<size_t> bytes = static_cast<size_t>(count);
2978 bytes *= sizeof(GLuint);
2979 if (!bytes.IsValid()) {
2980 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count overflow");
2981 return false;
2983 SetBucketContents(kResultBucketId, indices, bytes.ValueOrDefault(0));
2984 helper_->GetActiveUniformsiv(
2985 program, kResultBucketId, pname, GetResultShmId(), GetResultShmOffset());
2986 WaitForCmd();
2987 bool success = result->GetNumResults() == count;
2988 if (success) {
2989 if (params) {
2990 result->CopyResult(params);
2992 GPU_CLIENT_LOG_CODE_BLOCK({
2993 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
2994 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2998 helper_->SetBucketSize(kResultBucketId, 0);
2999 return success;
3002 void GLES2Implementation::GetActiveUniformsiv(
3003 GLuint program, GLsizei count, const GLuint* indices,
3004 GLenum pname, GLint* params) {
3005 GPU_CLIENT_SINGLE_THREAD_CHECK();
3006 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv("
3007 << program << ", " << count << ", "
3008 << static_cast<const void*>(indices) << ", "
3009 << GLES2Util::GetStringUniformParameter(pname) << ", "
3010 << static_cast<const void*>(params) << ")");
3011 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
3012 if (count < 0) {
3013 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count < 0");
3014 return;
3016 bool success = share_group_->program_info_manager()->GetActiveUniformsiv(
3017 this, program, count, indices, pname, params);
3018 if (success) {
3019 if (params) {
3020 GPU_CLIENT_LOG_CODE_BLOCK({
3021 for (GLsizei ii = 0; ii < count; ++ii) {
3022 GPU_CLIENT_LOG(" " << ii << ": " << params[ii]);
3027 CheckGLError();
3030 void GLES2Implementation::GetAttachedShaders(
3031 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
3032 GPU_CLIENT_SINGLE_THREAD_CHECK();
3033 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
3034 << program << ", " << maxcount << ", "
3035 << static_cast<const void*>(count) << ", "
3036 << static_cast<const void*>(shaders) << ", ");
3037 if (maxcount < 0) {
3038 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
3039 return;
3041 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
3042 typedef cmds::GetAttachedShaders::Result Result;
3043 uint32 size = Result::ComputeSize(maxcount);
3044 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
3045 if (!result) {
3046 return;
3048 result->SetNumResults(0);
3049 helper_->GetAttachedShaders(
3050 program,
3051 transfer_buffer_->GetShmId(),
3052 transfer_buffer_->GetOffset(result),
3053 size);
3054 int32 token = helper_->InsertToken();
3055 WaitForCmd();
3056 if (count) {
3057 *count = result->GetNumResults();
3059 result->CopyResult(shaders);
3060 GPU_CLIENT_LOG_CODE_BLOCK({
3061 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3062 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3065 transfer_buffer_->FreePendingToken(result, token);
3066 CheckGLError();
3069 void GLES2Implementation::GetShaderPrecisionFormat(
3070 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
3071 GPU_CLIENT_SINGLE_THREAD_CHECK();
3072 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
3073 << GLES2Util::GetStringShaderType(shadertype) << ", "
3074 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
3075 << static_cast<const void*>(range) << ", "
3076 << static_cast<const void*>(precision) << ", ");
3077 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
3078 typedef cmds::GetShaderPrecisionFormat::Result Result;
3079 Result* result = GetResultAs<Result*>();
3080 if (!result) {
3081 return;
3084 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
3085 GLStaticState::ShaderPrecisionMap::iterator i =
3086 static_state_.shader_precisions.find(key);
3087 if (i != static_state_.shader_precisions.end()) {
3088 *result = i->second;
3089 } else {
3090 result->success = false;
3091 helper_->GetShaderPrecisionFormat(
3092 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
3093 WaitForCmd();
3094 if (result->success)
3095 static_state_.shader_precisions[key] = *result;
3098 if (result->success) {
3099 if (range) {
3100 range[0] = result->min_range;
3101 range[1] = result->max_range;
3102 GPU_CLIENT_LOG(" min_range: " << range[0]);
3103 GPU_CLIENT_LOG(" min_range: " << range[1]);
3105 if (precision) {
3106 precision[0] = result->precision;
3107 GPU_CLIENT_LOG(" min_range: " << precision[0]);
3110 CheckGLError();
3113 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
3114 const char* result = NULL;
3115 // Clears the bucket so if the command fails nothing will be in it.
3116 helper_->SetBucketSize(kResultBucketId, 0);
3117 helper_->GetString(name, kResultBucketId);
3118 std::string str;
3119 if (GetBucketAsString(kResultBucketId, &str)) {
3120 // Adds extensions implemented on client side only.
3121 switch (name) {
3122 case GL_EXTENSIONS:
3123 str += std::string(str.empty() ? "" : " ") +
3124 "GL_CHROMIUM_flipy "
3125 "GL_EXT_unpack_subimage "
3126 "GL_CHROMIUM_map_sub";
3127 if (capabilities_.image)
3128 str += " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
3129 if (capabilities_.future_sync_points)
3130 str += " GL_CHROMIUM_future_sync_point";
3131 break;
3132 default:
3133 break;
3136 // Because of WebGL the extensions can change. We have to cache each unique
3137 // result since we don't know when the client will stop referring to a
3138 // previous one it queries.
3139 GLStringMap::iterator it = gl_strings_.find(name);
3140 if (it == gl_strings_.end()) {
3141 std::set<std::string> strings;
3142 std::pair<GLStringMap::iterator, bool> insert_result =
3143 gl_strings_.insert(std::make_pair(name, strings));
3144 DCHECK(insert_result.second);
3145 it = insert_result.first;
3147 std::set<std::string>& string_set = it->second;
3148 std::set<std::string>::const_iterator sit = string_set.find(str);
3149 if (sit != string_set.end()) {
3150 result = sit->c_str();
3151 } else {
3152 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
3153 string_set.insert(str);
3154 DCHECK(insert_result.second);
3155 result = insert_result.first->c_str();
3158 return reinterpret_cast<const GLubyte*>(result);
3161 const GLubyte* GLES2Implementation::GetString(GLenum name) {
3162 GPU_CLIENT_SINGLE_THREAD_CHECK();
3163 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
3164 << GLES2Util::GetStringStringType(name) << ")");
3165 TRACE_EVENT0("gpu", "GLES2::GetString");
3166 const GLubyte* result = GetStringHelper(name);
3167 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
3168 CheckGLError();
3169 return result;
3172 bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
3173 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3174 GLenum* type, char* name) {
3175 // Clear the bucket so if the command fails nothing will be in it.
3176 helper_->SetBucketSize(kResultBucketId, 0);
3177 typedef cmds::GetTransformFeedbackVarying::Result Result;
3178 Result* result = GetResultAs<Result*>();
3179 if (!result) {
3180 return false;
3182 // Set as failed so if the command fails we'll recover.
3183 result->success = false;
3184 helper_->GetTransformFeedbackVarying(
3185 program, index, kResultBucketId, GetResultShmId(), GetResultShmOffset());
3186 WaitForCmd();
3187 if (result->success) {
3188 if (size) {
3189 *size = result->size;
3191 if (type) {
3192 *type = result->type;
3194 if (length || name) {
3195 std::vector<int8> str;
3196 GetBucketContents(kResultBucketId, &str);
3197 GLsizei max_size = std::min(bufsize, static_cast<GLsizei>(str.size()));
3198 if (max_size > 0) {
3199 --max_size;
3201 if (length) {
3202 *length = max_size;
3204 if (name) {
3205 if (max_size > 0) {
3206 memcpy(name, &str[0], max_size);
3207 name[max_size] = '\0';
3208 } else if (bufsize > 0) {
3209 name[0] = '\0';
3214 return result->success != 0;
3217 void GLES2Implementation::GetTransformFeedbackVarying(
3218 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3219 GLenum* type, char* name) {
3220 GPU_CLIENT_SINGLE_THREAD_CHECK();
3221 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
3222 << program << ", " << index << ", " << bufsize << ", "
3223 << static_cast<const void*>(length) << ", "
3224 << static_cast<const void*>(size) << ", "
3225 << static_cast<const void*>(type) << ", "
3226 << static_cast<const void*>(name) << ", ");
3227 if (bufsize < 0) {
3228 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVarying",
3229 "bufsize < 0");
3230 return;
3232 TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
3233 bool success =
3234 share_group_->program_info_manager()->GetTransformFeedbackVarying(
3235 this, program, index, bufsize, length, size, type, name);
3236 if (success) {
3237 if (size) {
3238 GPU_CLIENT_LOG(" size: " << *size);
3240 if (type) {
3241 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
3243 if (name) {
3244 GPU_CLIENT_LOG(" name: " << name);
3247 CheckGLError();
3250 void GLES2Implementation::GetUniformfv(
3251 GLuint program, GLint location, GLfloat* params) {
3252 GPU_CLIENT_SINGLE_THREAD_CHECK();
3253 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
3254 << program << ", " << location << ", "
3255 << static_cast<const void*>(params) << ")");
3256 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
3257 typedef cmds::GetUniformfv::Result Result;
3258 Result* result = GetResultAs<Result*>();
3259 if (!result) {
3260 return;
3262 result->SetNumResults(0);
3263 helper_->GetUniformfv(
3264 program, location, GetResultShmId(), GetResultShmOffset());
3265 WaitForCmd();
3266 result->CopyResult(params);
3267 GPU_CLIENT_LOG_CODE_BLOCK({
3268 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3269 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3272 CheckGLError();
3275 void GLES2Implementation::GetUniformiv(
3276 GLuint program, GLint location, GLint* params) {
3277 GPU_CLIENT_SINGLE_THREAD_CHECK();
3278 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
3279 << program << ", " << location << ", "
3280 << static_cast<const void*>(params) << ")");
3281 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
3282 typedef cmds::GetUniformiv::Result Result;
3283 Result* result = GetResultAs<Result*>();
3284 if (!result) {
3285 return;
3287 result->SetNumResults(0);
3288 helper_->GetUniformiv(
3289 program, location, GetResultShmId(), GetResultShmOffset());
3290 WaitForCmd();
3291 GetResultAs<cmds::GetUniformiv::Result*>()->CopyResult(params);
3292 GPU_CLIENT_LOG_CODE_BLOCK({
3293 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3294 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3297 CheckGLError();
3300 void GLES2Implementation::GetUniformuiv(
3301 GLuint program, GLint location, GLuint* params) {
3302 GPU_CLIENT_SINGLE_THREAD_CHECK();
3303 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformuiv("
3304 << program << ", " << location << ", "
3305 << static_cast<const void*>(params) << ")");
3306 TRACE_EVENT0("gpu", "GLES2::GetUniformuiv");
3307 typedef cmds::GetUniformuiv::Result Result;
3308 Result* result = GetResultAs<Result*>();
3309 if (!result) {
3310 return;
3312 result->SetNumResults(0);
3313 helper_->GetUniformuiv(
3314 program, location, GetResultShmId(), GetResultShmOffset());
3315 WaitForCmd();
3316 GetResultAs<cmds::GetUniformuiv::Result*>()->CopyResult(params);
3317 GPU_CLIENT_LOG_CODE_BLOCK({
3318 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3319 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3322 CheckGLError();
3325 void GLES2Implementation::ReadPixels(
3326 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
3327 GLenum type, void* pixels) {
3328 GPU_CLIENT_SINGLE_THREAD_CHECK();
3329 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
3330 << xoffset << ", " << yoffset << ", "
3331 << width << ", " << height << ", "
3332 << GLES2Util::GetStringReadPixelFormat(format) << ", "
3333 << GLES2Util::GetStringPixelType(type) << ", "
3334 << static_cast<const void*>(pixels) << ")");
3335 if (width < 0 || height < 0) {
3336 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
3337 return;
3339 if (width == 0 || height == 0) {
3340 return;
3343 // glReadPixel pads the size of each row of pixels by an amount specified by
3344 // glPixelStorei. So, we have to take that into account both in the fact that
3345 // the pixels returned from the ReadPixel command will include that padding
3346 // and that when we copy the results to the user's buffer we need to not
3347 // write those padding bytes but leave them as they are.
3349 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
3350 typedef cmds::ReadPixels::Result Result;
3352 int8* dest = reinterpret_cast<int8*>(pixels);
3353 uint32 temp_size;
3354 uint32 unpadded_row_size;
3355 uint32 padded_row_size;
3356 if (!GLES2Util::ComputeImageDataSizes(
3357 width, 2, 1, format, type, pack_alignment_, &temp_size,
3358 &unpadded_row_size, &padded_row_size)) {
3359 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
3360 return;
3363 if (bound_pixel_pack_transfer_buffer_id_) {
3364 GLuint offset = ToGLuint(pixels);
3365 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3366 bound_pixel_pack_transfer_buffer_id_,
3367 "glReadPixels", offset, padded_row_size * height);
3368 if (buffer && buffer->shm_id() != -1) {
3369 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
3370 buffer->shm_id(), buffer->shm_offset(),
3371 0, 0, true);
3372 CheckGLError();
3374 return;
3377 if (!pixels) {
3378 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
3379 return;
3382 // Transfer by rows.
3383 // The max rows we can transfer.
3384 while (height) {
3385 GLsizei desired_size = padded_row_size * (height - 1) + unpadded_row_size;
3386 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
3387 if (!buffer.valid()) {
3388 return;
3390 GLint num_rows = ComputeNumRowsThatFitInBuffer(
3391 padded_row_size, unpadded_row_size, buffer.size(), height);
3392 num_rows = std::min(num_rows, height);
3393 // NOTE: We must look up the address of the result area AFTER allocation
3394 // of the transfer buffer since the transfer buffer may be reallocated.
3395 Result* result = GetResultAs<Result*>();
3396 if (!result) {
3397 return;
3399 *result = 0; // mark as failed.
3400 helper_->ReadPixels(
3401 xoffset, yoffset, width, num_rows, format, type,
3402 buffer.shm_id(), buffer.offset(),
3403 GetResultShmId(), GetResultShmOffset(),
3404 false);
3405 WaitForCmd();
3406 if (*result != 0) {
3407 // when doing a y-flip we have to iterate through top-to-bottom chunks
3408 // of the dst. The service side handles reversing the rows within a
3409 // chunk.
3410 int8* rows_dst;
3411 if (pack_reverse_row_order_) {
3412 rows_dst = dest + (height - num_rows) * padded_row_size;
3413 } else {
3414 rows_dst = dest;
3416 // We have to copy 1 row at a time to avoid writing pad bytes.
3417 const int8* src = static_cast<const int8*>(buffer.address());
3418 for (GLint yy = 0; yy < num_rows; ++yy) {
3419 memcpy(rows_dst, src, unpadded_row_size);
3420 rows_dst += padded_row_size;
3421 src += padded_row_size;
3423 if (!pack_reverse_row_order_) {
3424 dest = rows_dst;
3427 // If it was not marked as successful exit.
3428 if (*result == 0) {
3429 return;
3431 yoffset += num_rows;
3432 height -= num_rows;
3434 CheckGLError();
3437 void GLES2Implementation::ActiveTexture(GLenum texture) {
3438 GPU_CLIENT_SINGLE_THREAD_CHECK();
3439 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
3440 << GLES2Util::GetStringEnum(texture) << ")");
3441 GLuint texture_index = texture - GL_TEXTURE0;
3442 if (texture_index >=
3443 static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
3444 SetGLErrorInvalidEnum(
3445 "glActiveTexture", texture, "texture");
3446 return;
3449 active_texture_unit_ = texture_index;
3450 helper_->ActiveTexture(texture);
3451 CheckGLError();
3454 void GLES2Implementation::GenBuffersHelper(
3455 GLsizei /* n */, const GLuint* /* buffers */) {
3458 void GLES2Implementation::GenFramebuffersHelper(
3459 GLsizei /* n */, const GLuint* /* framebuffers */) {
3462 void GLES2Implementation::GenRenderbuffersHelper(
3463 GLsizei /* n */, const GLuint* /* renderbuffers */) {
3466 void GLES2Implementation::GenTexturesHelper(
3467 GLsizei /* n */, const GLuint* /* textures */) {
3470 void GLES2Implementation::GenVertexArraysOESHelper(
3471 GLsizei n, const GLuint* arrays) {
3472 vertex_array_object_manager_->GenVertexArrays(n, arrays);
3475 void GLES2Implementation::GenQueriesEXTHelper(
3476 GLsizei /* n */, const GLuint* /* queries */) {
3479 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
3480 GLsizei /* n */,
3481 const GLuint* /* valuebuffers */) {
3484 void GLES2Implementation::GenSamplersHelper(
3485 GLsizei /* n */, const GLuint* /* samplers */) {
3488 void GLES2Implementation::GenTransformFeedbacksHelper(
3489 GLsizei /* n */, const GLuint* /* transformfeedbacks */) {
3492 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
3493 // generates a new resource. On newer versions of OpenGL they don't. The code
3494 // related to binding below will need to change if we switch to the new OpenGL
3495 // model. Specifically it assumes a bind will succeed which is always true in
3496 // the old model but possibly not true in the new model if another context has
3497 // deleted the resource.
3499 // NOTE #2: There is a bug in some BindXXXHelpers, that IDs might be marked as
3500 // used even when Bind has failed. However, the bug is minor compared to the
3501 // overhead & duplicated checking in client side.
3503 void GLES2Implementation::BindBufferHelper(
3504 GLenum target, GLuint buffer_id) {
3505 // TODO(gman): See note #1 above.
3506 bool changed = false;
3507 switch (target) {
3508 case GL_ARRAY_BUFFER:
3509 if (bound_array_buffer_ != buffer_id) {
3510 bound_array_buffer_ = buffer_id;
3511 changed = true;
3513 break;
3514 case GL_COPY_READ_BUFFER:
3515 if (bound_copy_read_buffer_ != buffer_id) {
3516 bound_copy_read_buffer_ = buffer_id;
3517 changed = true;
3519 break;
3520 case GL_COPY_WRITE_BUFFER:
3521 if (bound_copy_write_buffer_ != buffer_id) {
3522 bound_copy_write_buffer_ = buffer_id;
3523 changed = true;
3525 break;
3526 case GL_ELEMENT_ARRAY_BUFFER:
3527 changed = vertex_array_object_manager_->BindElementArray(buffer_id);
3528 break;
3529 case GL_PIXEL_PACK_BUFFER:
3530 if (bound_pixel_pack_buffer_ != buffer_id) {
3531 bound_pixel_pack_buffer_ = buffer_id;
3532 changed = true;
3534 break;
3535 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3536 bound_pixel_pack_transfer_buffer_id_ = buffer_id;
3537 break;
3538 case GL_PIXEL_UNPACK_BUFFER:
3539 if (bound_pixel_unpack_buffer_ != buffer_id) {
3540 bound_pixel_unpack_buffer_ = buffer_id;
3541 changed = true;
3543 break;
3544 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3545 bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
3546 break;
3547 case GL_TRANSFORM_FEEDBACK_BUFFER:
3548 if (bound_transform_feedback_buffer_ != buffer_id) {
3549 bound_transform_feedback_buffer_ = buffer_id;
3550 changed = true;
3552 break;
3553 case GL_UNIFORM_BUFFER:
3554 if (bound_uniform_buffer_ != buffer_id) {
3555 bound_uniform_buffer_ = buffer_id;
3556 changed = true;
3558 break;
3559 default:
3560 changed = true;
3561 break;
3563 // TODO(gman): See note #2 above.
3564 if (changed) {
3565 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3566 this, target, buffer_id, &GLES2Implementation::BindBufferStub);
3570 void GLES2Implementation::BindBufferStub(GLenum target, GLuint buffer) {
3571 helper_->BindBuffer(target, buffer);
3572 if (share_group_->bind_generates_resource())
3573 helper_->CommandBufferHelper::OrderingBarrier();
3576 void GLES2Implementation::BindBufferBaseHelper(
3577 GLenum target, GLuint index, GLuint buffer_id) {
3578 // TODO(zmo): See note #1 above.
3579 // TODO(zmo): See note #2 above.
3580 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3581 this, target, index, buffer_id, &GLES2Implementation::BindBufferBaseStub);
3584 void GLES2Implementation::BindBufferBaseStub(
3585 GLenum target, GLuint index, GLuint buffer) {
3586 helper_->BindBufferBase(target, index, buffer);
3587 if (share_group_->bind_generates_resource())
3588 helper_->CommandBufferHelper::Flush();
3591 void GLES2Implementation::BindBufferRangeHelper(
3592 GLenum target, GLuint index, GLuint buffer_id,
3593 GLintptr offset, GLsizeiptr size) {
3594 // TODO(zmo): See note #1 above.
3595 // TODO(zmo): See note #2 above.
3596 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3597 this, target, index, buffer_id, offset, size,
3598 &GLES2Implementation::BindBufferRangeStub);
3601 void GLES2Implementation::BindBufferRangeStub(
3602 GLenum target, GLuint index, GLuint buffer,
3603 GLintptr offset, GLsizeiptr size) {
3604 helper_->BindBufferRange(target, index, buffer, offset, size);
3605 if (share_group_->bind_generates_resource())
3606 helper_->CommandBufferHelper::Flush();
3609 void GLES2Implementation::BindFramebufferHelper(
3610 GLenum target, GLuint framebuffer) {
3611 // TODO(gman): See note #1 above.
3612 bool changed = false;
3613 switch (target) {
3614 case GL_FRAMEBUFFER:
3615 if (bound_framebuffer_ != framebuffer ||
3616 bound_read_framebuffer_ != framebuffer) {
3617 bound_framebuffer_ = framebuffer;
3618 bound_read_framebuffer_ = framebuffer;
3619 changed = true;
3621 break;
3622 case GL_READ_FRAMEBUFFER:
3623 if (!IsChromiumFramebufferMultisampleAvailable()) {
3624 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3625 return;
3627 if (bound_read_framebuffer_ != framebuffer) {
3628 bound_read_framebuffer_ = framebuffer;
3629 changed = true;
3631 break;
3632 case GL_DRAW_FRAMEBUFFER:
3633 if (!IsChromiumFramebufferMultisampleAvailable()) {
3634 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3635 return;
3637 if (bound_framebuffer_ != framebuffer) {
3638 bound_framebuffer_ = framebuffer;
3639 changed = true;
3641 break;
3642 default:
3643 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3644 return;
3647 if (changed) {
3648 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(
3649 this, target, framebuffer, &GLES2Implementation::BindFramebufferStub);
3653 void GLES2Implementation::BindFramebufferStub(GLenum target,
3654 GLuint framebuffer) {
3655 helper_->BindFramebuffer(target, framebuffer);
3656 if (share_group_->bind_generates_resource())
3657 helper_->CommandBufferHelper::OrderingBarrier();
3660 void GLES2Implementation::BindRenderbufferHelper(
3661 GLenum target, GLuint renderbuffer) {
3662 // TODO(gman): See note #1 above.
3663 bool changed = false;
3664 switch (target) {
3665 case GL_RENDERBUFFER:
3666 if (bound_renderbuffer_ != renderbuffer) {
3667 bound_renderbuffer_ = renderbuffer;
3668 changed = true;
3670 break;
3671 default:
3672 changed = true;
3673 break;
3675 // TODO(zmo): See note #2 above.
3676 if (changed) {
3677 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(
3678 this, target, renderbuffer,
3679 &GLES2Implementation::BindRenderbufferStub);
3683 void GLES2Implementation::BindRenderbufferStub(GLenum target,
3684 GLuint renderbuffer) {
3685 helper_->BindRenderbuffer(target, renderbuffer);
3686 if (share_group_->bind_generates_resource())
3687 helper_->CommandBufferHelper::OrderingBarrier();
3690 void GLES2Implementation::BindSamplerHelper(GLuint unit,
3691 GLuint sampler) {
3692 helper_->BindSampler(unit, sampler);
3695 void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
3696 // TODO(gman): See note #1 above.
3697 // TODO(gman): Change this to false once we figure out why it's failing
3698 // on daisy.
3699 bool changed = true;
3700 TextureUnit& unit = texture_units_[active_texture_unit_];
3701 switch (target) {
3702 case GL_TEXTURE_2D:
3703 if (unit.bound_texture_2d != texture) {
3704 unit.bound_texture_2d = texture;
3705 changed = true;
3707 break;
3708 case GL_TEXTURE_CUBE_MAP:
3709 if (unit.bound_texture_cube_map != texture) {
3710 unit.bound_texture_cube_map = texture;
3711 changed = true;
3713 break;
3714 case GL_TEXTURE_EXTERNAL_OES:
3715 if (unit.bound_texture_external_oes != texture) {
3716 unit.bound_texture_external_oes = texture;
3717 changed = true;
3719 break;
3720 default:
3721 changed = true;
3722 break;
3724 // TODO(gman): See note #2 above.
3725 if (changed) {
3726 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(
3727 this, target, texture, &GLES2Implementation::BindTextureStub);
3731 void GLES2Implementation::BindTextureStub(GLenum target, GLuint texture) {
3732 helper_->BindTexture(target, texture);
3733 if (share_group_->bind_generates_resource())
3734 helper_->CommandBufferHelper::OrderingBarrier();
3737 void GLES2Implementation::BindTransformFeedbackHelper(
3738 GLenum target, GLuint transformfeedback) {
3739 helper_->BindTransformFeedback(target, transformfeedback);
3742 void GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
3743 bool changed = false;
3744 if (vertex_array_object_manager_->BindVertexArray(array, &changed)) {
3745 if (changed) {
3746 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
3747 // because unlike other resources VertexArrayObject ids must
3748 // be generated by GenVertexArrays. A random id to Bind will not
3749 // generate a new object.
3750 helper_->BindVertexArrayOES(array);
3752 } else {
3753 SetGLError(
3754 GL_INVALID_OPERATION, "glBindVertexArrayOES",
3755 "id was not generated with glGenVertexArrayOES");
3759 void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
3760 GLuint valuebuffer) {
3761 bool changed = false;
3762 switch (target) {
3763 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
3764 if (bound_valuebuffer_ != valuebuffer) {
3765 bound_valuebuffer_ = valuebuffer;
3766 changed = true;
3768 break;
3769 default:
3770 changed = true;
3771 break;
3773 // TODO(gman): See note #2 above.
3774 if (changed) {
3775 GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(
3776 this, target, valuebuffer,
3777 &GLES2Implementation::BindValuebufferCHROMIUMStub);
3781 void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target,
3782 GLuint valuebuffer) {
3783 helper_->BindValuebufferCHROMIUM(target, valuebuffer);
3784 if (share_group_->bind_generates_resource())
3785 helper_->CommandBufferHelper::OrderingBarrier();
3788 void GLES2Implementation::UseProgramHelper(GLuint program) {
3789 if (current_program_ != program) {
3790 current_program_ = program;
3791 helper_->UseProgram(program);
3795 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
3796 return vertex_array_object_manager_->IsReservedId(id);
3799 void GLES2Implementation::DeleteBuffersHelper(
3800 GLsizei n, const GLuint* buffers) {
3801 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
3802 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
3803 SetGLError(
3804 GL_INVALID_VALUE,
3805 "glDeleteBuffers", "id not created by this context.");
3806 return;
3808 for (GLsizei ii = 0; ii < n; ++ii) {
3809 if (buffers[ii] == bound_array_buffer_) {
3810 bound_array_buffer_ = 0;
3812 if (buffers[ii] == bound_copy_read_buffer_) {
3813 bound_copy_read_buffer_ = 0;
3815 if (buffers[ii] == bound_copy_write_buffer_) {
3816 bound_copy_write_buffer_ = 0;
3818 if (buffers[ii] == bound_pixel_pack_buffer_) {
3819 bound_pixel_pack_buffer_ = 0;
3821 if (buffers[ii] == bound_pixel_unpack_buffer_) {
3822 bound_pixel_unpack_buffer_ = 0;
3824 if (buffers[ii] == bound_transform_feedback_buffer_) {
3825 bound_transform_feedback_buffer_ = 0;
3827 if (buffers[ii] == bound_uniform_buffer_) {
3828 bound_uniform_buffer_ = 0;
3830 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
3832 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
3833 if (buffer)
3834 RemoveTransferBuffer(buffer);
3836 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
3837 bound_pixel_unpack_transfer_buffer_id_ = 0;
3840 RemoveMappedBufferRangeById(buffers[ii]);
3844 void GLES2Implementation::DeleteBuffersStub(
3845 GLsizei n, const GLuint* buffers) {
3846 helper_->DeleteBuffersImmediate(n, buffers);
3850 void GLES2Implementation::DeleteFramebuffersHelper(
3851 GLsizei n, const GLuint* framebuffers) {
3852 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
3853 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
3854 SetGLError(
3855 GL_INVALID_VALUE,
3856 "glDeleteFramebuffers", "id not created by this context.");
3857 return;
3859 for (GLsizei ii = 0; ii < n; ++ii) {
3860 if (framebuffers[ii] == bound_framebuffer_) {
3861 bound_framebuffer_ = 0;
3863 if (framebuffers[ii] == bound_read_framebuffer_) {
3864 bound_read_framebuffer_ = 0;
3869 void GLES2Implementation::DeleteFramebuffersStub(
3870 GLsizei n, const GLuint* framebuffers) {
3871 helper_->DeleteFramebuffersImmediate(n, framebuffers);
3874 void GLES2Implementation::DeleteRenderbuffersHelper(
3875 GLsizei n, const GLuint* renderbuffers) {
3876 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
3877 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
3878 SetGLError(
3879 GL_INVALID_VALUE,
3880 "glDeleteRenderbuffers", "id not created by this context.");
3881 return;
3883 for (GLsizei ii = 0; ii < n; ++ii) {
3884 if (renderbuffers[ii] == bound_renderbuffer_) {
3885 bound_renderbuffer_ = 0;
3890 void GLES2Implementation::DeleteRenderbuffersStub(
3891 GLsizei n, const GLuint* renderbuffers) {
3892 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
3895 void GLES2Implementation::DeleteTexturesHelper(
3896 GLsizei n, const GLuint* textures) {
3897 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
3898 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
3899 SetGLError(
3900 GL_INVALID_VALUE,
3901 "glDeleteTextures", "id not created by this context.");
3902 return;
3904 for (GLsizei ii = 0; ii < n; ++ii) {
3905 for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
3906 ++tt) {
3907 TextureUnit& unit = texture_units_[tt];
3908 if (textures[ii] == unit.bound_texture_2d) {
3909 unit.bound_texture_2d = 0;
3911 if (textures[ii] == unit.bound_texture_cube_map) {
3912 unit.bound_texture_cube_map = 0;
3914 if (textures[ii] == unit.bound_texture_external_oes) {
3915 unit.bound_texture_external_oes = 0;
3921 void GLES2Implementation::DeleteTexturesStub(GLsizei n,
3922 const GLuint* textures) {
3923 helper_->DeleteTexturesImmediate(n, textures);
3926 void GLES2Implementation::DeleteVertexArraysOESHelper(
3927 GLsizei n, const GLuint* arrays) {
3928 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
3929 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
3930 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
3931 SetGLError(
3932 GL_INVALID_VALUE,
3933 "glDeleteVertexArraysOES", "id not created by this context.");
3934 return;
3938 void GLES2Implementation::DeleteVertexArraysOESStub(
3939 GLsizei n, const GLuint* arrays) {
3940 helper_->DeleteVertexArraysOESImmediate(n, arrays);
3943 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
3944 GLsizei n,
3945 const GLuint* valuebuffers) {
3946 if (!GetIdHandler(id_namespaces::kValuebuffers)
3947 ->FreeIds(this, n, valuebuffers,
3948 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
3949 SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
3950 "id not created by this context.");
3951 return;
3953 for (GLsizei ii = 0; ii < n; ++ii) {
3954 if (valuebuffers[ii] == bound_valuebuffer_) {
3955 bound_valuebuffer_ = 0;
3960 void GLES2Implementation::DeleteSamplersStub(
3961 GLsizei n, const GLuint* samplers) {
3962 helper_->DeleteSamplersImmediate(n, samplers);
3965 void GLES2Implementation::DeleteSamplersHelper(
3966 GLsizei n, const GLuint* samplers) {
3967 if (!GetIdHandler(id_namespaces::kSamplers)->FreeIds(
3968 this, n, samplers, &GLES2Implementation::DeleteSamplersStub)) {
3969 SetGLError(
3970 GL_INVALID_VALUE,
3971 "glDeleteSamplers", "id not created by this context.");
3972 return;
3976 void GLES2Implementation::DeleteTransformFeedbacksStub(
3977 GLsizei n, const GLuint* transformfeedbacks) {
3978 helper_->DeleteTransformFeedbacksImmediate(n, transformfeedbacks);
3981 void GLES2Implementation::DeleteTransformFeedbacksHelper(
3982 GLsizei n, const GLuint* transformfeedbacks) {
3983 if (!GetIdHandler(id_namespaces::kTransformFeedbacks)->FreeIds(
3984 this, n, transformfeedbacks,
3985 &GLES2Implementation::DeleteTransformFeedbacksStub)) {
3986 SetGLError(
3987 GL_INVALID_VALUE,
3988 "glDeleteTransformFeedbacks", "id not created by this context.");
3989 return;
3993 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
3994 GLsizei n,
3995 const GLuint* valuebuffers) {
3996 helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
3999 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
4000 GPU_CLIENT_SINGLE_THREAD_CHECK();
4001 GPU_CLIENT_LOG(
4002 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
4003 vertex_array_object_manager_->SetAttribEnable(index, false);
4004 helper_->DisableVertexAttribArray(index);
4005 CheckGLError();
4008 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
4009 GPU_CLIENT_SINGLE_THREAD_CHECK();
4010 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
4011 << index << ")");
4012 vertex_array_object_manager_->SetAttribEnable(index, true);
4013 helper_->EnableVertexAttribArray(index);
4014 CheckGLError();
4017 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
4018 GPU_CLIENT_SINGLE_THREAD_CHECK();
4019 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
4020 << GLES2Util::GetStringDrawMode(mode) << ", "
4021 << first << ", " << count << ")");
4022 if (count < 0) {
4023 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
4024 return;
4026 bool simulated = false;
4027 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
4028 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
4029 return;
4031 helper_->DrawArrays(mode, first, count);
4032 RestoreArrayBuffer(simulated);
4033 CheckGLError();
4036 void GLES2Implementation::GetVertexAttribfv(
4037 GLuint index, GLenum pname, GLfloat* params) {
4038 GPU_CLIENT_SINGLE_THREAD_CHECK();
4039 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
4040 << index << ", "
4041 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4042 << static_cast<const void*>(params) << ")");
4043 uint32 value = 0;
4044 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4045 *params = static_cast<GLfloat>(value);
4046 return;
4048 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
4049 typedef cmds::GetVertexAttribfv::Result Result;
4050 Result* result = GetResultAs<Result*>();
4051 if (!result) {
4052 return;
4054 result->SetNumResults(0);
4055 helper_->GetVertexAttribfv(
4056 index, pname, GetResultShmId(), GetResultShmOffset());
4057 WaitForCmd();
4058 result->CopyResult(params);
4059 GPU_CLIENT_LOG_CODE_BLOCK({
4060 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4061 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4064 CheckGLError();
4067 void GLES2Implementation::GetVertexAttribiv(
4068 GLuint index, GLenum pname, GLint* params) {
4069 GPU_CLIENT_SINGLE_THREAD_CHECK();
4070 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
4071 << index << ", "
4072 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4073 << static_cast<const void*>(params) << ")");
4074 uint32 value = 0;
4075 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4076 *params = static_cast<GLint>(value);
4077 return;
4079 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
4080 typedef cmds::GetVertexAttribiv::Result Result;
4081 Result* result = GetResultAs<Result*>();
4082 if (!result) {
4083 return;
4085 result->SetNumResults(0);
4086 helper_->GetVertexAttribiv(
4087 index, pname, GetResultShmId(), GetResultShmOffset());
4088 WaitForCmd();
4089 result->CopyResult(params);
4090 GPU_CLIENT_LOG_CODE_BLOCK({
4091 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4092 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4095 CheckGLError();
4098 void GLES2Implementation::GetVertexAttribIiv(
4099 GLuint index, GLenum pname, GLint* params) {
4100 GPU_CLIENT_SINGLE_THREAD_CHECK();
4101 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIiv("
4102 << index << ", "
4103 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4104 << static_cast<const void*>(params) << ")");
4105 uint32 value = 0;
4106 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4107 *params = static_cast<GLint>(value);
4108 return;
4110 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIiv");
4111 typedef cmds::GetVertexAttribiv::Result Result;
4112 Result* result = GetResultAs<Result*>();
4113 if (!result) {
4114 return;
4116 result->SetNumResults(0);
4117 helper_->GetVertexAttribIiv(
4118 index, pname, GetResultShmId(), GetResultShmOffset());
4119 WaitForCmd();
4120 result->CopyResult(params);
4121 GPU_CLIENT_LOG_CODE_BLOCK({
4122 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4123 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4126 CheckGLError();
4129 void GLES2Implementation::GetVertexAttribIuiv(
4130 GLuint index, GLenum pname, GLuint* params) {
4131 GPU_CLIENT_SINGLE_THREAD_CHECK();
4132 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIuiv("
4133 << index << ", "
4134 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4135 << static_cast<const void*>(params) << ")");
4136 uint32 value = 0;
4137 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4138 *params = static_cast<GLuint>(value);
4139 return;
4141 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIuiv");
4142 typedef cmds::GetVertexAttribiv::Result Result;
4143 Result* result = GetResultAs<Result*>();
4144 if (!result) {
4145 return;
4147 result->SetNumResults(0);
4148 helper_->GetVertexAttribIuiv(
4149 index, pname, GetResultShmId(), GetResultShmOffset());
4150 WaitForCmd();
4151 result->CopyResult(params);
4152 GPU_CLIENT_LOG_CODE_BLOCK({
4153 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4154 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4157 CheckGLError();
4160 GLenum GLES2Implementation::GetGraphicsResetStatusKHR() {
4161 GPU_CLIENT_SINGLE_THREAD_CHECK();
4162 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetGraphicsResetStatusKHR()");
4163 // If we can't make command buffers then the context is lost.
4164 if (gpu_control_->IsGpuChannelLost())
4165 return GL_UNKNOWN_CONTEXT_RESET_KHR;
4166 // Otherwise, check the command buffer if it is lost.
4167 if (helper_->IsContextLost()) {
4168 // TODO(danakj): We could GetLastState() off the CommandBuffer and return
4169 // the actual reason here if we cared to.
4170 return GL_UNKNOWN_CONTEXT_RESET_KHR;
4172 return GL_NO_ERROR;
4175 void GLES2Implementation::Swap() {
4176 SwapBuffers();
4179 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
4180 PostSubBufferCHROMIUM(
4181 sub_buffer.x(), sub_buffer.y(), sub_buffer.width(), sub_buffer.height());
4184 static GLenum GetGLESOverlayTransform(gfx::OverlayTransform plane_transform) {
4185 switch (plane_transform) {
4186 case gfx::OVERLAY_TRANSFORM_INVALID:
4187 break;
4188 case gfx::OVERLAY_TRANSFORM_NONE:
4189 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
4190 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
4191 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM;
4192 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
4193 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM;
4194 case gfx::OVERLAY_TRANSFORM_ROTATE_90:
4195 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM;
4196 case gfx::OVERLAY_TRANSFORM_ROTATE_180:
4197 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM;
4198 case gfx::OVERLAY_TRANSFORM_ROTATE_270:
4199 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM;
4201 NOTREACHED();
4202 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
4205 void GLES2Implementation::ScheduleOverlayPlane(
4206 int plane_z_order,
4207 gfx::OverlayTransform plane_transform,
4208 unsigned overlay_texture_id,
4209 const gfx::Rect& display_bounds,
4210 const gfx::RectF& uv_rect) {
4211 ScheduleOverlayPlaneCHROMIUM(plane_z_order,
4212 GetGLESOverlayTransform(plane_transform),
4213 overlay_texture_id,
4214 display_bounds.x(),
4215 display_bounds.y(),
4216 display_bounds.width(),
4217 display_bounds.height(),
4218 uv_rect.x(),
4219 uv_rect.y(),
4220 uv_rect.width(),
4221 uv_rect.height());
4224 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
4225 const char* feature) {
4226 GPU_CLIENT_SINGLE_THREAD_CHECK();
4227 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
4228 << feature << ")");
4229 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
4230 typedef cmds::EnableFeatureCHROMIUM::Result Result;
4231 Result* result = GetResultAs<Result*>();
4232 if (!result) {
4233 return false;
4235 *result = 0;
4236 SetBucketAsCString(kResultBucketId, feature);
4237 helper_->EnableFeatureCHROMIUM(
4238 kResultBucketId, GetResultShmId(), GetResultShmOffset());
4239 WaitForCmd();
4240 helper_->SetBucketSize(kResultBucketId, 0);
4241 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
4242 return *result != 0;
4245 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
4246 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
4247 GPU_CLIENT_SINGLE_THREAD_CHECK();
4248 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
4249 << target << ", " << offset << ", " << size << ", "
4250 << GLES2Util::GetStringEnum(access) << ")");
4251 // NOTE: target is NOT checked because the service will check it
4252 // and we don't know what targets are valid.
4253 if (access != GL_WRITE_ONLY) {
4254 SetGLErrorInvalidEnum(
4255 "glMapBufferSubDataCHROMIUM", access, "access");
4256 return NULL;
4258 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
4259 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
4260 return NULL;
4263 int32 shm_id;
4264 unsigned int shm_offset;
4265 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4266 if (!mem) {
4267 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
4268 return NULL;
4271 std::pair<MappedBufferMap::iterator, bool> result =
4272 mapped_buffers_.insert(std::make_pair(
4273 mem,
4274 MappedBuffer(
4275 access, shm_id, mem, shm_offset, target, offset, size)));
4276 DCHECK(result.second);
4277 GPU_CLIENT_LOG(" returned " << mem);
4278 return mem;
4281 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
4282 GPU_CLIENT_SINGLE_THREAD_CHECK();
4283 GPU_CLIENT_LOG(
4284 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
4285 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
4286 if (it == mapped_buffers_.end()) {
4287 SetGLError(
4288 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
4289 return;
4291 const MappedBuffer& mb = it->second;
4292 helper_->BufferSubData(
4293 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
4294 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
4295 mapped_buffers_.erase(it);
4296 CheckGLError();
4299 GLuint GLES2Implementation::GetBoundBufferHelper(GLenum target) {
4300 GLenum binding = GLES2Util::MapBufferTargetToBindingEnum(target);
4301 GLint id = 0;
4302 bool cached = GetHelper(binding, &id);
4303 DCHECK(cached);
4304 return static_cast<GLuint>(id);
4307 void GLES2Implementation::RemoveMappedBufferRangeByTarget(GLenum target) {
4308 GLuint buffer = GetBoundBufferHelper(target);
4309 RemoveMappedBufferRangeById(buffer);
4312 void GLES2Implementation::RemoveMappedBufferRangeById(GLuint buffer) {
4313 if (buffer > 0) {
4314 auto iter = mapped_buffer_range_map_.find(buffer);
4315 if (iter != mapped_buffer_range_map_.end() && iter->second.shm_memory) {
4316 mapped_memory_->FreePendingToken(
4317 iter->second.shm_memory, helper_->InsertToken());
4318 mapped_buffer_range_map_.erase(iter);
4323 void GLES2Implementation::ClearMappedBufferRangeMap() {
4324 for (auto& buffer_range : mapped_buffer_range_map_) {
4325 if (buffer_range.second.shm_memory) {
4326 mapped_memory_->FreePendingToken(
4327 buffer_range.second.shm_memory, helper_->InsertToken());
4330 mapped_buffer_range_map_.clear();
4333 void* GLES2Implementation::MapBufferRange(
4334 GLenum target, GLintptr offset, GLsizeiptr size, GLbitfield access) {
4335 GPU_CLIENT_SINGLE_THREAD_CHECK();
4336 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferRange("
4337 << GLES2Util::GetStringEnum(target) << ", " << offset << ", "
4338 << size << ", " << access << ")");
4339 if (!ValidateSize("glMapBufferRange", size) ||
4340 !ValidateOffset("glMapBufferRange", offset)) {
4341 return nullptr;
4344 int32 shm_id;
4345 unsigned int shm_offset;
4346 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4347 if (!mem) {
4348 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferRange", "out of memory");
4349 return nullptr;
4352 typedef cmds::MapBufferRange::Result Result;
4353 Result* result = GetResultAs<Result*>();
4354 *result = 0;
4355 helper_->MapBufferRange(target, offset, size, access, shm_id, shm_offset,
4356 GetResultShmId(), GetResultShmOffset());
4357 // TODO(zmo): For write only mode with MAP_INVALID_*_BIT, we should
4358 // consider an early return without WaitForCmd(). crbug.com/465804.
4359 WaitForCmd();
4360 if (*result) {
4361 const GLbitfield kInvalidateBits =
4362 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
4363 if ((access & kInvalidateBits) != 0) {
4364 // We do not read back from the buffer, therefore, we set the client
4365 // side memory to zero to avoid uninitialized data.
4366 memset(mem, 0, size);
4368 GLuint buffer = GetBoundBufferHelper(target);
4369 DCHECK_NE(0u, buffer);
4370 // glMapBufferRange fails on an already mapped buffer.
4371 DCHECK(mapped_buffer_range_map_.find(buffer) ==
4372 mapped_buffer_range_map_.end());
4373 auto iter = mapped_buffer_range_map_.insert(std::make_pair(
4374 buffer,
4375 MappedBuffer(access, shm_id, mem, shm_offset, target, offset, size)));
4376 DCHECK(iter.second);
4377 } else {
4378 mapped_memory_->Free(mem);
4379 mem = nullptr;
4382 GPU_CLIENT_LOG(" returned " << mem);
4383 CheckGLError();
4384 return mem;
4387 GLboolean GLES2Implementation::UnmapBuffer(GLenum target) {
4388 GPU_CLIENT_SINGLE_THREAD_CHECK();
4389 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapBuffer("
4390 << GLES2Util::GetStringEnum(target) << ")");
4391 switch (target) {
4392 case GL_ARRAY_BUFFER:
4393 case GL_ELEMENT_ARRAY_BUFFER:
4394 case GL_COPY_READ_BUFFER:
4395 case GL_COPY_WRITE_BUFFER:
4396 case GL_PIXEL_PACK_BUFFER:
4397 case GL_PIXEL_UNPACK_BUFFER:
4398 case GL_TRANSFORM_FEEDBACK_BUFFER:
4399 case GL_UNIFORM_BUFFER:
4400 break;
4401 default:
4402 SetGLError(GL_INVALID_ENUM, "glUnmapBuffer", "invalid target");
4403 return GL_FALSE;
4405 GLuint buffer = GetBoundBufferHelper(target);
4406 if (buffer == 0) {
4407 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "no buffer bound");
4408 return GL_FALSE;
4410 auto iter = mapped_buffer_range_map_.find(buffer);
4411 if (iter == mapped_buffer_range_map_.end()) {
4412 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "buffer is unmapped");
4413 return GL_FALSE;
4416 helper_->UnmapBuffer(target);
4417 RemoveMappedBufferRangeById(buffer);
4418 // TODO(zmo): There is a rare situation that data might be corrupted and
4419 // GL_FALSE should be returned. We lose context on that sitatuon, so we
4420 // don't have to WaitForCmd().
4421 GPU_CLIENT_LOG(" returned " << GL_TRUE);
4422 CheckGLError();
4423 return GL_TRUE;
4426 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
4427 GLenum target,
4428 GLint level,
4429 GLint xoffset,
4430 GLint yoffset,
4431 GLsizei width,
4432 GLsizei height,
4433 GLenum format,
4434 GLenum type,
4435 GLenum access) {
4436 GPU_CLIENT_SINGLE_THREAD_CHECK();
4437 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
4438 << target << ", " << level << ", "
4439 << xoffset << ", " << yoffset << ", "
4440 << width << ", " << height << ", "
4441 << GLES2Util::GetStringTextureFormat(format) << ", "
4442 << GLES2Util::GetStringPixelType(type) << ", "
4443 << GLES2Util::GetStringEnum(access) << ")");
4444 if (access != GL_WRITE_ONLY) {
4445 SetGLErrorInvalidEnum(
4446 "glMapTexSubImage2DCHROMIUM", access, "access");
4447 return NULL;
4449 // NOTE: target is NOT checked because the service will check it
4450 // and we don't know what targets are valid.
4451 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
4452 SetGLError(
4453 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
4454 return NULL;
4456 uint32 size;
4457 if (!GLES2Util::ComputeImageDataSizes(
4458 width, height, 1, format, type, unpack_alignment_, &size, NULL, NULL)) {
4459 SetGLError(
4460 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
4461 return NULL;
4463 int32 shm_id;
4464 unsigned int shm_offset;
4465 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4466 if (!mem) {
4467 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
4468 return NULL;
4471 std::pair<MappedTextureMap::iterator, bool> result =
4472 mapped_textures_.insert(std::make_pair(
4473 mem,
4474 MappedTexture(
4475 access, shm_id, mem, shm_offset,
4476 target, level, xoffset, yoffset, width, height, format, type)));
4477 DCHECK(result.second);
4478 GPU_CLIENT_LOG(" returned " << mem);
4479 return mem;
4482 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
4483 GPU_CLIENT_SINGLE_THREAD_CHECK();
4484 GPU_CLIENT_LOG(
4485 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
4486 MappedTextureMap::iterator it = mapped_textures_.find(mem);
4487 if (it == mapped_textures_.end()) {
4488 SetGLError(
4489 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
4490 return;
4492 const MappedTexture& mt = it->second;
4493 helper_->TexSubImage2D(
4494 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
4495 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
4496 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
4497 mapped_textures_.erase(it);
4498 CheckGLError();
4501 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
4502 float scale_factor) {
4503 GPU_CLIENT_SINGLE_THREAD_CHECK();
4504 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
4505 << width << ", " << height << ", " << scale_factor << ")");
4506 helper_->ResizeCHROMIUM(width, height, scale_factor);
4507 CheckGLError();
4510 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
4511 GPU_CLIENT_SINGLE_THREAD_CHECK();
4512 GPU_CLIENT_LOG("[" << GetLogPrefix()
4513 << "] glGetRequestableExtensionsCHROMIUM()");
4514 TRACE_EVENT0("gpu",
4515 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
4516 const char* result = NULL;
4517 // Clear the bucket so if the command fails nothing will be in it.
4518 helper_->SetBucketSize(kResultBucketId, 0);
4519 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
4520 std::string str;
4521 if (GetBucketAsString(kResultBucketId, &str)) {
4522 // The set of requestable extensions shrinks as we enable
4523 // them. Because we don't know when the client will stop referring
4524 // to a previous one it queries (see GetString) we need to cache
4525 // the unique results.
4526 std::set<std::string>::const_iterator sit =
4527 requestable_extensions_set_.find(str);
4528 if (sit != requestable_extensions_set_.end()) {
4529 result = sit->c_str();
4530 } else {
4531 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
4532 requestable_extensions_set_.insert(str);
4533 DCHECK(insert_result.second);
4534 result = insert_result.first->c_str();
4537 GPU_CLIENT_LOG(" returned " << result);
4538 return reinterpret_cast<const GLchar*>(result);
4541 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
4542 // with VirtualGL contexts.
4543 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
4544 GPU_CLIENT_SINGLE_THREAD_CHECK();
4545 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
4546 << extension << ")");
4547 SetBucketAsCString(kResultBucketId, extension);
4548 helper_->RequestExtensionCHROMIUM(kResultBucketId);
4549 helper_->SetBucketSize(kResultBucketId, 0);
4551 struct ExtensionCheck {
4552 const char* extension;
4553 ExtensionStatus* status;
4555 const ExtensionCheck checks[] = {
4557 "GL_ANGLE_pack_reverse_row_order",
4558 &angle_pack_reverse_row_order_status_,
4561 "GL_CHROMIUM_framebuffer_multisample",
4562 &chromium_framebuffer_multisample_,
4565 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
4566 for (size_t ii = 0; ii < kNumChecks; ++ii) {
4567 const ExtensionCheck& check = checks[ii];
4568 if (*check.status == kUnavailableExtensionStatus &&
4569 !strcmp(extension, check.extension)) {
4570 *check.status = kUnknownExtensionStatus;
4575 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
4576 GPU_CLIENT_SINGLE_THREAD_CHECK();
4577 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
4578 // Wait if this would add too many rate limit tokens.
4579 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
4580 helper_->WaitForToken(rate_limit_tokens_.front());
4581 rate_limit_tokens_.pop();
4583 rate_limit_tokens_.push(helper_->InsertToken());
4586 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
4587 GLuint program, std::vector<int8>* result) {
4588 DCHECK(result);
4589 // Clear the bucket so if the command fails nothing will be in it.
4590 helper_->SetBucketSize(kResultBucketId, 0);
4591 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
4592 GetBucketContents(kResultBucketId, result);
4595 void GLES2Implementation::GetProgramInfoCHROMIUM(
4596 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4597 GPU_CLIENT_SINGLE_THREAD_CHECK();
4598 if (bufsize < 0) {
4599 SetGLError(
4600 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
4601 return;
4603 if (size == NULL) {
4604 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
4605 return;
4607 // Make sure they've set size to 0 else the value will be undefined on
4608 // lost context.
4609 DCHECK_EQ(0, *size);
4610 std::vector<int8> result;
4611 GetProgramInfoCHROMIUMHelper(program, &result);
4612 if (result.empty()) {
4613 return;
4615 *size = result.size();
4616 if (!info) {
4617 return;
4619 if (static_cast<size_t>(bufsize) < result.size()) {
4620 SetGLError(GL_INVALID_OPERATION,
4621 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
4622 return;
4624 memcpy(info, &result[0], result.size());
4627 void GLES2Implementation::GetUniformBlocksCHROMIUMHelper(
4628 GLuint program, std::vector<int8>* result) {
4629 DCHECK(result);
4630 // Clear the bucket so if the command fails nothing will be in it.
4631 helper_->SetBucketSize(kResultBucketId, 0);
4632 helper_->GetUniformBlocksCHROMIUM(program, kResultBucketId);
4633 GetBucketContents(kResultBucketId, result);
4636 void GLES2Implementation::GetUniformBlocksCHROMIUM(
4637 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4638 GPU_CLIENT_SINGLE_THREAD_CHECK();
4639 if (bufsize < 0) {
4640 SetGLError(
4641 GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "bufsize less than 0.");
4642 return;
4644 if (size == NULL) {
4645 SetGLError(GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "size is null.");
4646 return;
4648 // Make sure they've set size to 0 else the value will be undefined on
4649 // lost context.
4650 DCHECK_EQ(0, *size);
4651 std::vector<int8> result;
4652 GetUniformBlocksCHROMIUMHelper(program, &result);
4653 if (result.empty()) {
4654 return;
4656 *size = result.size();
4657 if (!info) {
4658 return;
4660 if (static_cast<size_t>(bufsize) < result.size()) {
4661 SetGLError(GL_INVALID_OPERATION, "glGetUniformBlocksCHROMIUM",
4662 "bufsize is too small for result.");
4663 return;
4665 memcpy(info, &result[0], result.size());
4668 void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
4669 GLuint program, std::vector<int8>* result) {
4670 DCHECK(result);
4671 // Clear the bucket so if the command fails nothing will be in it.
4672 helper_->SetBucketSize(kResultBucketId, 0);
4673 helper_->GetUniformsES3CHROMIUM(program, kResultBucketId);
4674 GetBucketContents(kResultBucketId, result);
4677 void GLES2Implementation::GetUniformsES3CHROMIUM(
4678 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4679 GPU_CLIENT_SINGLE_THREAD_CHECK();
4680 if (bufsize < 0) {
4681 SetGLError(
4682 GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "bufsize less than 0.");
4683 return;
4685 if (size == NULL) {
4686 SetGLError(GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "size is null.");
4687 return;
4689 // Make sure they've set size to 0 else the value will be undefined on
4690 // lost context.
4691 DCHECK_EQ(0, *size);
4692 std::vector<int8> result;
4693 GetUniformsES3CHROMIUMHelper(program, &result);
4694 if (result.empty()) {
4695 return;
4697 *size = result.size();
4698 if (!info) {
4699 return;
4701 if (static_cast<size_t>(bufsize) < result.size()) {
4702 SetGLError(GL_INVALID_OPERATION,
4703 "glGetUniformsES3CHROMIUM", "bufsize is too small for result.");
4704 return;
4706 memcpy(info, &result[0], result.size());
4709 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
4710 GLuint program, std::vector<int8>* result) {
4711 DCHECK(result);
4712 // Clear the bucket so if the command fails nothing will be in it.
4713 helper_->SetBucketSize(kResultBucketId, 0);
4714 helper_->GetTransformFeedbackVaryingsCHROMIUM(program, kResultBucketId);
4715 GetBucketContents(kResultBucketId, result);
4718 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(
4719 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4720 GPU_CLIENT_SINGLE_THREAD_CHECK();
4721 if (bufsize < 0) {
4722 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4723 "bufsize less than 0.");
4724 return;
4726 if (size == NULL) {
4727 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4728 "size is null.");
4729 return;
4731 // Make sure they've set size to 0 else the value will be undefined on
4732 // lost context.
4733 DCHECK_EQ(0, *size);
4734 std::vector<int8> result;
4735 GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
4736 if (result.empty()) {
4737 return;
4739 *size = result.size();
4740 if (!info) {
4741 return;
4743 if (static_cast<size_t>(bufsize) < result.size()) {
4744 SetGLError(GL_INVALID_OPERATION, "glGetTransformFeedbackVaryingsCHROMIUM",
4745 "bufsize is too small for result.");
4746 return;
4748 memcpy(info, &result[0], result.size());
4751 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
4752 GPU_CLIENT_SINGLE_THREAD_CHECK();
4753 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
4754 << texture << ")");
4755 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
4756 helper_->CommandBufferHelper::Flush();
4757 return gpu_control_->CreateStreamTexture(texture);
4760 void GLES2Implementation::PostSubBufferCHROMIUM(
4761 GLint x, GLint y, GLint width, GLint height) {
4762 GPU_CLIENT_SINGLE_THREAD_CHECK();
4763 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
4764 << x << ", " << y << ", " << width << ", " << height << ")");
4765 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
4766 "width", width, "height", height);
4768 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
4769 swap_buffers_tokens_.push(helper_->InsertToken());
4770 helper_->PostSubBufferCHROMIUM(x, y, width, height);
4771 helper_->CommandBufferHelper::Flush();
4772 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
4773 helper_->WaitForToken(swap_buffers_tokens_.front());
4774 swap_buffers_tokens_.pop();
4778 void GLES2Implementation::DeleteQueriesEXTHelper(
4779 GLsizei n, const GLuint* queries) {
4780 for (GLsizei ii = 0; ii < n; ++ii) {
4781 query_tracker_->RemoveQuery(queries[ii]);
4782 query_id_allocator_->FreeID(queries[ii]);
4785 helper_->DeleteQueriesEXTImmediate(n, queries);
4788 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
4789 GPU_CLIENT_SINGLE_THREAD_CHECK();
4790 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
4792 // TODO(gman): To be spec compliant IDs from other contexts sharing
4793 // resources need to return true here even though you can't share
4794 // queries across contexts?
4795 return query_tracker_->GetQuery(id) != NULL;
4798 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
4799 GPU_CLIENT_SINGLE_THREAD_CHECK();
4800 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
4801 << GLES2Util::GetStringQueryTarget(target)
4802 << ", " << id << ")");
4804 // if any outstanding queries INV_OP
4805 QueryMap::iterator it = current_queries_.find(target);
4806 if (it != current_queries_.end()) {
4807 SetGLError(
4808 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
4809 return;
4812 // id = 0 INV_OP
4813 if (id == 0) {
4814 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
4815 return;
4818 // if not GENned INV_OPERATION
4819 if (!query_id_allocator_->InUse(id)) {
4820 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "invalid id");
4821 return;
4824 // if id does not have an object
4825 QueryTracker::Query* query = query_tracker_->GetQuery(id);
4826 if (!query) {
4827 query = query_tracker_->CreateQuery(id, target);
4828 if (!query) {
4829 SetGLError(GL_OUT_OF_MEMORY,
4830 "glBeginQueryEXT",
4831 "transfer buffer allocation failed");
4832 return;
4834 } else if (query->target() != target) {
4835 SetGLError(
4836 GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
4837 return;
4840 current_queries_[target] = query;
4842 query->Begin(this);
4843 CheckGLError();
4846 void GLES2Implementation::EndQueryEXT(GLenum target) {
4847 GPU_CLIENT_SINGLE_THREAD_CHECK();
4848 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
4849 << GLES2Util::GetStringQueryTarget(target) << ")");
4850 // Don't do anything if the context is lost.
4851 if (helper_->IsContextLost()) {
4852 return;
4855 QueryMap::iterator it = current_queries_.find(target);
4856 if (it == current_queries_.end()) {
4857 SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
4858 return;
4861 QueryTracker::Query* query = it->second;
4862 query->End(this);
4863 current_queries_.erase(it);
4864 CheckGLError();
4867 void GLES2Implementation::GetQueryivEXT(
4868 GLenum target, GLenum pname, GLint* params) {
4869 GPU_CLIENT_SINGLE_THREAD_CHECK();
4870 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
4871 << GLES2Util::GetStringQueryTarget(target) << ", "
4872 << GLES2Util::GetStringQueryParameter(pname) << ", "
4873 << static_cast<const void*>(params) << ")");
4875 if (pname != GL_CURRENT_QUERY_EXT) {
4876 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
4877 return;
4879 QueryMap::iterator it = current_queries_.find(target);
4880 if (it != current_queries_.end()) {
4881 QueryTracker::Query* query = it->second;
4882 *params = query->id();
4883 } else {
4884 *params = 0;
4886 GPU_CLIENT_LOG(" " << *params);
4887 CheckGLError();
4890 void GLES2Implementation::GetQueryObjectuivEXT(
4891 GLuint id, GLenum pname, GLuint* params) {
4892 GPU_CLIENT_SINGLE_THREAD_CHECK();
4893 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
4894 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
4895 << static_cast<const void*>(params) << ")");
4897 QueryTracker::Query* query = query_tracker_->GetQuery(id);
4898 if (!query) {
4899 SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
4900 return;
4903 QueryMap::iterator it = current_queries_.find(query->target());
4904 if (it != current_queries_.end()) {
4905 SetGLError(
4906 GL_INVALID_OPERATION,
4907 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
4908 return;
4911 if (query->NeverUsed()) {
4912 SetGLError(
4913 GL_INVALID_OPERATION,
4914 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
4915 return;
4918 switch (pname) {
4919 case GL_QUERY_RESULT_EXT:
4920 if (!query->CheckResultsAvailable(helper_)) {
4921 helper_->WaitForToken(query->token());
4922 if (!query->CheckResultsAvailable(helper_)) {
4923 FinishHelper();
4924 CHECK(query->CheckResultsAvailable(helper_));
4927 *params = query->GetResult();
4928 break;
4929 case GL_QUERY_RESULT_AVAILABLE_EXT:
4930 *params = query->CheckResultsAvailable(helper_);
4931 break;
4932 default:
4933 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
4934 break;
4936 GPU_CLIENT_LOG(" " << *params);
4937 CheckGLError();
4940 void GLES2Implementation::DrawArraysInstancedANGLE(
4941 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
4942 GPU_CLIENT_SINGLE_THREAD_CHECK();
4943 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
4944 << GLES2Util::GetStringDrawMode(mode) << ", "
4945 << first << ", " << count << ", " << primcount << ")");
4946 if (count < 0) {
4947 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
4948 return;
4950 if (primcount < 0) {
4951 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
4952 return;
4954 if (primcount == 0) {
4955 return;
4957 bool simulated = false;
4958 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
4959 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
4960 &simulated)) {
4961 return;
4963 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
4964 RestoreArrayBuffer(simulated);
4965 CheckGLError();
4968 void GLES2Implementation::DrawElementsInstancedANGLE(
4969 GLenum mode, GLsizei count, GLenum type, const void* indices,
4970 GLsizei primcount) {
4971 GPU_CLIENT_SINGLE_THREAD_CHECK();
4972 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
4973 << GLES2Util::GetStringDrawMode(mode) << ", "
4974 << count << ", "
4975 << GLES2Util::GetStringIndexType(type) << ", "
4976 << static_cast<const void*>(indices) << ", "
4977 << primcount << ")");
4978 if (count < 0) {
4979 SetGLError(GL_INVALID_VALUE,
4980 "glDrawElementsInstancedANGLE", "count less than 0.");
4981 return;
4983 if (count == 0) {
4984 return;
4986 if (primcount < 0) {
4987 SetGLError(GL_INVALID_VALUE,
4988 "glDrawElementsInstancedANGLE", "primcount < 0");
4989 return;
4991 if (primcount == 0) {
4992 return;
4994 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
4995 !ValidateOffset("glDrawElementsInstancedANGLE",
4996 reinterpret_cast<GLintptr>(indices))) {
4997 return;
4999 GLuint offset = 0;
5000 bool simulated = false;
5001 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
5002 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
5003 indices, &offset, &simulated)) {
5004 return;
5006 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
5007 RestoreElementAndArrayBuffers(simulated);
5008 CheckGLError();
5011 void GLES2Implementation::GenMailboxCHROMIUM(
5012 GLbyte* mailbox) {
5013 GPU_CLIENT_SINGLE_THREAD_CHECK();
5014 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
5015 << static_cast<const void*>(mailbox) << ")");
5016 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
5018 gpu::Mailbox result = gpu::Mailbox::Generate();
5019 memcpy(mailbox, result.name, sizeof(result.name));
5022 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target,
5023 const GLbyte* data) {
5024 GPU_CLIENT_SINGLE_THREAD_CHECK();
5025 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
5026 << static_cast<const void*>(data) << ")");
5027 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5028 DCHECK(mailbox.Verify()) << "ProduceTextureCHROMIUM was passed a "
5029 "mailbox that was not generated by "
5030 "GenMailboxCHROMIUM.";
5031 helper_->ProduceTextureCHROMIUMImmediate(target, data);
5032 CheckGLError();
5035 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
5036 GLuint texture, GLenum target, const GLbyte* data) {
5037 GPU_CLIENT_SINGLE_THREAD_CHECK();
5038 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
5039 << static_cast<const void*>(data) << ")");
5040 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5041 DCHECK(mailbox.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
5042 "mailbox that was not generated by "
5043 "GenMailboxCHROMIUM.";
5044 helper_->ProduceTextureDirectCHROMIUMImmediate(texture, target, data);
5045 CheckGLError();
5048 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target,
5049 const GLbyte* data) {
5050 GPU_CLIENT_SINGLE_THREAD_CHECK();
5051 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
5052 << static_cast<const void*>(data) << ")");
5053 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5054 DCHECK(mailbox.Verify()) << "ConsumeTextureCHROMIUM was passed a "
5055 "mailbox that was not generated by "
5056 "GenMailboxCHROMIUM.";
5057 helper_->ConsumeTextureCHROMIUMImmediate(target, data);
5058 CheckGLError();
5061 GLuint GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
5062 GLenum target, const GLbyte* data) {
5063 GPU_CLIENT_SINGLE_THREAD_CHECK();
5064 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
5065 << static_cast<const void*>(data) << ")");
5066 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5067 DCHECK(mailbox.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
5068 "mailbox that was not generated by "
5069 "GenMailboxCHROMIUM.";
5070 GLuint client_id;
5071 GetIdHandler(id_namespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
5072 helper_->CreateAndConsumeTextureCHROMIUMImmediate(target,
5073 client_id, data);
5074 if (share_group_->bind_generates_resource())
5075 helper_->CommandBufferHelper::Flush();
5076 CheckGLError();
5077 return client_id;
5080 void GLES2Implementation::PushGroupMarkerEXT(
5081 GLsizei length, const GLchar* marker) {
5082 GPU_CLIENT_SINGLE_THREAD_CHECK();
5083 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
5084 << length << ", " << marker << ")");
5085 if (!marker) {
5086 marker = "";
5088 SetBucketAsString(
5089 kResultBucketId,
5090 (length ? std::string(marker, length) : std::string(marker)));
5091 helper_->PushGroupMarkerEXT(kResultBucketId);
5092 helper_->SetBucketSize(kResultBucketId, 0);
5093 debug_marker_manager_.PushGroup(
5094 length ? std::string(marker, length) : std::string(marker));
5097 void GLES2Implementation::InsertEventMarkerEXT(
5098 GLsizei length, const GLchar* marker) {
5099 GPU_CLIENT_SINGLE_THREAD_CHECK();
5100 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
5101 << length << ", " << marker << ")");
5102 if (!marker) {
5103 marker = "";
5105 SetBucketAsString(
5106 kResultBucketId,
5107 (length ? std::string(marker, length) : std::string(marker)));
5108 helper_->InsertEventMarkerEXT(kResultBucketId);
5109 helper_->SetBucketSize(kResultBucketId, 0);
5110 debug_marker_manager_.SetMarker(
5111 length ? std::string(marker, length) : std::string(marker));
5114 void GLES2Implementation::PopGroupMarkerEXT() {
5115 GPU_CLIENT_SINGLE_THREAD_CHECK();
5116 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
5117 helper_->PopGroupMarkerEXT();
5118 debug_marker_manager_.PopGroup();
5121 void GLES2Implementation::TraceBeginCHROMIUM(
5122 const char* category_name, const char* trace_name) {
5123 GPU_CLIENT_SINGLE_THREAD_CHECK();
5124 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
5125 << category_name << ", " << trace_name << ")");
5126 SetBucketAsCString(kResultBucketId, category_name);
5127 SetBucketAsCString(kResultBucketId + 1, trace_name);
5128 helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1);
5129 helper_->SetBucketSize(kResultBucketId, 0);
5130 helper_->SetBucketSize(kResultBucketId + 1, 0);
5131 current_trace_stack_++;
5134 void GLES2Implementation::TraceEndCHROMIUM() {
5135 GPU_CLIENT_SINGLE_THREAD_CHECK();
5136 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
5137 if (current_trace_stack_ == 0) {
5138 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
5139 "missing begin trace");
5140 return;
5142 helper_->TraceEndCHROMIUM();
5143 current_trace_stack_--;
5146 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
5147 GPU_CLIENT_SINGLE_THREAD_CHECK();
5148 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
5149 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
5150 switch (target) {
5151 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
5152 if (access != GL_READ_ONLY) {
5153 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
5154 return NULL;
5156 break;
5157 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
5158 if (access != GL_WRITE_ONLY) {
5159 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
5160 return NULL;
5162 break;
5163 default:
5164 SetGLError(
5165 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
5166 return NULL;
5168 GLuint buffer_id;
5169 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
5170 if (!buffer_id) {
5171 return NULL;
5173 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
5174 if (!buffer) {
5175 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
5176 return NULL;
5178 if (buffer->mapped()) {
5179 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
5180 return NULL;
5182 // Here we wait for previous transfer operations to be finished.
5183 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
5184 // with this method of synchronization. Until this is fixed,
5185 // MapBufferCHROMIUM will not block even if the transfer is not ready
5186 // for these calls.
5187 if (buffer->last_usage_token()) {
5188 helper_->WaitForToken(buffer->last_usage_token());
5189 buffer->set_last_usage_token(0);
5191 buffer->set_mapped(true);
5193 GPU_CLIENT_LOG(" returned " << buffer->address());
5194 CheckGLError();
5195 return buffer->address();
5198 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
5199 GPU_CLIENT_SINGLE_THREAD_CHECK();
5200 GPU_CLIENT_LOG(
5201 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
5202 GLuint buffer_id;
5203 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
5204 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
5206 if (!buffer_id) {
5207 return false;
5209 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
5210 if (!buffer) {
5211 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
5212 return false;
5214 if (!buffer->mapped()) {
5215 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
5216 return false;
5218 buffer->set_mapped(false);
5219 CheckGLError();
5220 return true;
5223 bool GLES2Implementation::EnsureAsyncUploadSync() {
5224 if (async_upload_sync_)
5225 return true;
5227 int32 shm_id;
5228 unsigned int shm_offset;
5229 void* mem = mapped_memory_->Alloc(sizeof(AsyncUploadSync),
5230 &shm_id,
5231 &shm_offset);
5232 if (!mem)
5233 return false;
5235 async_upload_sync_shm_id_ = shm_id;
5236 async_upload_sync_shm_offset_ = shm_offset;
5237 async_upload_sync_ = static_cast<AsyncUploadSync*>(mem);
5238 async_upload_sync_->Reset();
5240 return true;
5243 uint32 GLES2Implementation::NextAsyncUploadToken() {
5244 async_upload_token_++;
5245 if (async_upload_token_ == 0)
5246 async_upload_token_++;
5247 return async_upload_token_;
5250 void GLES2Implementation::PollAsyncUploads() {
5251 if (!async_upload_sync_)
5252 return;
5254 if (helper_->IsContextLost()) {
5255 DetachedAsyncUploadMemoryList::iterator it =
5256 detached_async_upload_memory_.begin();
5257 while (it != detached_async_upload_memory_.end()) {
5258 mapped_memory_->Free(it->first);
5259 it = detached_async_upload_memory_.erase(it);
5261 return;
5264 DetachedAsyncUploadMemoryList::iterator it =
5265 detached_async_upload_memory_.begin();
5266 while (it != detached_async_upload_memory_.end()) {
5267 if (HasAsyncUploadTokenPassed(it->second)) {
5268 mapped_memory_->Free(it->first);
5269 it = detached_async_upload_memory_.erase(it);
5270 } else {
5271 break;
5276 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
5277 // Free all completed unmanaged async uploads buffers.
5278 PollAsyncUploads();
5280 // Synchronously free rest of the unmanaged async upload buffers.
5281 if (!detached_async_upload_memory_.empty()) {
5282 WaitAllAsyncTexImage2DCHROMIUM();
5283 WaitForCmd();
5284 PollAsyncUploads();
5288 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
5289 GLenum target, GLint level, GLenum internalformat, GLsizei width,
5290 GLsizei height, GLint border, GLenum format, GLenum type,
5291 const void* pixels) {
5292 GPU_CLIENT_SINGLE_THREAD_CHECK();
5293 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
5294 << GLES2Util::GetStringTextureTarget(target) << ", "
5295 << level << ", "
5296 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
5297 << width << ", " << height << ", " << border << ", "
5298 << GLES2Util::GetStringTextureFormat(format) << ", "
5299 << GLES2Util::GetStringPixelType(type) << ", "
5300 << static_cast<const void*>(pixels) << ")");
5301 if (level < 0 || height < 0 || width < 0) {
5302 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
5303 return;
5305 if (border != 0) {
5306 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
5307 return;
5309 uint32 size;
5310 uint32 unpadded_row_size;
5311 uint32 padded_row_size;
5312 if (!GLES2Util::ComputeImageDataSizes(
5313 width, height, 1, format, type, unpack_alignment_, &size,
5314 &unpadded_row_size, &padded_row_size)) {
5315 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
5316 return;
5319 // If there's no data/buffer just issue the AsyncTexImage2D
5320 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
5321 helper_->AsyncTexImage2DCHROMIUM(
5322 target, level, internalformat, width, height, format, type,
5323 0, 0, 0, 0, 0);
5324 return;
5327 if (!EnsureAsyncUploadSync()) {
5328 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
5329 return;
5332 // Otherwise, async uploads require a transfer buffer to be bound.
5333 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
5334 // the buffer before the transfer is finished. (Currently such
5335 // synchronization has to be handled manually.)
5336 GLuint offset = ToGLuint(pixels);
5337 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
5338 bound_pixel_unpack_transfer_buffer_id_,
5339 "glAsyncTexImage2DCHROMIUM", offset, size);
5340 if (buffer && buffer->shm_id() != -1) {
5341 uint32 async_token = NextAsyncUploadToken();
5342 buffer->set_last_async_upload_token(async_token);
5343 helper_->AsyncTexImage2DCHROMIUM(
5344 target, level, internalformat, width, height, format, type,
5345 buffer->shm_id(), buffer->shm_offset() + offset,
5346 async_token,
5347 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
5351 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
5352 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
5353 GLsizei height, GLenum format, GLenum type, const void* pixels) {
5354 GPU_CLIENT_SINGLE_THREAD_CHECK();
5355 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
5356 << GLES2Util::GetStringTextureTarget(target) << ", "
5357 << level << ", "
5358 << xoffset << ", " << yoffset << ", "
5359 << width << ", " << height << ", "
5360 << GLES2Util::GetStringTextureFormat(format) << ", "
5361 << GLES2Util::GetStringPixelType(type) << ", "
5362 << static_cast<const void*>(pixels) << ")");
5363 if (level < 0 || height < 0 || width < 0) {
5364 SetGLError(
5365 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
5366 return;
5369 uint32 size;
5370 uint32 unpadded_row_size;
5371 uint32 padded_row_size;
5372 if (!GLES2Util::ComputeImageDataSizes(
5373 width, height, 1, format, type, unpack_alignment_, &size,
5374 &unpadded_row_size, &padded_row_size)) {
5375 SetGLError(
5376 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
5377 return;
5380 if (!EnsureAsyncUploadSync()) {
5381 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
5382 return;
5385 // Async uploads require a transfer buffer to be bound.
5386 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
5387 // the buffer before the transfer is finished. (Currently such
5388 // synchronization has to be handled manually.)
5389 GLuint offset = ToGLuint(pixels);
5390 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
5391 bound_pixel_unpack_transfer_buffer_id_,
5392 "glAsyncTexSubImage2DCHROMIUM", offset, size);
5393 if (buffer && buffer->shm_id() != -1) {
5394 uint32 async_token = NextAsyncUploadToken();
5395 buffer->set_last_async_upload_token(async_token);
5396 helper_->AsyncTexSubImage2DCHROMIUM(
5397 target, level, xoffset, yoffset, width, height, format, type,
5398 buffer->shm_id(), buffer->shm_offset() + offset,
5399 async_token,
5400 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
5404 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
5405 GPU_CLIENT_SINGLE_THREAD_CHECK();
5406 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
5407 << GLES2Util::GetStringTextureTarget(target) << ")");
5408 helper_->WaitAsyncTexImage2DCHROMIUM(target);
5409 CheckGLError();
5412 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
5413 GPU_CLIENT_SINGLE_THREAD_CHECK();
5414 GPU_CLIENT_LOG("[" << GetLogPrefix()
5415 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
5416 helper_->WaitAllAsyncTexImage2DCHROMIUM();
5417 CheckGLError();
5420 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
5421 GPU_CLIENT_SINGLE_THREAD_CHECK();
5422 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
5423 helper_->CommandBufferHelper::Flush();
5424 return gpu_control_->InsertSyncPoint();
5427 GLuint GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
5428 GPU_CLIENT_SINGLE_THREAD_CHECK();
5429 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
5430 DCHECK(capabilities_.future_sync_points);
5431 return gpu_control_->InsertFutureSyncPoint();
5434 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point) {
5435 GPU_CLIENT_SINGLE_THREAD_CHECK();
5436 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
5437 << sync_point << ")");
5438 DCHECK(capabilities_.future_sync_points);
5439 helper_->CommandBufferHelper::Flush();
5440 gpu_control_->RetireSyncPoint(sync_point);
5443 namespace {
5445 bool ValidImageFormat(GLenum internalformat,
5446 const Capabilities& capabilities) {
5447 switch (internalformat) {
5448 case GL_ATC_RGB_AMD:
5449 case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
5450 return capabilities.texture_format_atc;
5451 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
5452 return capabilities.texture_format_dxt1;
5453 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
5454 return capabilities.texture_format_dxt5;
5455 case GL_ETC1_RGB8_OES:
5456 return capabilities.texture_format_etc1;
5457 case GL_R8:
5458 case GL_RGB:
5459 case GL_RGBA:
5460 case GL_BGRA_EXT:
5461 return true;
5462 default:
5463 return false;
5467 bool ValidImageUsage(GLenum usage) {
5468 switch (usage) {
5469 case GL_MAP_CHROMIUM:
5470 case GL_SCANOUT_CHROMIUM:
5471 return true;
5472 default:
5473 return false;
5477 } // namespace
5479 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer,
5480 GLsizei width,
5481 GLsizei height,
5482 GLenum internalformat) {
5483 if (width <= 0) {
5484 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
5485 return 0;
5488 if (height <= 0) {
5489 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
5490 return 0;
5493 if (!ValidImageFormat(internalformat, capabilities_)) {
5494 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "invalid format");
5495 return 0;
5498 int32_t image_id =
5499 gpu_control_->CreateImage(buffer, width, height, internalformat);
5500 if (image_id < 0) {
5501 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "image_id < 0");
5502 return 0;
5504 return image_id;
5507 GLuint GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer,
5508 GLsizei width,
5509 GLsizei height,
5510 GLenum internalformat) {
5511 GPU_CLIENT_SINGLE_THREAD_CHECK();
5512 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
5513 << ", " << height << ", "
5514 << GLES2Util::GetStringImageInternalFormat(internalformat)
5515 << ")");
5516 GLuint image_id =
5517 CreateImageCHROMIUMHelper(buffer, width, height, internalformat);
5518 CheckGLError();
5519 return image_id;
5522 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
5523 // Flush the command stream to make sure all pending commands
5524 // that may refer to the image_id are executed on the service side.
5525 helper_->CommandBufferHelper::Flush();
5526 gpu_control_->DestroyImage(image_id);
5529 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
5530 GPU_CLIENT_SINGLE_THREAD_CHECK();
5531 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
5532 << image_id << ")");
5533 DestroyImageCHROMIUMHelper(image_id);
5534 CheckGLError();
5537 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
5538 GLsizei width,
5539 GLsizei height,
5540 GLenum internalformat,
5541 GLenum usage) {
5542 if (width <= 0) {
5543 SetGLError(
5544 GL_INVALID_VALUE, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
5545 return 0;
5548 if (height <= 0) {
5549 SetGLError(GL_INVALID_VALUE,
5550 "glCreateGpuMemoryBufferImageCHROMIUM",
5551 "height <= 0");
5552 return 0;
5555 if (!ValidImageFormat(internalformat, capabilities_)) {
5556 SetGLError(GL_INVALID_VALUE,
5557 "glCreateGpuMemoryBufferImageCHROMIUM",
5558 "invalid format");
5559 return 0;
5562 if (!ValidImageUsage(usage)) {
5563 SetGLError(GL_INVALID_VALUE,
5564 "glCreateGpuMemoryBufferImageCHROMIUM",
5565 "invalid usage");
5566 return 0;
5569 // Flush the command stream to ensure ordering in case the newly
5570 // returned image_id has recently been in use with a different buffer.
5571 helper_->CommandBufferHelper::Flush();
5572 int32_t image_id = gpu_control_->CreateGpuMemoryBufferImage(
5573 width, height, internalformat, usage);
5574 if (image_id < 0) {
5575 SetGLError(GL_OUT_OF_MEMORY,
5576 "glCreateGpuMemoryBufferImageCHROMIUM",
5577 "image_id < 0");
5578 return 0;
5580 return image_id;
5583 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
5584 GLsizei width,
5585 GLsizei height,
5586 GLenum internalformat,
5587 GLenum usage) {
5588 GPU_CLIENT_SINGLE_THREAD_CHECK();
5589 GPU_CLIENT_LOG("[" << GetLogPrefix()
5590 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
5591 << ", " << height << ", "
5592 << GLES2Util::GetStringImageInternalFormat(internalformat)
5593 << ", " << GLES2Util::GetStringImageUsage(usage) << ")");
5594 GLuint image_id = CreateGpuMemoryBufferImageCHROMIUMHelper(
5595 width, height, internalformat, usage);
5596 CheckGLError();
5597 return image_id;
5600 bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
5601 if (size < 0) {
5602 SetGLError(GL_INVALID_VALUE, func, "size < 0");
5603 return false;
5605 if (!base::IsValueInRangeForNumericType<int32_t>(size)) {
5606 SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
5607 return false;
5609 return true;
5612 bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
5613 if (offset < 0) {
5614 SetGLError(GL_INVALID_VALUE, func, "offset < 0");
5615 return false;
5617 if (!base::IsValueInRangeForNumericType<int32_t>(offset)) {
5618 SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
5619 return false;
5621 return true;
5624 bool GLES2Implementation::GetSamplerParameterfvHelper(
5625 GLuint /* sampler */, GLenum /* pname */, GLfloat* /* params */) {
5626 // TODO(zmo): Implement client side caching.
5627 return false;
5630 bool GLES2Implementation::GetSamplerParameterivHelper(
5631 GLuint /* sampler */, GLenum /* pname */, GLint* /* params */) {
5632 // TODO(zmo): Implement client side caching.
5633 return false;
5636 bool GLES2Implementation::PackStringsToBucket(GLsizei count,
5637 const char* const* str,
5638 const GLint* length,
5639 const char* func_name) {
5640 DCHECK_LE(0, count);
5641 // Compute the total size.
5642 base::CheckedNumeric<size_t> total_size = count;
5643 total_size += 1;
5644 total_size *= sizeof(GLint);
5645 if (!total_size.IsValid()) {
5646 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5647 return false;
5649 size_t header_size = total_size.ValueOrDefault(0);
5650 std::vector<GLint> header(count + 1);
5651 header[0] = static_cast<GLint>(count);
5652 for (GLsizei ii = 0; ii < count; ++ii) {
5653 GLint len = 0;
5654 if (str[ii]) {
5655 len = (length && length[ii] >= 0)
5656 ? length[ii]
5657 : base::checked_cast<GLint>(strlen(str[ii]));
5659 total_size += len;
5660 total_size += 1; // NULL at the end of each char array.
5661 if (!total_size.IsValid()) {
5662 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5663 return false;
5665 header[ii + 1] = len;
5667 // Pack data into a bucket on the service.
5668 helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
5669 size_t offset = 0;
5670 for (GLsizei ii = 0; ii <= count; ++ii) {
5671 const char* src =
5672 (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
5673 base::CheckedNumeric<size_t> checked_size =
5674 (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
5675 if (ii > 0) {
5676 checked_size += 1; // NULL in the end.
5678 if (!checked_size.IsValid()) {
5679 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5680 return false;
5682 size_t size = checked_size.ValueOrDefault(0);
5683 while (size) {
5684 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
5685 if (!buffer.valid() || buffer.size() == 0) {
5686 SetGLError(GL_OUT_OF_MEMORY, func_name, "too large");
5687 return false;
5689 size_t copy_size = buffer.size();
5690 if (ii > 0 && buffer.size() == size)
5691 --copy_size;
5692 if (copy_size)
5693 memcpy(buffer.address(), src, copy_size);
5694 if (copy_size < buffer.size()) {
5695 // Append NULL in the end.
5696 DCHECK(copy_size + 1 == buffer.size());
5697 char* str = reinterpret_cast<char*>(buffer.address());
5698 str[copy_size] = 0;
5700 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
5701 buffer.shm_id(), buffer.offset());
5702 offset += buffer.size();
5703 src += buffer.size();
5704 size -= buffer.size();
5707 DCHECK_EQ(total_size.ValueOrDefault(0), offset);
5708 return true;
5711 void GLES2Implementation::UniformBlockBinding(GLuint program,
5712 GLuint index,
5713 GLuint binding) {
5714 GPU_CLIENT_SINGLE_THREAD_CHECK();
5715 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
5716 << ", " << index << ", " << binding << ")");
5717 share_group_->program_info_manager()->UniformBlockBinding(
5718 this, program, index, binding);
5719 helper_->UniformBlockBinding(program, index, binding);
5720 CheckGLError();
5723 GLenum GLES2Implementation::ClientWaitSync(
5724 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5725 GPU_CLIENT_SINGLE_THREAD_CHECK();
5726 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync
5727 << ", " << flags << ", " << timeout << ")");
5728 typedef cmds::ClientWaitSync::Result Result;
5729 Result* result = GetResultAs<Result*>();
5730 if (!result) {
5731 SetGLError(GL_OUT_OF_MEMORY, "ClientWaitSync", "");
5732 return GL_WAIT_FAILED;
5734 *result = GL_WAIT_FAILED;
5735 uint32_t v32_0 = 0, v32_1 = 0;
5736 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5737 helper_->ClientWaitSync(
5738 ToGLuint(sync), flags, v32_0, v32_1,
5739 GetResultShmId(), GetResultShmOffset());
5740 WaitForCmd();
5741 GPU_CLIENT_LOG("returned " << *result);
5742 CheckGLError();
5743 return *result;
5746 void GLES2Implementation::WaitSync(
5747 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5748 GPU_CLIENT_SINGLE_THREAD_CHECK();
5749 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync << ", "
5750 << flags << ", " << timeout << ")");
5751 uint32_t v32_0 = 0, v32_1 = 0;
5752 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5753 helper_->WaitSync(ToGLuint(sync), flags, v32_0, v32_1);
5754 CheckGLError();
5757 void GLES2Implementation::GetInternalformativ(
5758 GLenum target, GLenum format, GLenum pname,
5759 GLsizei buf_size, GLint* params) {
5760 GPU_CLIENT_SINGLE_THREAD_CHECK();
5761 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
5762 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetInternalformativ("
5763 << GLES2Util::GetStringRenderBufferTarget(target) << ", "
5764 << GLES2Util::GetStringRenderBufferFormat(format) << ", "
5765 << GLES2Util::GetStringInternalFormatParameter(pname)
5766 << ", " << buf_size << ", "
5767 << static_cast<const void*>(params) << ")");
5768 if (buf_size < 0) {
5769 SetGLError(GL_INVALID_VALUE, "glGetInternalformativ", "bufSize < 0");
5770 return;
5772 TRACE_EVENT0("gpu", "GLES2Implementation::GetInternalformativ");
5773 if (GetInternalformativHelper(target, format, pname, buf_size, params)) {
5774 return;
5776 typedef cmds::GetInternalformativ::Result Result;
5777 Result* result = GetResultAs<Result*>();
5778 if (!result) {
5779 return;
5781 result->SetNumResults(0);
5782 helper_->GetInternalformativ(target, format, pname,
5783 GetResultShmId(), GetResultShmOffset());
5784 WaitForCmd();
5785 GPU_CLIENT_LOG_CODE_BLOCK({
5786 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
5787 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
5790 if (buf_size > 0 && params) {
5791 GLint* data = result->GetData();
5792 if (buf_size >= result->GetNumResults()) {
5793 buf_size = result->GetNumResults();
5795 for (GLsizei ii = 0; ii < buf_size; ++ii) {
5796 params[ii] = data[ii];
5799 CheckGLError();
5802 // Include the auto-generated part of this file. We split this because it means
5803 // we can easily edit the non-auto generated parts right here in this file
5804 // instead of having to edit some template or the code generator.
5805 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
5807 } // namespace gles2
5808 } // namespace gpu