Rewrite AndroidSyncSettings to be significantly simpler.
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blob59385241e5c89526420ceda1fd8c50d75fc050b1
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // A class to emulate GLES2 over command buffers.
7 #include "gpu/command_buffer/client/gles2_implementation.h"
9 #include <GLES2/gl2ext.h>
10 #include <GLES2/gl2extchromium.h>
11 #include <GLES3/gl3.h>
12 #include <algorithm>
13 #include <limits>
14 #include <map>
15 #include <queue>
16 #include <set>
17 #include <sstream>
18 #include <string>
19 #include "base/bind.h"
20 #include "base/compiler_specific.h"
21 #include "base/numerics/safe_math.h"
22 #include "gpu/command_buffer/client/buffer_tracker.h"
23 #include "gpu/command_buffer/client/gpu_control.h"
24 #include "gpu/command_buffer/client/program_info_manager.h"
25 #include "gpu/command_buffer/client/query_tracker.h"
26 #include "gpu/command_buffer/client/transfer_buffer.h"
27 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
28 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
29 #include "gpu/command_buffer/common/trace_event.h"
31 #if defined(GPU_CLIENT_DEBUG)
32 #include "base/command_line.h"
33 #include "gpu/command_buffer/client/gpu_switches.h"
34 #endif
36 namespace gpu {
37 namespace gles2 {
39 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
40 static GLuint ToGLuint(const void* ptr) {
41 return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
44 #if !defined(_MSC_VER)
45 const size_t GLES2Implementation::kMaxSizeOfSimpleResult;
46 const unsigned int GLES2Implementation::kStartingOffset;
47 #endif
49 GLES2Implementation::GLStaticState::GLStaticState() {
52 GLES2Implementation::GLStaticState::~GLStaticState() {
55 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
56 GLES2Implementation* gles2_implementation)
57 : gles2_implementation_(gles2_implementation) {
58 CHECK_EQ(0, gles2_implementation_->use_count_);
59 ++gles2_implementation_->use_count_;
62 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
63 --gles2_implementation_->use_count_;
64 CHECK_EQ(0, gles2_implementation_->use_count_);
67 GLES2Implementation::GLES2Implementation(
68 GLES2CmdHelper* helper,
69 ShareGroup* share_group,
70 TransferBufferInterface* transfer_buffer,
71 bool bind_generates_resource,
72 bool lose_context_when_out_of_memory,
73 bool support_client_side_arrays,
74 GpuControl* gpu_control)
75 : helper_(helper),
76 transfer_buffer_(transfer_buffer),
77 angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
78 chromium_framebuffer_multisample_(kUnknownExtensionStatus),
79 pack_alignment_(4),
80 unpack_alignment_(4),
81 unpack_flip_y_(false),
82 unpack_row_length_(0),
83 unpack_image_height_(0),
84 unpack_skip_rows_(0),
85 unpack_skip_pixels_(0),
86 unpack_skip_images_(0),
87 pack_reverse_row_order_(false),
88 active_texture_unit_(0),
89 bound_framebuffer_(0),
90 bound_read_framebuffer_(0),
91 bound_renderbuffer_(0),
92 bound_valuebuffer_(0),
93 current_program_(0),
94 bound_array_buffer_id_(0),
95 bound_pixel_pack_transfer_buffer_id_(0),
96 bound_pixel_unpack_transfer_buffer_id_(0),
97 async_upload_token_(0),
98 async_upload_sync_(NULL),
99 async_upload_sync_shm_id_(0),
100 async_upload_sync_shm_offset_(0),
101 error_bits_(0),
102 debug_(false),
103 lose_context_when_out_of_memory_(lose_context_when_out_of_memory),
104 support_client_side_arrays_(support_client_side_arrays),
105 use_count_(0),
106 error_message_callback_(NULL),
107 current_trace_stack_(0),
108 gpu_control_(gpu_control),
109 capabilities_(gpu_control->GetCapabilities()),
110 weak_ptr_factory_(this) {
111 DCHECK(helper);
112 DCHECK(transfer_buffer);
113 DCHECK(gpu_control);
115 std::stringstream ss;
116 ss << std::hex << this;
117 this_in_hex_ = ss.str();
119 GPU_CLIENT_LOG_CODE_BLOCK({
120 debug_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
121 switches::kEnableGPUClientLogging);
124 share_group_ =
125 (share_group ? share_group : new ShareGroup(bind_generates_resource));
126 DCHECK(share_group_->bind_generates_resource() == bind_generates_resource);
128 memset(&reserved_ids_, 0, sizeof(reserved_ids_));
131 bool GLES2Implementation::Initialize(
132 unsigned int starting_transfer_buffer_size,
133 unsigned int min_transfer_buffer_size,
134 unsigned int max_transfer_buffer_size,
135 unsigned int mapped_memory_limit) {
136 TRACE_EVENT0("gpu", "GLES2Implementation::Initialize");
137 DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
138 DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
139 DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
141 if (!transfer_buffer_->Initialize(
142 starting_transfer_buffer_size,
143 kStartingOffset,
144 min_transfer_buffer_size,
145 max_transfer_buffer_size,
146 kAlignment,
147 kSizeToFlush)) {
148 return false;
151 mapped_memory_.reset(
152 new MappedMemoryManager(
153 helper_,
154 base::Bind(&GLES2Implementation::PollAsyncUploads,
155 // The mapped memory manager is owned by |this| here, and
156 // since its destroyed before before we destroy ourselves
157 // we don't need extra safety measures for this closure.
158 base::Unretained(this)),
159 mapped_memory_limit));
161 unsigned chunk_size = 2 * 1024 * 1024;
162 if (mapped_memory_limit != kNoLimit) {
163 // Use smaller chunks if the client is very memory conscientious.
164 chunk_size = std::min(mapped_memory_limit / 4, chunk_size);
166 mapped_memory_->set_chunk_size_multiple(chunk_size);
168 GLStaticState::ShaderPrecisionMap* shader_precisions =
169 &static_state_.shader_precisions;
170 capabilities_.VisitPrecisions([shader_precisions](
171 GLenum shader, GLenum type, Capabilities::ShaderPrecision* result) {
172 const GLStaticState::ShaderPrecisionKey key(shader, type);
173 cmds::GetShaderPrecisionFormat::Result cached_result = {
174 true, result->min_range, result->max_range, result->precision};
175 shader_precisions->insert(std::make_pair(key, cached_result));
178 util_.set_num_compressed_texture_formats(
179 capabilities_.num_compressed_texture_formats);
180 util_.set_num_shader_binary_formats(capabilities_.num_shader_binary_formats);
182 texture_units_.reset(
183 new TextureUnit[capabilities_.max_combined_texture_image_units]);
185 query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
186 buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
188 query_id_allocator_.reset(new IdAllocator());
189 if (support_client_side_arrays_) {
190 GetIdHandler(id_namespaces::kBuffers)->MakeIds(
191 this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
194 vertex_array_object_manager_.reset(new VertexArrayObjectManager(
195 capabilities_.max_vertex_attribs, reserved_ids_[0], reserved_ids_[1],
196 support_client_side_arrays_));
198 // GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
199 // on Client & Service.
200 if (capabilities_.bind_generates_resource_chromium !=
201 (share_group_->bind_generates_resource() ? 1 : 0)) {
202 SetGLError(GL_INVALID_OPERATION,
203 "Initialize",
204 "Service bind_generates_resource mismatch.");
205 return false;
208 return true;
211 GLES2Implementation::~GLES2Implementation() {
212 // Make sure the queries are finished otherwise we'll delete the
213 // shared memory (mapped_memory_) which will free the memory used
214 // by the queries. The GPU process when validating that memory is still
215 // shared will fail and abort (ie, it will stop running).
216 WaitForCmd();
217 query_tracker_.reset();
219 // GLES2Implementation::Initialize() could fail before allocating
220 // reserved_ids_, so we need delete them carefully.
221 if (support_client_side_arrays_ && reserved_ids_[0]) {
222 DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
225 // Release any per-context data in share group.
226 share_group_->FreeContext(this);
228 buffer_tracker_.reset();
230 FreeAllAsyncUploadBuffers();
232 if (async_upload_sync_) {
233 mapped_memory_->Free(async_upload_sync_);
234 async_upload_sync_ = NULL;
237 // Make sure the commands make it the service.
238 WaitForCmd();
241 GLES2CmdHelper* GLES2Implementation::helper() const {
242 return helper_;
245 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
246 return share_group_->GetIdHandler(namespace_id);
249 IdAllocator* GLES2Implementation::GetIdAllocator(int namespace_id) const {
250 if (namespace_id == id_namespaces::kQueries)
251 return query_id_allocator_.get();
252 NOTREACHED();
253 return NULL;
256 void* GLES2Implementation::GetResultBuffer() {
257 return transfer_buffer_->GetResultBuffer();
260 int32 GLES2Implementation::GetResultShmId() {
261 return transfer_buffer_->GetShmId();
264 uint32 GLES2Implementation::GetResultShmOffset() {
265 return transfer_buffer_->GetResultOffset();
268 void GLES2Implementation::FreeUnusedSharedMemory() {
269 mapped_memory_->FreeUnused();
272 void GLES2Implementation::FreeEverything() {
273 FreeAllAsyncUploadBuffers();
274 WaitForCmd();
275 query_tracker_->Shrink();
276 FreeUnusedSharedMemory();
277 transfer_buffer_->Free();
278 helper_->FreeRingBuffer();
281 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
282 if (!helper_->IsContextLost())
283 callback.Run();
286 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
287 const base::Closure& callback) {
288 gpu_control_->SignalSyncPoint(
289 sync_point,
290 base::Bind(&GLES2Implementation::RunIfContextNotLost,
291 weak_ptr_factory_.GetWeakPtr(),
292 callback));
295 void GLES2Implementation::SignalQuery(uint32 query,
296 const base::Closure& callback) {
297 // Flush previously entered commands to ensure ordering with any
298 // glBeginQueryEXT() calls that may have been put into the context.
299 ShallowFlushCHROMIUM();
300 gpu_control_->SignalQuery(
301 query,
302 base::Bind(&GLES2Implementation::RunIfContextNotLost,
303 weak_ptr_factory_.GetWeakPtr(),
304 callback));
307 void GLES2Implementation::SetSurfaceVisible(bool visible) {
308 TRACE_EVENT1(
309 "gpu", "GLES2Implementation::SetSurfaceVisible", "visible", visible);
310 // TODO(piman): This probably should be ShallowFlushCHROMIUM().
311 Flush();
312 gpu_control_->SetSurfaceVisible(visible);
313 if (!visible)
314 FreeEverything();
317 void GLES2Implementation::WaitForCmd() {
318 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
319 helper_->CommandBufferHelper::Finish();
322 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
323 const char* extensions =
324 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
325 if (!extensions)
326 return false;
328 int length = strlen(ext);
329 while (true) {
330 int n = strcspn(extensions, " ");
331 if (n == length && 0 == strncmp(ext, extensions, length)) {
332 return true;
334 if ('\0' == extensions[n]) {
335 return false;
337 extensions += n + 1;
341 bool GLES2Implementation::IsExtensionAvailableHelper(
342 const char* extension, ExtensionStatus* status) {
343 switch (*status) {
344 case kAvailableExtensionStatus:
345 return true;
346 case kUnavailableExtensionStatus:
347 return false;
348 default: {
349 bool available = IsExtensionAvailable(extension);
350 *status = available ? kAvailableExtensionStatus :
351 kUnavailableExtensionStatus;
352 return available;
357 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
358 return IsExtensionAvailableHelper(
359 "GL_ANGLE_pack_reverse_row_order",
360 &angle_pack_reverse_row_order_status_);
363 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
364 return IsExtensionAvailableHelper(
365 "GL_CHROMIUM_framebuffer_multisample",
366 &chromium_framebuffer_multisample_);
369 const std::string& GLES2Implementation::GetLogPrefix() const {
370 const std::string& prefix(debug_marker_manager_.GetMarker());
371 return prefix.empty() ? this_in_hex_ : prefix;
374 GLenum GLES2Implementation::GetError() {
375 GPU_CLIENT_SINGLE_THREAD_CHECK();
376 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
377 GLenum err = GetGLError();
378 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
379 return err;
382 GLenum GLES2Implementation::GetClientSideGLError() {
383 if (error_bits_ == 0) {
384 return GL_NO_ERROR;
387 GLenum error = GL_NO_ERROR;
388 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
389 if ((error_bits_ & mask) != 0) {
390 error = GLES2Util::GLErrorBitToGLError(mask);
391 break;
394 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
395 return error;
398 GLenum GLES2Implementation::GetGLError() {
399 TRACE_EVENT0("gpu", "GLES2::GetGLError");
400 // Check the GL error first, then our wrapped error.
401 typedef cmds::GetError::Result Result;
402 Result* result = GetResultAs<Result*>();
403 // If we couldn't allocate a result the context is lost.
404 if (!result) {
405 return GL_NO_ERROR;
407 *result = GL_NO_ERROR;
408 helper_->GetError(GetResultShmId(), GetResultShmOffset());
409 WaitForCmd();
410 GLenum error = *result;
411 if (error == GL_NO_ERROR) {
412 error = GetClientSideGLError();
413 } else {
414 // There was an error, clear the corresponding wrapped error.
415 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
417 return error;
420 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
421 void GLES2Implementation::FailGLError(GLenum error) {
422 if (error != GL_NO_ERROR) {
423 NOTREACHED() << "Error";
426 // NOTE: Calling GetGLError overwrites data in the result buffer.
427 void GLES2Implementation::CheckGLError() {
428 FailGLError(GetGLError());
430 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
432 void GLES2Implementation::SetGLError(
433 GLenum error, const char* function_name, const char* msg) {
434 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
435 << GLES2Util::GetStringError(error) << ": "
436 << function_name << ": " << msg);
437 FailGLError(error);
438 if (msg) {
439 last_error_ = msg;
441 if (error_message_callback_) {
442 std::string temp(GLES2Util::GetStringError(error) + " : " +
443 function_name + ": " + (msg ? msg : ""));
444 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
446 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
448 if (error == GL_OUT_OF_MEMORY && lose_context_when_out_of_memory_) {
449 helper_->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
450 GL_UNKNOWN_CONTEXT_RESET_ARB);
454 void GLES2Implementation::SetGLErrorInvalidEnum(
455 const char* function_name, GLenum value, const char* label) {
456 SetGLError(GL_INVALID_ENUM, function_name,
457 (std::string(label) + " was " +
458 GLES2Util::GetStringEnum(value)).c_str());
461 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
462 std::vector<int8>* data) {
463 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
464 DCHECK(data);
465 const uint32 kStartSize = 32 * 1024;
466 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
467 if (!buffer.valid()) {
468 return false;
470 typedef cmd::GetBucketStart::Result Result;
471 Result* result = GetResultAs<Result*>();
472 if (!result) {
473 return false;
475 *result = 0;
476 helper_->GetBucketStart(
477 bucket_id, GetResultShmId(), GetResultShmOffset(),
478 buffer.size(), buffer.shm_id(), buffer.offset());
479 WaitForCmd();
480 uint32 size = *result;
481 data->resize(size);
482 if (size > 0u) {
483 uint32 offset = 0;
484 while (size) {
485 if (!buffer.valid()) {
486 buffer.Reset(size);
487 if (!buffer.valid()) {
488 return false;
490 helper_->GetBucketData(
491 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
492 WaitForCmd();
494 uint32 size_to_copy = std::min(size, buffer.size());
495 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
496 offset += size_to_copy;
497 size -= size_to_copy;
498 buffer.Release();
500 // Free the bucket. This is not required but it does free up the memory.
501 // and we don't have to wait for the result so from the client's perspective
502 // it's cheap.
503 helper_->SetBucketSize(bucket_id, 0);
505 return true;
508 void GLES2Implementation::SetBucketContents(
509 uint32 bucket_id, const void* data, size_t size) {
510 DCHECK(data);
511 helper_->SetBucketSize(bucket_id, size);
512 if (size > 0u) {
513 uint32 offset = 0;
514 while (size) {
515 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
516 if (!buffer.valid()) {
517 return;
519 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
520 buffer.size());
521 helper_->SetBucketData(
522 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
523 offset += buffer.size();
524 size -= buffer.size();
529 void GLES2Implementation::SetBucketAsCString(
530 uint32 bucket_id, const char* str) {
531 // NOTE: strings are passed NULL terminated. That means the empty
532 // string will have a size of 1 and no-string will have a size of 0
533 if (str) {
534 SetBucketContents(bucket_id, str, strlen(str) + 1);
535 } else {
536 helper_->SetBucketSize(bucket_id, 0);
540 bool GLES2Implementation::GetBucketAsString(
541 uint32 bucket_id, std::string* str) {
542 DCHECK(str);
543 std::vector<int8> data;
544 // NOTE: strings are passed NULL terminated. That means the empty
545 // string will have a size of 1 and no-string will have a size of 0
546 if (!GetBucketContents(bucket_id, &data)) {
547 return false;
549 if (data.empty()) {
550 return false;
552 str->assign(&data[0], &data[0] + data.size() - 1);
553 return true;
556 void GLES2Implementation::SetBucketAsString(
557 uint32 bucket_id, const std::string& str) {
558 // NOTE: strings are passed NULL terminated. That means the empty
559 // string will have a size of 1 and no-string will have a size of 0
560 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
563 void GLES2Implementation::Disable(GLenum cap) {
564 GPU_CLIENT_SINGLE_THREAD_CHECK();
565 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
566 << GLES2Util::GetStringCapability(cap) << ")");
567 bool changed = false;
568 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
569 helper_->Disable(cap);
571 CheckGLError();
574 void GLES2Implementation::Enable(GLenum cap) {
575 GPU_CLIENT_SINGLE_THREAD_CHECK();
576 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
577 << GLES2Util::GetStringCapability(cap) << ")");
578 bool changed = false;
579 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
580 helper_->Enable(cap);
582 CheckGLError();
585 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
586 GPU_CLIENT_SINGLE_THREAD_CHECK();
587 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
588 << GLES2Util::GetStringCapability(cap) << ")");
589 bool state = false;
590 if (!state_.GetEnabled(cap, &state)) {
591 typedef cmds::IsEnabled::Result Result;
592 Result* result = GetResultAs<Result*>();
593 if (!result) {
594 return GL_FALSE;
596 *result = 0;
597 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
598 WaitForCmd();
599 state = (*result) != 0;
602 GPU_CLIENT_LOG("returned " << state);
603 CheckGLError();
604 return state;
607 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
608 switch (pname) {
609 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
610 *params = capabilities_.max_combined_texture_image_units;
611 return true;
612 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
613 *params = capabilities_.max_cube_map_texture_size;
614 return true;
615 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
616 *params = capabilities_.max_fragment_uniform_vectors;
617 return true;
618 case GL_MAX_RENDERBUFFER_SIZE:
619 *params = capabilities_.max_renderbuffer_size;
620 return true;
621 case GL_MAX_TEXTURE_IMAGE_UNITS:
622 *params = capabilities_.max_texture_image_units;
623 return true;
624 case GL_MAX_TEXTURE_SIZE:
625 *params = capabilities_.max_texture_size;
626 return true;
627 case GL_MAX_VARYING_VECTORS:
628 *params = capabilities_.max_varying_vectors;
629 return true;
630 case GL_MAX_VERTEX_ATTRIBS:
631 *params = capabilities_.max_vertex_attribs;
632 return true;
633 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
634 *params = capabilities_.max_vertex_texture_image_units;
635 return true;
636 case GL_MAX_VERTEX_UNIFORM_VECTORS:
637 *params = capabilities_.max_vertex_uniform_vectors;
638 return true;
639 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
640 *params = capabilities_.num_compressed_texture_formats;
641 return true;
642 case GL_NUM_SHADER_BINARY_FORMATS:
643 *params = capabilities_.num_shader_binary_formats;
644 return true;
645 case GL_ARRAY_BUFFER_BINDING:
646 if (share_group_->bind_generates_resource()) {
647 *params = bound_array_buffer_id_;
648 return true;
650 return false;
651 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
652 if (share_group_->bind_generates_resource()) {
653 *params =
654 vertex_array_object_manager_->bound_element_array_buffer();
655 return true;
657 return false;
658 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
659 *params = bound_pixel_pack_transfer_buffer_id_;
660 return true;
661 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
662 *params = bound_pixel_unpack_transfer_buffer_id_;
663 return true;
664 case GL_ACTIVE_TEXTURE:
665 *params = active_texture_unit_ + GL_TEXTURE0;
666 return true;
667 case GL_TEXTURE_BINDING_2D:
668 if (share_group_->bind_generates_resource()) {
669 *params = texture_units_[active_texture_unit_].bound_texture_2d;
670 return true;
672 return false;
673 case GL_TEXTURE_BINDING_CUBE_MAP:
674 if (share_group_->bind_generates_resource()) {
675 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
676 return true;
678 return false;
679 case GL_TEXTURE_BINDING_EXTERNAL_OES:
680 if (share_group_->bind_generates_resource()) {
681 *params =
682 texture_units_[active_texture_unit_].bound_texture_external_oes;
683 return true;
685 return false;
686 case GL_FRAMEBUFFER_BINDING:
687 if (share_group_->bind_generates_resource()) {
688 *params = bound_framebuffer_;
689 return true;
691 return false;
692 case GL_READ_FRAMEBUFFER_BINDING:
693 if (IsChromiumFramebufferMultisampleAvailable() &&
694 share_group_->bind_generates_resource()) {
695 *params = bound_read_framebuffer_;
696 return true;
698 return false;
699 case GL_RENDERBUFFER_BINDING:
700 if (share_group_->bind_generates_resource()) {
701 *params = bound_renderbuffer_;
702 return true;
704 return false;
705 case GL_MAX_UNIFORM_BUFFER_BINDINGS:
706 *params = capabilities_.max_uniform_buffer_bindings;
707 return true;
708 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
709 *params = capabilities_.max_transform_feedback_separate_attribs;
710 return true;
711 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
712 *params = capabilities_.uniform_buffer_offset_alignment;
713 return true;
714 default:
715 return false;
719 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
720 // TODO(gman): Make this handle pnames that return more than 1 value.
721 GLint value;
722 if (!GetHelper(pname, &value)) {
723 return false;
725 *params = static_cast<GLboolean>(value);
726 return true;
729 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
730 // TODO(gman): Make this handle pnames that return more than 1 value.
731 GLint value;
732 if (!GetHelper(pname, &value)) {
733 return false;
735 *params = static_cast<GLfloat>(value);
736 return true;
739 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
740 return GetHelper(pname, params);
743 bool GLES2Implementation::GetInternalformativHelper(
744 GLenum target, GLenum format, GLenum pname, GLsizei bufSize,
745 GLint* params) {
746 // TODO(zmo): Implement the client side caching.
747 return false;
750 bool GLES2Implementation::GetSyncivHelper(
751 GLsync sync, GLenum pname, GLsizei bufsize, GLsizei* length,
752 GLint* values) {
753 GLint value = 0;
754 switch (pname) {
755 case GL_OBJECT_TYPE:
756 value = GL_SYNC_FENCE;
757 break;
758 case GL_SYNC_CONDITION:
759 value = GL_SYNC_GPU_COMMANDS_COMPLETE;
760 break;
761 case GL_SYNC_FLAGS:
762 value = 0;
763 break;
764 default:
765 return false;
767 if (bufsize > 0) {
768 DCHECK(values);
769 *values = value;
771 if (length) {
772 *length = 1;
774 return true;
777 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
778 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
779 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
780 Result* result = GetResultAs<Result*>();
781 if (!result) {
782 return 0;
784 *result = 0;
785 helper_->GetMaxValueInBufferCHROMIUM(
786 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
787 WaitForCmd();
788 return *result;
791 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
792 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
793 GPU_CLIENT_SINGLE_THREAD_CHECK();
794 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
795 << buffer_id << ", " << count << ", "
796 << GLES2Util::GetStringGetMaxIndexType(type)
797 << ", " << offset << ")");
798 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
799 buffer_id, count, type, offset);
800 GPU_CLIENT_LOG("returned " << result);
801 CheckGLError();
802 return result;
805 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
806 if (restore) {
807 RestoreArrayBuffer(restore);
808 // Restore the element array binding.
809 // We only need to restore it if it wasn't a client side array.
810 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
811 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
816 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
817 if (restore) {
818 // Restore the user's current binding.
819 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_);
823 void GLES2Implementation::DrawElements(
824 GLenum mode, GLsizei count, GLenum type, const void* indices) {
825 GPU_CLIENT_SINGLE_THREAD_CHECK();
826 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
827 << GLES2Util::GetStringDrawMode(mode) << ", "
828 << count << ", "
829 << GLES2Util::GetStringIndexType(type) << ", "
830 << static_cast<const void*>(indices) << ")");
831 if (count < 0) {
832 SetGLError(GL_INVALID_VALUE, "glDrawElements", "count less than 0.");
833 return;
835 if (count == 0) {
836 return;
838 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
839 !ValidateOffset("glDrawElements", reinterpret_cast<GLintptr>(indices))) {
840 return;
842 GLuint offset = 0;
843 bool simulated = false;
844 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
845 "glDrawElements", this, helper_, count, type, 0, indices,
846 &offset, &simulated)) {
847 return;
849 helper_->DrawElements(mode, count, type, offset);
850 RestoreElementAndArrayBuffers(simulated);
851 CheckGLError();
854 void GLES2Implementation::Flush() {
855 GPU_CLIENT_SINGLE_THREAD_CHECK();
856 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
857 // Insert the cmd to call glFlush
858 helper_->Flush();
859 // Flush our command buffer
860 // (tell the service to execute up to the flush cmd.)
861 helper_->CommandBufferHelper::Flush();
864 void GLES2Implementation::ShallowFlushCHROMIUM() {
865 GPU_CLIENT_SINGLE_THREAD_CHECK();
866 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
867 // Flush our command buffer
868 // (tell the service to execute up to the flush cmd.)
869 helper_->CommandBufferHelper::Flush();
870 // TODO(piman): Add the FreeEverything() logic here.
873 void GLES2Implementation::OrderingBarrierCHROMIUM() {
874 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOrderingBarrierCHROMIUM");
875 // Flush command buffer at the GPU channel level. May be implemented as
876 // Flush().
877 helper_->CommandBufferHelper::OrderingBarrier();
880 void GLES2Implementation::Finish() {
881 GPU_CLIENT_SINGLE_THREAD_CHECK();
882 FinishHelper();
885 void GLES2Implementation::ShallowFinishCHROMIUM() {
886 GPU_CLIENT_SINGLE_THREAD_CHECK();
887 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
888 // Flush our command buffer (tell the service to execute up to the flush cmd
889 // and don't return until it completes).
890 helper_->CommandBufferHelper::Finish();
893 void GLES2Implementation::FinishHelper() {
894 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
895 TRACE_EVENT0("gpu", "GLES2::Finish");
896 // Insert the cmd to call glFinish
897 helper_->Finish();
898 // Finish our command buffer
899 // (tell the service to execute up to the Finish cmd and wait for it to
900 // execute.)
901 helper_->CommandBufferHelper::Finish();
904 void GLES2Implementation::SwapBuffers() {
905 GPU_CLIENT_SINGLE_THREAD_CHECK();
906 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
907 // TODO(piman): Strictly speaking we'd want to insert the token after the
908 // swap, but the state update with the updated token might not have happened
909 // by the time the SwapBuffer callback gets called, forcing us to synchronize
910 // with the GPU process more than needed. So instead, make it happen before.
911 // All it means is that we could be slightly looser on the kMaxSwapBuffers
912 // semantics if the client doesn't use the callback mechanism, and by chance
913 // the scheduler yields between the InsertToken and the SwapBuffers.
914 swap_buffers_tokens_.push(helper_->InsertToken());
915 helper_->SwapBuffers();
916 helper_->CommandBufferHelper::Flush();
917 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
918 // compensate for TODO above.
919 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
920 helper_->WaitForToken(swap_buffers_tokens_.front());
921 swap_buffers_tokens_.pop();
925 void GLES2Implementation::SwapInterval(int interval) {
926 GPU_CLIENT_SINGLE_THREAD_CHECK();
927 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapInterval("
928 << interval << ")");
929 helper_->SwapInterval(interval);
932 void GLES2Implementation::BindAttribLocation(
933 GLuint program, GLuint index, const char* name) {
934 GPU_CLIENT_SINGLE_THREAD_CHECK();
935 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
936 << program << ", " << index << ", " << name << ")");
937 SetBucketAsString(kResultBucketId, name);
938 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
939 helper_->SetBucketSize(kResultBucketId, 0);
940 CheckGLError();
943 void GLES2Implementation::BindUniformLocationCHROMIUM(
944 GLuint program, GLint location, const char* name) {
945 GPU_CLIENT_SINGLE_THREAD_CHECK();
946 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
947 << program << ", " << location << ", " << name << ")");
948 SetBucketAsString(kResultBucketId, name);
949 helper_->BindUniformLocationCHROMIUMBucket(
950 program, location, kResultBucketId);
951 helper_->SetBucketSize(kResultBucketId, 0);
952 CheckGLError();
955 void GLES2Implementation::GetVertexAttribPointerv(
956 GLuint index, GLenum pname, void** ptr) {
957 GPU_CLIENT_SINGLE_THREAD_CHECK();
958 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
959 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
960 << static_cast<void*>(ptr) << ")");
961 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
962 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
963 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
964 typedef cmds::GetVertexAttribPointerv::Result Result;
965 Result* result = GetResultAs<Result*>();
966 if (!result) {
967 return;
969 result->SetNumResults(0);
970 helper_->GetVertexAttribPointerv(
971 index, pname, GetResultShmId(), GetResultShmOffset());
972 WaitForCmd();
973 result->CopyResult(ptr);
974 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
976 GPU_CLIENT_LOG_CODE_BLOCK({
977 for (int32 i = 0; i < num_results; ++i) {
978 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
981 CheckGLError();
984 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
985 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
986 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
987 SetGLError(
988 GL_INVALID_VALUE,
989 "glDeleteProgram", "id not created by this context.");
990 return false;
992 if (program == current_program_) {
993 current_program_ = 0;
995 return true;
998 void GLES2Implementation::DeleteProgramStub(
999 GLsizei n, const GLuint* programs) {
1000 DCHECK_EQ(1, n);
1001 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1002 helper_->DeleteProgram(programs[0]);
1005 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1006 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1007 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1008 SetGLError(
1009 GL_INVALID_VALUE,
1010 "glDeleteShader", "id not created by this context.");
1011 return false;
1013 return true;
1016 void GLES2Implementation::DeleteShaderStub(
1017 GLsizei n, const GLuint* shaders) {
1018 DCHECK_EQ(1, n);
1019 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1020 helper_->DeleteShader(shaders[0]);
1023 void GLES2Implementation::DeleteSyncHelper(GLsync sync) {
1024 GLuint sync_uint = ToGLuint(sync);
1025 if (!GetIdHandler(id_namespaces::kSyncs)->FreeIds(
1026 this, 1, &sync_uint, &GLES2Implementation::DeleteSyncStub)) {
1027 SetGLError(
1028 GL_INVALID_VALUE,
1029 "glDeleteSync", "id not created by this context.");
1033 void GLES2Implementation::DeleteSyncStub(GLsizei n, const GLuint* syncs) {
1034 DCHECK_EQ(1, n);
1035 helper_->DeleteSync(syncs[0]);
1038 GLint GLES2Implementation::GetAttribLocationHelper(
1039 GLuint program, const char* name) {
1040 typedef cmds::GetAttribLocation::Result Result;
1041 Result* result = GetResultAs<Result*>();
1042 if (!result) {
1043 return -1;
1045 *result = -1;
1046 SetBucketAsCString(kResultBucketId, name);
1047 helper_->GetAttribLocation(
1048 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1049 WaitForCmd();
1050 helper_->SetBucketSize(kResultBucketId, 0);
1051 return *result;
1054 GLint GLES2Implementation::GetAttribLocation(
1055 GLuint program, const char* name) {
1056 GPU_CLIENT_SINGLE_THREAD_CHECK();
1057 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1058 << ", " << name << ")");
1059 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1060 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1061 this, program, name);
1062 GPU_CLIENT_LOG("returned " << loc);
1063 CheckGLError();
1064 return loc;
1067 GLint GLES2Implementation::GetUniformLocationHelper(
1068 GLuint program, const char* name) {
1069 typedef cmds::GetUniformLocation::Result Result;
1070 Result* result = GetResultAs<Result*>();
1071 if (!result) {
1072 return -1;
1074 *result = -1;
1075 SetBucketAsCString(kResultBucketId, name);
1076 helper_->GetUniformLocation(program, kResultBucketId,
1077 GetResultShmId(), GetResultShmOffset());
1078 WaitForCmd();
1079 helper_->SetBucketSize(kResultBucketId, 0);
1080 return *result;
1083 GLint GLES2Implementation::GetUniformLocation(
1084 GLuint program, const char* name) {
1085 GPU_CLIENT_SINGLE_THREAD_CHECK();
1086 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1087 << ", " << name << ")");
1088 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1089 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1090 this, program, name);
1091 GPU_CLIENT_LOG("returned " << loc);
1092 CheckGLError();
1093 return loc;
1096 bool GLES2Implementation::GetUniformIndicesHelper(
1097 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1098 typedef cmds::GetUniformIndices::Result Result;
1099 Result* result = GetResultAs<Result*>();
1100 if (!result) {
1101 return false;
1103 result->SetNumResults(0);
1104 if (!PackStringsToBucket(count, names, NULL, "glGetUniformIndices")) {
1105 return false;
1107 helper_->GetUniformIndices(program, kResultBucketId,
1108 GetResultShmId(), GetResultShmOffset());
1109 WaitForCmd();
1110 if (result->GetNumResults() != count) {
1111 return false;
1113 result->CopyResult(indices);
1114 return true;
1117 void GLES2Implementation::GetUniformIndices(
1118 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1119 GPU_CLIENT_SINGLE_THREAD_CHECK();
1120 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
1121 << ", " << count << ", " << names << ", " << indices << ")");
1122 TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
1123 if (count < 0) {
1124 SetGLError(GL_INVALID_VALUE, "glGetUniformIndices", "count < 0");
1125 return;
1127 if (count == 0) {
1128 return;
1130 bool success = share_group_->program_info_manager()->GetUniformIndices(
1131 this, program, count, names, indices);
1132 if (success) {
1133 GPU_CLIENT_LOG_CODE_BLOCK({
1134 for (GLsizei ii = 0; ii < count; ++ii) {
1135 GPU_CLIENT_LOG(" " << ii << ": " << indices[ii]);
1139 CheckGLError();
1142 bool GLES2Implementation::GetProgramivHelper(
1143 GLuint program, GLenum pname, GLint* params) {
1144 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1145 this, program, pname, params);
1146 GPU_CLIENT_LOG_CODE_BLOCK({
1147 if (got_value) {
1148 GPU_CLIENT_LOG(" 0: " << *params);
1151 return got_value;
1154 GLint GLES2Implementation::GetFragDataLocationHelper(
1155 GLuint program, const char* name) {
1156 typedef cmds::GetFragDataLocation::Result Result;
1157 Result* result = GetResultAs<Result*>();
1158 if (!result) {
1159 return -1;
1161 *result = -1;
1162 SetBucketAsCString(kResultBucketId, name);
1163 helper_->GetFragDataLocation(
1164 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1165 WaitForCmd();
1166 helper_->SetBucketSize(kResultBucketId, 0);
1167 return *result;
1170 GLint GLES2Implementation::GetFragDataLocation(
1171 GLuint program, const char* name) {
1172 GPU_CLIENT_SINGLE_THREAD_CHECK();
1173 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataLocation("
1174 << program << ", " << name << ")");
1175 TRACE_EVENT0("gpu", "GLES2::GetFragDataLocation");
1176 GLint loc = share_group_->program_info_manager()->GetFragDataLocation(
1177 this, program, name);
1178 GPU_CLIENT_LOG("returned " << loc);
1179 CheckGLError();
1180 return loc;
1183 GLuint GLES2Implementation::GetUniformBlockIndexHelper(
1184 GLuint program, const char* name) {
1185 typedef cmds::GetUniformBlockIndex::Result Result;
1186 Result* result = GetResultAs<Result*>();
1187 if (!result) {
1188 return GL_INVALID_INDEX;
1190 *result = GL_INVALID_INDEX;
1191 SetBucketAsCString(kResultBucketId, name);
1192 helper_->GetUniformBlockIndex(
1193 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1194 WaitForCmd();
1195 helper_->SetBucketSize(kResultBucketId, 0);
1196 return *result;
1199 GLuint GLES2Implementation::GetUniformBlockIndex(
1200 GLuint program, const char* name) {
1201 GPU_CLIENT_SINGLE_THREAD_CHECK();
1202 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformBlockIndex("
1203 << program << ", " << name << ")");
1204 TRACE_EVENT0("gpu", "GLES2::GetUniformBlockIndex");
1205 GLuint index = share_group_->program_info_manager()->GetUniformBlockIndex(
1206 this, program, name);
1207 GPU_CLIENT_LOG("returned " << index);
1208 CheckGLError();
1209 return index;
1212 void GLES2Implementation::LinkProgram(GLuint program) {
1213 GPU_CLIENT_SINGLE_THREAD_CHECK();
1214 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1215 helper_->LinkProgram(program);
1216 share_group_->program_info_manager()->CreateInfo(program);
1217 CheckGLError();
1220 void GLES2Implementation::ShaderBinary(
1221 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1222 GLsizei length) {
1223 GPU_CLIENT_SINGLE_THREAD_CHECK();
1224 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1225 << static_cast<const void*>(shaders) << ", "
1226 << GLES2Util::GetStringEnum(binaryformat) << ", "
1227 << static_cast<const void*>(binary) << ", "
1228 << length << ")");
1229 if (n < 0) {
1230 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1231 return;
1233 if (length < 0) {
1234 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1235 return;
1237 // TODO(gman): ShaderBinary should use buckets.
1238 unsigned int shader_id_size = n * sizeof(*shaders);
1239 ScopedTransferBufferArray<GLint> buffer(
1240 shader_id_size + length, helper_, transfer_buffer_);
1241 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1242 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1243 return;
1245 void* shader_ids = buffer.elements();
1246 void* shader_data = buffer.elements() + shader_id_size;
1247 memcpy(shader_ids, shaders, shader_id_size);
1248 memcpy(shader_data, binary, length);
1249 helper_->ShaderBinary(
1251 buffer.shm_id(),
1252 buffer.offset(),
1253 binaryformat,
1254 buffer.shm_id(),
1255 buffer.offset() + shader_id_size,
1256 length);
1257 CheckGLError();
1260 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1261 GPU_CLIENT_SINGLE_THREAD_CHECK();
1262 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1263 << GLES2Util::GetStringPixelStore(pname) << ", "
1264 << param << ")");
1265 switch (pname) {
1266 case GL_PACK_ALIGNMENT:
1267 pack_alignment_ = param;
1268 break;
1269 case GL_UNPACK_ALIGNMENT:
1270 unpack_alignment_ = param;
1271 break;
1272 case GL_UNPACK_ROW_LENGTH_EXT:
1273 unpack_row_length_ = param;
1274 return;
1275 case GL_UNPACK_IMAGE_HEIGHT:
1276 unpack_image_height_ = param;
1277 return;
1278 case GL_UNPACK_SKIP_ROWS_EXT:
1279 unpack_skip_rows_ = param;
1280 return;
1281 case GL_UNPACK_SKIP_PIXELS_EXT:
1282 unpack_skip_pixels_ = param;
1283 return;
1284 case GL_UNPACK_SKIP_IMAGES:
1285 unpack_skip_images_ = param;
1286 return;
1287 case GL_UNPACK_FLIP_Y_CHROMIUM:
1288 unpack_flip_y_ = (param != 0);
1289 break;
1290 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1291 pack_reverse_row_order_ =
1292 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1293 break;
1294 default:
1295 break;
1297 helper_->PixelStorei(pname, param);
1298 CheckGLError();
1301 void GLES2Implementation::VertexAttribIPointer(
1302 GLuint index, GLint size, GLenum type, GLsizei stride, const void* ptr) {
1303 GPU_CLIENT_SINGLE_THREAD_CHECK();
1304 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1305 << index << ", "
1306 << size << ", "
1307 << GLES2Util::GetStringVertexAttribType(type) << ", "
1308 << stride << ", "
1309 << ptr << ")");
1310 helper_->VertexAttribIPointer(index, size, type, stride, ToGLuint(ptr));
1311 CheckGLError();
1314 void GLES2Implementation::VertexAttribPointer(
1315 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1316 const void* ptr) {
1317 GPU_CLIENT_SINGLE_THREAD_CHECK();
1318 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1319 << index << ", "
1320 << size << ", "
1321 << GLES2Util::GetStringVertexAttribType(type) << ", "
1322 << GLES2Util::GetStringBool(normalized) << ", "
1323 << stride << ", "
1324 << ptr << ")");
1325 // Record the info on the client side.
1326 if (!vertex_array_object_manager_->SetAttribPointer(
1327 bound_array_buffer_id_, index, size, type, normalized, stride, ptr)) {
1328 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1329 "client side arrays are not allowed in vertex array objects.");
1330 return;
1332 if (!support_client_side_arrays_ || bound_array_buffer_id_ != 0) {
1333 // Only report NON client side buffers to the service.
1334 if (!ValidateOffset("glVertexAttribPointer",
1335 reinterpret_cast<GLintptr>(ptr))) {
1336 return;
1338 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1339 ToGLuint(ptr));
1341 CheckGLError();
1344 void GLES2Implementation::VertexAttribDivisorANGLE(
1345 GLuint index, GLuint divisor) {
1346 GPU_CLIENT_SINGLE_THREAD_CHECK();
1347 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1348 << index << ", "
1349 << divisor << ") ");
1350 // Record the info on the client side.
1351 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1352 helper_->VertexAttribDivisorANGLE(index, divisor);
1353 CheckGLError();
1356 void GLES2Implementation::BufferDataHelper(
1357 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1358 if (!ValidateSize("glBufferData", size))
1359 return;
1361 #if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
1362 // Do not upload uninitialized data. Even if it's not a bug, it can cause a
1363 // bogus MSan report during a readback later. This is because MSan doesn't
1364 // understand shared memory and would assume we were reading back the same
1365 // unintialized data.
1366 if (data) __msan_check_mem_is_initialized(data, size);
1367 #endif
1369 GLuint buffer_id;
1370 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1371 if (!buffer_id) {
1372 return;
1375 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1376 if (buffer)
1377 RemoveTransferBuffer(buffer);
1379 // Create new buffer.
1380 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1381 DCHECK(buffer);
1382 if (buffer->address() && data)
1383 memcpy(buffer->address(), data, size);
1384 return;
1387 if (size == 0) {
1388 return;
1391 // If there is no data just send BufferData
1392 if (!data) {
1393 helper_->BufferData(target, size, 0, 0, usage);
1394 return;
1397 // See if we can send all at once.
1398 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1399 if (!buffer.valid()) {
1400 return;
1403 if (buffer.size() >= static_cast<unsigned int>(size)) {
1404 memcpy(buffer.address(), data, size);
1405 helper_->BufferData(
1406 target,
1407 size,
1408 buffer.shm_id(),
1409 buffer.offset(),
1410 usage);
1411 return;
1414 // Make the buffer with BufferData then send via BufferSubData
1415 helper_->BufferData(target, size, 0, 0, usage);
1416 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1417 CheckGLError();
1420 void GLES2Implementation::BufferData(
1421 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1422 GPU_CLIENT_SINGLE_THREAD_CHECK();
1423 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1424 << GLES2Util::GetStringBufferTarget(target) << ", "
1425 << size << ", "
1426 << static_cast<const void*>(data) << ", "
1427 << GLES2Util::GetStringBufferUsage(usage) << ")");
1428 BufferDataHelper(target, size, data, usage);
1429 CheckGLError();
1432 void GLES2Implementation::BufferSubDataHelper(
1433 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1434 if (size == 0) {
1435 return;
1438 if (!ValidateSize("glBufferSubData", size) ||
1439 !ValidateOffset("glBufferSubData", offset)) {
1440 return;
1443 GLuint buffer_id;
1444 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1445 if (!buffer_id) {
1446 return;
1448 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1449 if (!buffer) {
1450 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1451 return;
1454 int32 end = 0;
1455 int32 buffer_size = buffer->size();
1456 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1457 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1458 return;
1461 if (buffer->address() && data)
1462 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1463 return;
1466 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1467 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1470 void GLES2Implementation::BufferSubDataHelperImpl(
1471 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1472 ScopedTransferBufferPtr* buffer) {
1473 DCHECK(buffer);
1474 DCHECK_GT(size, 0);
1476 const int8* source = static_cast<const int8*>(data);
1477 while (size) {
1478 if (!buffer->valid() || buffer->size() == 0) {
1479 buffer->Reset(size);
1480 if (!buffer->valid()) {
1481 return;
1484 memcpy(buffer->address(), source, buffer->size());
1485 helper_->BufferSubData(
1486 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1487 offset += buffer->size();
1488 source += buffer->size();
1489 size -= buffer->size();
1490 buffer->Release();
1494 void GLES2Implementation::BufferSubData(
1495 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1496 GPU_CLIENT_SINGLE_THREAD_CHECK();
1497 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1498 << GLES2Util::GetStringBufferTarget(target) << ", "
1499 << offset << ", " << size << ", "
1500 << static_cast<const void*>(data) << ")");
1501 BufferSubDataHelper(target, offset, size, data);
1502 CheckGLError();
1505 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
1506 int32 token = buffer->last_usage_token();
1507 uint32 async_token = buffer->last_async_upload_token();
1509 if (async_token) {
1510 if (HasAsyncUploadTokenPassed(async_token)) {
1511 buffer_tracker_->Free(buffer);
1512 } else {
1513 detached_async_upload_memory_.push_back(
1514 std::make_pair(buffer->address(), async_token));
1515 buffer_tracker_->Unmanage(buffer);
1517 } else if (token) {
1518 if (helper_->HasTokenPassed(token))
1519 buffer_tracker_->Free(buffer);
1520 else
1521 buffer_tracker_->FreePendingToken(buffer, token);
1522 } else {
1523 buffer_tracker_->Free(buffer);
1526 buffer_tracker_->RemoveBuffer(buffer->id());
1529 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1530 GLenum target,
1531 const char* function_name,
1532 GLuint* buffer_id) {
1533 *buffer_id = 0;
1535 switch (target) {
1536 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1537 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1538 break;
1539 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1540 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1541 break;
1542 default:
1543 // Unknown target
1544 return false;
1546 if (!*buffer_id) {
1547 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1549 return true;
1552 BufferTracker::Buffer*
1553 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1554 GLuint buffer_id,
1555 const char* function_name,
1556 GLuint offset, GLsizei size) {
1557 DCHECK(buffer_id);
1558 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1559 if (!buffer) {
1560 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1561 return NULL;
1563 if (buffer->mapped()) {
1564 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1565 return NULL;
1567 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1568 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1569 return NULL;
1571 return buffer;
1574 void GLES2Implementation::CompressedTexImage2D(
1575 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1576 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1577 GPU_CLIENT_SINGLE_THREAD_CHECK();
1578 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1579 << GLES2Util::GetStringTextureTarget(target) << ", "
1580 << level << ", "
1581 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1582 << width << ", " << height << ", " << border << ", "
1583 << image_size << ", "
1584 << static_cast<const void*>(data) << ")");
1585 if (width < 0 || height < 0 || level < 0) {
1586 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1587 return;
1589 if (border != 0) {
1590 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "border != 0");
1591 return;
1593 if (height == 0 || width == 0) {
1594 return;
1596 // If there's a pixel unpack buffer bound use it when issuing
1597 // CompressedTexImage2D.
1598 if (bound_pixel_unpack_transfer_buffer_id_) {
1599 GLuint offset = ToGLuint(data);
1600 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1601 bound_pixel_unpack_transfer_buffer_id_,
1602 "glCompressedTexImage2D", offset, image_size);
1603 if (buffer && buffer->shm_id() != -1) {
1604 helper_->CompressedTexImage2D(
1605 target, level, internalformat, width, height, image_size,
1606 buffer->shm_id(), buffer->shm_offset() + offset);
1607 buffer->set_last_usage_token(helper_->InsertToken());
1609 return;
1611 SetBucketContents(kResultBucketId, data, image_size);
1612 helper_->CompressedTexImage2DBucket(
1613 target, level, internalformat, width, height, kResultBucketId);
1614 // Free the bucket. This is not required but it does free up the memory.
1615 // and we don't have to wait for the result so from the client's perspective
1616 // it's cheap.
1617 helper_->SetBucketSize(kResultBucketId, 0);
1618 CheckGLError();
1621 void GLES2Implementation::CompressedTexSubImage2D(
1622 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1623 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1624 GPU_CLIENT_SINGLE_THREAD_CHECK();
1625 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1626 << GLES2Util::GetStringTextureTarget(target) << ", "
1627 << level << ", "
1628 << xoffset << ", " << yoffset << ", "
1629 << width << ", " << height << ", "
1630 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1631 << image_size << ", "
1632 << static_cast<const void*>(data) << ")");
1633 if (width < 0 || height < 0 || level < 0) {
1634 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1635 return;
1637 // If there's a pixel unpack buffer bound use it when issuing
1638 // CompressedTexSubImage2D.
1639 if (bound_pixel_unpack_transfer_buffer_id_) {
1640 GLuint offset = ToGLuint(data);
1641 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1642 bound_pixel_unpack_transfer_buffer_id_,
1643 "glCompressedTexSubImage2D", offset, image_size);
1644 if (buffer && buffer->shm_id() != -1) {
1645 helper_->CompressedTexSubImage2D(
1646 target, level, xoffset, yoffset, width, height, format, image_size,
1647 buffer->shm_id(), buffer->shm_offset() + offset);
1648 buffer->set_last_usage_token(helper_->InsertToken());
1649 CheckGLError();
1651 return;
1653 SetBucketContents(kResultBucketId, data, image_size);
1654 helper_->CompressedTexSubImage2DBucket(
1655 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1656 // Free the bucket. This is not required but it does free up the memory.
1657 // and we don't have to wait for the result so from the client's perspective
1658 // it's cheap.
1659 helper_->SetBucketSize(kResultBucketId, 0);
1660 CheckGLError();
1663 namespace {
1665 void CopyRectToBuffer(
1666 const void* pixels,
1667 uint32 height,
1668 uint32 unpadded_row_size,
1669 uint32 pixels_padded_row_size,
1670 bool flip_y,
1671 void* buffer,
1672 uint32 buffer_padded_row_size) {
1673 const int8* source = static_cast<const int8*>(pixels);
1674 int8* dest = static_cast<int8*>(buffer);
1675 if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
1676 if (flip_y) {
1677 dest += buffer_padded_row_size * (height - 1);
1679 // the last row is copied unpadded at the end
1680 for (; height > 1; --height) {
1681 memcpy(dest, source, buffer_padded_row_size);
1682 if (flip_y) {
1683 dest -= buffer_padded_row_size;
1684 } else {
1685 dest += buffer_padded_row_size;
1687 source += pixels_padded_row_size;
1689 memcpy(dest, source, unpadded_row_size);
1690 } else {
1691 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
1692 memcpy(dest, source, size);
1696 } // anonymous namespace
1698 void GLES2Implementation::TexImage2D(
1699 GLenum target, GLint level, GLint internalformat, GLsizei width,
1700 GLsizei height, GLint border, GLenum format, GLenum type,
1701 const void* pixels) {
1702 GPU_CLIENT_SINGLE_THREAD_CHECK();
1703 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1704 << GLES2Util::GetStringTextureTarget(target) << ", "
1705 << level << ", "
1706 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1707 << width << ", " << height << ", " << border << ", "
1708 << GLES2Util::GetStringTextureFormat(format) << ", "
1709 << GLES2Util::GetStringPixelType(type) << ", "
1710 << static_cast<const void*>(pixels) << ")");
1711 if (level < 0 || height < 0 || width < 0) {
1712 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
1713 return;
1715 if (border != 0) {
1716 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
1717 return;
1719 uint32 size;
1720 uint32 unpadded_row_size;
1721 uint32 padded_row_size;
1722 if (!GLES2Util::ComputeImageDataSizes(
1723 width, height, 1, format, type, unpack_alignment_, &size,
1724 &unpadded_row_size, &padded_row_size)) {
1725 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
1726 return;
1729 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1730 if (bound_pixel_unpack_transfer_buffer_id_) {
1731 GLuint offset = ToGLuint(pixels);
1732 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1733 bound_pixel_unpack_transfer_buffer_id_,
1734 "glTexImage2D", offset, size);
1735 if (buffer && buffer->shm_id() != -1) {
1736 helper_->TexImage2D(
1737 target, level, internalformat, width, height, format, type,
1738 buffer->shm_id(), buffer->shm_offset() + offset);
1739 buffer->set_last_usage_token(helper_->InsertToken());
1740 CheckGLError();
1742 return;
1745 // If there's no data just issue TexImage2D
1746 if (!pixels) {
1747 helper_->TexImage2D(
1748 target, level, internalformat, width, height, format, type,
1749 0, 0);
1750 CheckGLError();
1751 return;
1754 // compute the advance bytes per row for the src pixels
1755 uint32 src_padded_row_size;
1756 if (unpack_row_length_ > 0) {
1757 if (!GLES2Util::ComputeImagePaddedRowSize(
1758 unpack_row_length_, format, type, unpack_alignment_,
1759 &src_padded_row_size)) {
1760 SetGLError(
1761 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1762 return;
1764 } else {
1765 src_padded_row_size = padded_row_size;
1768 // advance pixels pointer past the skip rows and skip pixels
1769 pixels = reinterpret_cast<const int8*>(pixels) +
1770 unpack_skip_rows_ * src_padded_row_size;
1771 if (unpack_skip_pixels_) {
1772 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1773 pixels = reinterpret_cast<const int8*>(pixels) +
1774 unpack_skip_pixels_ * group_size;
1777 // Check if we can send it all at once.
1778 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1779 if (!buffer.valid()) {
1780 return;
1783 if (buffer.size() >= size) {
1784 CopyRectToBuffer(
1785 pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
1786 buffer.address(), padded_row_size);
1787 helper_->TexImage2D(
1788 target, level, internalformat, width, height, format, type,
1789 buffer.shm_id(), buffer.offset());
1790 CheckGLError();
1791 return;
1794 // No, so send it using TexSubImage2D.
1795 helper_->TexImage2D(
1796 target, level, internalformat, width, height, format, type,
1797 0, 0);
1798 TexSubImage2DImpl(
1799 target, level, 0, 0, width, height, format, type, unpadded_row_size,
1800 pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
1801 CheckGLError();
1804 void GLES2Implementation::TexImage3D(
1805 GLenum target, GLint level, GLint internalformat, GLsizei width,
1806 GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type,
1807 const void* pixels) {
1808 GPU_CLIENT_SINGLE_THREAD_CHECK();
1809 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D("
1810 << GLES2Util::GetStringTextureTarget(target) << ", "
1811 << level << ", "
1812 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1813 << width << ", " << height << ", " << depth << ", " << border << ", "
1814 << GLES2Util::GetStringTextureFormat(format) << ", "
1815 << GLES2Util::GetStringPixelType(type) << ", "
1816 << static_cast<const void*>(pixels) << ")");
1817 if (level < 0 || height < 0 || width < 0 || depth < 0) {
1818 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "dimension < 0");
1819 return;
1821 if (border != 0) {
1822 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "border != 0");
1823 return;
1825 uint32 size;
1826 uint32 unpadded_row_size;
1827 uint32 padded_row_size;
1828 if (!GLES2Util::ComputeImageDataSizes(
1829 width, height, depth, format, type, unpack_alignment_, &size,
1830 &unpadded_row_size, &padded_row_size)) {
1831 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large");
1832 return;
1835 // If there's a pixel unpack buffer bound use it when issuing TexImage3D.
1836 if (bound_pixel_unpack_transfer_buffer_id_) {
1837 GLuint offset = ToGLuint(pixels);
1838 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1839 bound_pixel_unpack_transfer_buffer_id_,
1840 "glTexImage3D", offset, size);
1841 if (buffer && buffer->shm_id() != -1) {
1842 helper_->TexImage3D(
1843 target, level, internalformat, width, height, depth, format, type,
1844 buffer->shm_id(), buffer->shm_offset() + offset);
1845 buffer->set_last_usage_token(helper_->InsertToken());
1846 CheckGLError();
1848 return;
1851 // If there's no data just issue TexImage3D
1852 if (!pixels) {
1853 helper_->TexImage3D(
1854 target, level, internalformat, width, height, depth, format, type,
1855 0, 0);
1856 CheckGLError();
1857 return;
1860 // compute the advance bytes per row for the src pixels
1861 uint32 src_padded_row_size;
1862 if (unpack_row_length_ > 0) {
1863 if (!GLES2Util::ComputeImagePaddedRowSize(
1864 unpack_row_length_, format, type, unpack_alignment_,
1865 &src_padded_row_size)) {
1866 SetGLError(
1867 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
1868 return;
1870 } else {
1871 src_padded_row_size = padded_row_size;
1873 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
1875 // advance pixels pointer past the skip images/rows/pixels
1876 pixels = reinterpret_cast<const int8*>(pixels) +
1877 unpack_skip_images_ * src_padded_row_size * src_height +
1878 unpack_skip_rows_ * src_padded_row_size;
1879 if (unpack_skip_pixels_) {
1880 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1881 pixels = reinterpret_cast<const int8*>(pixels) +
1882 unpack_skip_pixels_ * group_size;
1885 // Check if we can send it all at once.
1886 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1887 if (!buffer.valid()) {
1888 return;
1891 if (buffer.size() >= size) {
1892 void* buffer_pointer = buffer.address();
1893 for (GLsizei z = 0; z < depth; ++z) {
1894 // Only the last row of the last image is unpadded.
1895 uint32 src_unpadded_row_size =
1896 (z == depth - 1) ? unpadded_row_size : src_padded_row_size;
1897 // TODO(zmo): Ignore flip_y flag for now.
1898 CopyRectToBuffer(
1899 pixels, height, src_unpadded_row_size, src_padded_row_size, false,
1900 buffer_pointer, padded_row_size);
1901 pixels = reinterpret_cast<const int8*>(pixels) +
1902 src_padded_row_size * src_height;
1903 buffer_pointer = reinterpret_cast<int8*>(buffer_pointer) +
1904 padded_row_size * height;
1906 helper_->TexImage3D(
1907 target, level, internalformat, width, height, depth, format, type,
1908 buffer.shm_id(), buffer.offset());
1909 CheckGLError();
1910 return;
1913 // No, so send it using TexSubImage3D.
1914 helper_->TexImage3D(
1915 target, level, internalformat, width, height, depth, format, type,
1916 0, 0);
1917 TexSubImage3DImpl(
1918 target, level, 0, 0, 0, width, height, depth, format, type,
1919 unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &buffer,
1920 padded_row_size);
1921 CheckGLError();
1924 void GLES2Implementation::TexSubImage2D(
1925 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1926 GLsizei height, GLenum format, GLenum type, const void* pixels) {
1927 GPU_CLIENT_SINGLE_THREAD_CHECK();
1928 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1929 << GLES2Util::GetStringTextureTarget(target) << ", "
1930 << level << ", "
1931 << xoffset << ", " << yoffset << ", "
1932 << width << ", " << height << ", "
1933 << GLES2Util::GetStringTextureFormat(format) << ", "
1934 << GLES2Util::GetStringPixelType(type) << ", "
1935 << static_cast<const void*>(pixels) << ")");
1937 if (level < 0 || height < 0 || width < 0) {
1938 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
1939 return;
1941 if (height == 0 || width == 0) {
1942 return;
1945 uint32 temp_size;
1946 uint32 unpadded_row_size;
1947 uint32 padded_row_size;
1948 if (!GLES2Util::ComputeImageDataSizes(
1949 width, height, 1, format, type, unpack_alignment_, &temp_size,
1950 &unpadded_row_size, &padded_row_size)) {
1951 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
1952 return;
1955 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1956 if (bound_pixel_unpack_transfer_buffer_id_) {
1957 GLuint offset = ToGLuint(pixels);
1958 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1959 bound_pixel_unpack_transfer_buffer_id_,
1960 "glTexSubImage2D", offset, temp_size);
1961 if (buffer && buffer->shm_id() != -1) {
1962 helper_->TexSubImage2D(
1963 target, level, xoffset, yoffset, width, height, format, type,
1964 buffer->shm_id(), buffer->shm_offset() + offset, false);
1965 buffer->set_last_usage_token(helper_->InsertToken());
1966 CheckGLError();
1968 return;
1971 // compute the advance bytes per row for the src pixels
1972 uint32 src_padded_row_size;
1973 if (unpack_row_length_ > 0) {
1974 if (!GLES2Util::ComputeImagePaddedRowSize(
1975 unpack_row_length_, format, type, unpack_alignment_,
1976 &src_padded_row_size)) {
1977 SetGLError(
1978 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1979 return;
1981 } else {
1982 src_padded_row_size = padded_row_size;
1985 // advance pixels pointer past the skip rows and skip pixels
1986 pixels = reinterpret_cast<const int8*>(pixels) +
1987 unpack_skip_rows_ * src_padded_row_size;
1988 if (unpack_skip_pixels_) {
1989 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1990 pixels = reinterpret_cast<const int8*>(pixels) +
1991 unpack_skip_pixels_ * group_size;
1994 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
1995 TexSubImage2DImpl(
1996 target, level, xoffset, yoffset, width, height, format, type,
1997 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
1998 padded_row_size);
1999 CheckGLError();
2002 void GLES2Implementation::TexSubImage3D(
2003 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2004 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2005 const void* pixels) {
2006 GPU_CLIENT_SINGLE_THREAD_CHECK();
2007 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D("
2008 << GLES2Util::GetStringTextureTarget(target) << ", "
2009 << level << ", "
2010 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2011 << width << ", " << height << ", " << depth << ", "
2012 << GLES2Util::GetStringTextureFormat(format) << ", "
2013 << GLES2Util::GetStringPixelType(type) << ", "
2014 << static_cast<const void*>(pixels) << ")");
2016 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2017 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "dimension < 0");
2018 return;
2020 if (height == 0 || width == 0 || depth == 0) {
2021 return;
2024 uint32 temp_size;
2025 uint32 unpadded_row_size;
2026 uint32 padded_row_size;
2027 if (!GLES2Util::ComputeImageDataSizes(
2028 width, height, depth, format, type, unpack_alignment_, &temp_size,
2029 &unpadded_row_size, &padded_row_size)) {
2030 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "size to large");
2031 return;
2034 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2035 if (bound_pixel_unpack_transfer_buffer_id_) {
2036 GLuint offset = ToGLuint(pixels);
2037 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2038 bound_pixel_unpack_transfer_buffer_id_,
2039 "glTexSubImage3D", offset, temp_size);
2040 if (buffer && buffer->shm_id() != -1) {
2041 helper_->TexSubImage3D(
2042 target, level, xoffset, yoffset, zoffset, width, height, depth,
2043 format, type, buffer->shm_id(), buffer->shm_offset() + offset, false);
2044 buffer->set_last_usage_token(helper_->InsertToken());
2045 CheckGLError();
2047 return;
2050 // compute the advance bytes per row for the src pixels
2051 uint32 src_padded_row_size;
2052 if (unpack_row_length_ > 0) {
2053 if (!GLES2Util::ComputeImagePaddedRowSize(
2054 unpack_row_length_, format, type, unpack_alignment_,
2055 &src_padded_row_size)) {
2056 SetGLError(
2057 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2058 return;
2060 } else {
2061 src_padded_row_size = padded_row_size;
2063 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2065 // advance pixels pointer past the skip images/rows/pixels
2066 pixels = reinterpret_cast<const int8*>(pixels) +
2067 unpack_skip_images_ * src_padded_row_size * src_height +
2068 unpack_skip_rows_ * src_padded_row_size;
2069 if (unpack_skip_pixels_) {
2070 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2071 pixels = reinterpret_cast<const int8*>(pixels) +
2072 unpack_skip_pixels_ * group_size;
2075 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2076 TexSubImage3DImpl(
2077 target, level, xoffset, yoffset, zoffset, width, height, depth,
2078 format, type, unpadded_row_size, pixels, src_padded_row_size, GL_FALSE,
2079 &buffer, padded_row_size);
2080 CheckGLError();
2083 static GLint ComputeNumRowsThatFitInBuffer(
2084 uint32 padded_row_size, uint32 unpadded_row_size,
2085 unsigned int size, GLsizei remaining_rows) {
2086 DCHECK_GE(unpadded_row_size, 0u);
2087 if (padded_row_size == 0) {
2088 return 1;
2090 GLint num_rows = size / padded_row_size;
2091 if (num_rows + 1 == remaining_rows &&
2092 size - num_rows * padded_row_size >= unpadded_row_size) {
2093 num_rows++;
2095 return num_rows;
2098 void GLES2Implementation::TexSubImage2DImpl(
2099 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2100 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
2101 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
2102 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
2103 DCHECK(buffer);
2104 DCHECK_GE(level, 0);
2105 DCHECK_GT(height, 0);
2106 DCHECK_GT(width, 0);
2108 const int8* source = reinterpret_cast<const int8*>(pixels);
2109 GLint original_yoffset = yoffset;
2110 // Transfer by rows.
2111 while (height) {
2112 unsigned int desired_size =
2113 buffer_padded_row_size * (height - 1) + unpadded_row_size;
2114 if (!buffer->valid() || buffer->size() == 0) {
2115 buffer->Reset(desired_size);
2116 if (!buffer->valid()) {
2117 return;
2121 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2122 buffer_padded_row_size, unpadded_row_size, buffer->size(), height);
2123 num_rows = std::min(num_rows, height);
2124 CopyRectToBuffer(
2125 source, num_rows, unpadded_row_size, pixels_padded_row_size,
2126 unpack_flip_y_, buffer->address(), buffer_padded_row_size);
2127 GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
2128 helper_->TexSubImage2D(
2129 target, level, xoffset, y, width, num_rows, format, type,
2130 buffer->shm_id(), buffer->offset(), internal);
2131 buffer->Release();
2132 yoffset += num_rows;
2133 source += num_rows * pixels_padded_row_size;
2134 height -= num_rows;
2138 void GLES2Implementation::TexSubImage3DImpl(
2139 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei zoffset,
2140 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2141 uint32 unpadded_row_size, const void* pixels, uint32 pixels_padded_row_size,
2142 GLboolean internal, ScopedTransferBufferPtr* buffer,
2143 uint32 buffer_padded_row_size) {
2144 DCHECK(buffer);
2145 DCHECK_GE(level, 0);
2146 DCHECK_GT(height, 0);
2147 DCHECK_GT(width, 0);
2148 DCHECK_GT(depth, 0);
2149 const int8* source = reinterpret_cast<const int8*>(pixels);
2150 GLsizei total_rows = height * depth;
2151 GLint row_index = 0, depth_index = 0;
2152 while (total_rows) {
2153 // Each time, we either copy one or more images, or copy one or more rows
2154 // within a single image, depending on the buffer size limit.
2155 GLsizei max_rows;
2156 unsigned int desired_size;
2157 if (row_index > 0) {
2158 // We are in the middle of an image. Send the remaining of the image.
2159 max_rows = height - row_index;
2160 if (total_rows <= height) {
2161 // Last image, so last row is unpadded.
2162 desired_size = buffer_padded_row_size * (max_rows - 1) +
2163 unpadded_row_size;
2164 } else {
2165 desired_size = buffer_padded_row_size * max_rows;
2167 } else {
2168 // Send all the remaining data if possible.
2169 max_rows = total_rows;
2170 desired_size =
2171 buffer_padded_row_size * (max_rows - 1) + unpadded_row_size;
2173 if (!buffer->valid() || buffer->size() == 0) {
2174 buffer->Reset(desired_size);
2175 if (!buffer->valid()) {
2176 return;
2179 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2180 buffer_padded_row_size, unpadded_row_size, buffer->size(), total_rows);
2181 num_rows = std::min(num_rows, max_rows);
2182 GLint num_images = num_rows / height;
2183 GLsizei my_height, my_depth;
2184 if (num_images > 0) {
2185 num_rows = num_images * height;
2186 my_height = height;
2187 my_depth = num_images;
2188 } else {
2189 my_height = num_rows;
2190 my_depth = 1;
2193 // TODO(zmo): Ignore flip_y flag for now.
2194 if (num_images > 0) {
2195 int8* buffer_pointer = reinterpret_cast<int8*>(buffer->address());
2196 uint32 src_height =
2197 unpack_image_height_ > 0 ? unpack_image_height_ : height;
2198 uint32 image_size_dst = buffer_padded_row_size * height;
2199 uint32 image_size_src = pixels_padded_row_size * src_height;
2200 for (GLint ii = 0; ii < num_images; ++ii) {
2201 uint32 my_unpadded_row_size;
2202 if (total_rows == num_rows && ii + 1 == num_images)
2203 my_unpadded_row_size = unpadded_row_size;
2204 else
2205 my_unpadded_row_size = pixels_padded_row_size;
2206 CopyRectToBuffer(
2207 source + ii * image_size_src, my_height, my_unpadded_row_size,
2208 pixels_padded_row_size, false, buffer_pointer + ii * image_size_dst,
2209 buffer_padded_row_size);
2211 } else {
2212 uint32 my_unpadded_row_size;
2213 if (total_rows == num_rows)
2214 my_unpadded_row_size = unpadded_row_size;
2215 else
2216 my_unpadded_row_size = pixels_padded_row_size;
2217 CopyRectToBuffer(
2218 source, my_height, my_unpadded_row_size, pixels_padded_row_size,
2219 false, buffer->address(), buffer_padded_row_size);
2221 helper_->TexSubImage3D(
2222 target, level, xoffset, yoffset + row_index, zoffset + depth_index,
2223 width, my_height, my_depth,
2224 format, type, buffer->shm_id(), buffer->offset(), internal);
2225 buffer->Release();
2227 total_rows -= num_rows;
2228 if (total_rows > 0) {
2229 GLint num_image_paddings;
2230 if (num_images > 0) {
2231 DCHECK_EQ(row_index, 0);
2232 depth_index += num_images;
2233 num_image_paddings = num_images;
2234 } else {
2235 row_index = (row_index + my_height) % height;
2236 num_image_paddings = 0;
2237 if (my_height > 0 && row_index == 0) {
2238 depth_index++;
2239 num_image_paddings++;
2242 source += num_rows * pixels_padded_row_size;
2243 if (unpack_image_height_ > height && num_image_paddings > 0) {
2244 source += num_image_paddings * (unpack_image_height_ - height) *
2245 pixels_padded_row_size;
2251 bool GLES2Implementation::GetActiveAttribHelper(
2252 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2253 GLenum* type, char* name) {
2254 // Clear the bucket so if the command fails nothing will be in it.
2255 helper_->SetBucketSize(kResultBucketId, 0);
2256 typedef cmds::GetActiveAttrib::Result Result;
2257 Result* result = GetResultAs<Result*>();
2258 if (!result) {
2259 return false;
2261 // Set as failed so if the command fails we'll recover.
2262 result->success = false;
2263 helper_->GetActiveAttrib(program, index, kResultBucketId,
2264 GetResultShmId(), GetResultShmOffset());
2265 WaitForCmd();
2266 if (result->success) {
2267 if (size) {
2268 *size = result->size;
2270 if (type) {
2271 *type = result->type;
2273 if (length || name) {
2274 std::vector<int8> str;
2275 GetBucketContents(kResultBucketId, &str);
2276 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2277 std::max(static_cast<size_t>(0),
2278 str.size() - 1));
2279 if (length) {
2280 *length = max_size;
2282 if (name && bufsize > 0) {
2283 memcpy(name, &str[0], max_size);
2284 name[max_size] = '\0';
2288 return result->success != 0;
2291 void GLES2Implementation::GetActiveAttrib(
2292 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2293 GLenum* type, char* name) {
2294 GPU_CLIENT_SINGLE_THREAD_CHECK();
2295 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2296 << program << ", " << index << ", " << bufsize << ", "
2297 << static_cast<const void*>(length) << ", "
2298 << static_cast<const void*>(size) << ", "
2299 << static_cast<const void*>(type) << ", "
2300 << static_cast<const void*>(name) << ", ");
2301 if (bufsize < 0) {
2302 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
2303 return;
2305 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2306 bool success = share_group_->program_info_manager()->GetActiveAttrib(
2307 this, program, index, bufsize, length, size, type, name);
2308 if (success) {
2309 if (size) {
2310 GPU_CLIENT_LOG(" size: " << *size);
2312 if (type) {
2313 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2315 if (name) {
2316 GPU_CLIENT_LOG(" name: " << name);
2319 CheckGLError();
2322 bool GLES2Implementation::GetActiveUniformHelper(
2323 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2324 GLenum* type, char* name) {
2325 // Clear the bucket so if the command fails nothing will be in it.
2326 helper_->SetBucketSize(kResultBucketId, 0);
2327 typedef cmds::GetActiveUniform::Result Result;
2328 Result* result = GetResultAs<Result*>();
2329 if (!result) {
2330 return false;
2332 // Set as failed so if the command fails we'll recover.
2333 result->success = false;
2334 helper_->GetActiveUniform(program, index, kResultBucketId,
2335 GetResultShmId(), GetResultShmOffset());
2336 WaitForCmd();
2337 if (result->success) {
2338 if (size) {
2339 *size = result->size;
2341 if (type) {
2342 *type = result->type;
2344 if (length || name) {
2345 std::vector<int8> str;
2346 GetBucketContents(kResultBucketId, &str);
2347 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2348 std::max(static_cast<size_t>(0),
2349 str.size() - 1));
2350 if (length) {
2351 *length = max_size;
2353 if (name && bufsize > 0) {
2354 memcpy(name, &str[0], max_size);
2355 name[max_size] = '\0';
2359 return result->success != 0;
2362 void GLES2Implementation::GetActiveUniform(
2363 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2364 GLenum* type, char* name) {
2365 GPU_CLIENT_SINGLE_THREAD_CHECK();
2366 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2367 << program << ", " << index << ", " << bufsize << ", "
2368 << static_cast<const void*>(length) << ", "
2369 << static_cast<const void*>(size) << ", "
2370 << static_cast<const void*>(type) << ", "
2371 << static_cast<const void*>(name) << ", ");
2372 if (bufsize < 0) {
2373 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2374 return;
2376 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2377 bool success = share_group_->program_info_manager()->GetActiveUniform(
2378 this, program, index, bufsize, length, size, type, name);
2379 if (success) {
2380 if (size) {
2381 GPU_CLIENT_LOG(" size: " << *size);
2383 if (type) {
2384 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2386 if (name) {
2387 GPU_CLIENT_LOG(" name: " << name);
2390 CheckGLError();
2393 bool GLES2Implementation::GetActiveUniformBlockNameHelper(
2394 GLuint program, GLuint index, GLsizei bufsize,
2395 GLsizei* length, char* name) {
2396 DCHECK_LE(0, bufsize);
2397 // Clear the bucket so if the command fails nothing will be in it.
2398 helper_->SetBucketSize(kResultBucketId, 0);
2399 typedef cmds::GetActiveUniformBlockName::Result Result;
2400 Result* result = GetResultAs<Result*>();
2401 if (!result) {
2402 return false;
2404 // Set as failed so if the command fails we'll recover.
2405 *result = 0;
2406 helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
2407 GetResultShmId(), GetResultShmOffset());
2408 WaitForCmd();
2409 if (*result) {
2410 if (bufsize == 0) {
2411 if (length) {
2412 *length = 0;
2414 } else if (length || name) {
2415 std::vector<int8> str;
2416 GetBucketContents(kResultBucketId, &str);
2417 DCHECK(str.size() > 0);
2418 GLsizei max_size =
2419 std::min(bufsize, static_cast<GLsizei>(str.size())) - 1;
2420 if (length) {
2421 *length = max_size;
2423 if (name) {
2424 memcpy(name, &str[0], max_size);
2425 name[max_size] = '\0';
2429 return *result != 0;
2432 void GLES2Implementation::GetActiveUniformBlockName(
2433 GLuint program, GLuint index, GLsizei bufsize,
2434 GLsizei* length, char* name) {
2435 GPU_CLIENT_SINGLE_THREAD_CHECK();
2436 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
2437 << program << ", " << index << ", " << bufsize << ", "
2438 << static_cast<const void*>(length) << ", "
2439 << static_cast<const void*>(name) << ")");
2440 if (bufsize < 0) {
2441 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformBlockName", "bufsize < 0");
2442 return;
2444 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockName");
2445 bool success =
2446 share_group_->program_info_manager()->GetActiveUniformBlockName(
2447 this, program, index, bufsize, length, name);
2448 if (success) {
2449 if (name) {
2450 GPU_CLIENT_LOG(" name: " << name);
2453 CheckGLError();
2456 bool GLES2Implementation::GetActiveUniformBlockivHelper(
2457 GLuint program, GLuint index, GLenum pname, GLint* params) {
2458 typedef cmds::GetActiveUniformBlockiv::Result Result;
2459 Result* result = GetResultAs<Result*>();
2460 if (!result) {
2461 return false;
2463 result->SetNumResults(0);
2464 helper_->GetActiveUniformBlockiv(
2465 program, index, pname, GetResultShmId(), GetResultShmOffset());
2466 WaitForCmd();
2467 if (result->GetNumResults() > 0) {
2468 if (params) {
2469 result->CopyResult(params);
2471 GPU_CLIENT_LOG_CODE_BLOCK({
2472 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
2473 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2476 return true;
2478 return false;
2481 void GLES2Implementation::GetActiveUniformBlockiv(
2482 GLuint program, GLuint index, GLenum pname, GLint* params) {
2483 GPU_CLIENT_SINGLE_THREAD_CHECK();
2484 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
2485 << program << ", " << index << ", "
2486 << GLES2Util::GetStringUniformBlockParameter(pname) << ", "
2487 << static_cast<const void*>(params) << ")");
2488 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
2489 bool success =
2490 share_group_->program_info_manager()->GetActiveUniformBlockiv(
2491 this, program, index, pname, params);
2492 if (success) {
2493 if (params) {
2494 // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
2495 // be more than one value returned in params.
2496 GPU_CLIENT_LOG(" params: " << params[0]);
2499 CheckGLError();
2502 bool GLES2Implementation::GetActiveUniformsivHelper(
2503 GLuint program, GLsizei count, const GLuint* indices,
2504 GLenum pname, GLint* params) {
2505 typedef cmds::GetActiveUniformsiv::Result Result;
2506 Result* result = GetResultAs<Result*>();
2507 if (!result) {
2508 return false;
2510 result->SetNumResults(0);
2511 base::CheckedNumeric<size_t> bytes = static_cast<size_t>(count);
2512 bytes *= sizeof(GLuint);
2513 if (!bytes.IsValid()) {
2514 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count overflow");
2515 return false;
2517 SetBucketContents(kResultBucketId, indices, bytes.ValueOrDefault(0));
2518 helper_->GetActiveUniformsiv(
2519 program, kResultBucketId, pname, GetResultShmId(), GetResultShmOffset());
2520 WaitForCmd();
2521 bool success = result->GetNumResults() == count;
2522 if (success) {
2523 if (params) {
2524 result->CopyResult(params);
2526 GPU_CLIENT_LOG_CODE_BLOCK({
2527 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
2528 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2532 helper_->SetBucketSize(kResultBucketId, 0);
2533 return success;
2536 void GLES2Implementation::GetActiveUniformsiv(
2537 GLuint program, GLsizei count, const GLuint* indices,
2538 GLenum pname, GLint* params) {
2539 GPU_CLIENT_SINGLE_THREAD_CHECK();
2540 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv("
2541 << program << ", " << count << ", "
2542 << static_cast<const void*>(indices) << ", "
2543 << GLES2Util::GetStringUniformParameter(pname) << ", "
2544 << static_cast<const void*>(params) << ")");
2545 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
2546 if (count < 0) {
2547 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count < 0");
2548 return;
2550 bool success = share_group_->program_info_manager()->GetActiveUniformsiv(
2551 this, program, count, indices, pname, params);
2552 if (success) {
2553 if (params) {
2554 GPU_CLIENT_LOG_CODE_BLOCK({
2555 for (GLsizei ii = 0; ii < count; ++ii) {
2556 GPU_CLIENT_LOG(" " << ii << ": " << params[ii]);
2561 CheckGLError();
2564 void GLES2Implementation::GetAttachedShaders(
2565 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
2566 GPU_CLIENT_SINGLE_THREAD_CHECK();
2567 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2568 << program << ", " << maxcount << ", "
2569 << static_cast<const void*>(count) << ", "
2570 << static_cast<const void*>(shaders) << ", ");
2571 if (maxcount < 0) {
2572 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
2573 return;
2575 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2576 typedef cmds::GetAttachedShaders::Result Result;
2577 uint32 size = Result::ComputeSize(maxcount);
2578 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
2579 if (!result) {
2580 return;
2582 result->SetNumResults(0);
2583 helper_->GetAttachedShaders(
2584 program,
2585 transfer_buffer_->GetShmId(),
2586 transfer_buffer_->GetOffset(result),
2587 size);
2588 int32 token = helper_->InsertToken();
2589 WaitForCmd();
2590 if (count) {
2591 *count = result->GetNumResults();
2593 result->CopyResult(shaders);
2594 GPU_CLIENT_LOG_CODE_BLOCK({
2595 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2596 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2599 transfer_buffer_->FreePendingToken(result, token);
2600 CheckGLError();
2603 void GLES2Implementation::GetShaderPrecisionFormat(
2604 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
2605 GPU_CLIENT_SINGLE_THREAD_CHECK();
2606 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2607 << GLES2Util::GetStringShaderType(shadertype) << ", "
2608 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
2609 << static_cast<const void*>(range) << ", "
2610 << static_cast<const void*>(precision) << ", ");
2611 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2612 typedef cmds::GetShaderPrecisionFormat::Result Result;
2613 Result* result = GetResultAs<Result*>();
2614 if (!result) {
2615 return;
2618 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
2619 GLStaticState::ShaderPrecisionMap::iterator i =
2620 static_state_.shader_precisions.find(key);
2621 if (i != static_state_.shader_precisions.end()) {
2622 *result = i->second;
2623 } else {
2624 result->success = false;
2625 helper_->GetShaderPrecisionFormat(
2626 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
2627 WaitForCmd();
2628 if (result->success)
2629 static_state_.shader_precisions[key] = *result;
2632 if (result->success) {
2633 if (range) {
2634 range[0] = result->min_range;
2635 range[1] = result->max_range;
2636 GPU_CLIENT_LOG(" min_range: " << range[0]);
2637 GPU_CLIENT_LOG(" min_range: " << range[1]);
2639 if (precision) {
2640 precision[0] = result->precision;
2641 GPU_CLIENT_LOG(" min_range: " << precision[0]);
2644 CheckGLError();
2647 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
2648 const char* result = NULL;
2649 // Clears the bucket so if the command fails nothing will be in it.
2650 helper_->SetBucketSize(kResultBucketId, 0);
2651 helper_->GetString(name, kResultBucketId);
2652 std::string str;
2653 if (GetBucketAsString(kResultBucketId, &str)) {
2654 // Adds extensions implemented on client side only.
2655 switch (name) {
2656 case GL_EXTENSIONS:
2657 str += std::string(str.empty() ? "" : " ") +
2658 "GL_CHROMIUM_flipy "
2659 "GL_EXT_unpack_subimage "
2660 "GL_CHROMIUM_map_sub";
2661 if (capabilities_.image)
2662 str += " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
2663 if (capabilities_.future_sync_points)
2664 str += " GL_CHROMIUM_future_sync_point";
2665 break;
2666 default:
2667 break;
2670 // Because of WebGL the extensions can change. We have to cache each unique
2671 // result since we don't know when the client will stop referring to a
2672 // previous one it queries.
2673 GLStringMap::iterator it = gl_strings_.find(name);
2674 if (it == gl_strings_.end()) {
2675 std::set<std::string> strings;
2676 std::pair<GLStringMap::iterator, bool> insert_result =
2677 gl_strings_.insert(std::make_pair(name, strings));
2678 DCHECK(insert_result.second);
2679 it = insert_result.first;
2681 std::set<std::string>& string_set = it->second;
2682 std::set<std::string>::const_iterator sit = string_set.find(str);
2683 if (sit != string_set.end()) {
2684 result = sit->c_str();
2685 } else {
2686 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2687 string_set.insert(str);
2688 DCHECK(insert_result.second);
2689 result = insert_result.first->c_str();
2692 return reinterpret_cast<const GLubyte*>(result);
2695 const GLubyte* GLES2Implementation::GetString(GLenum name) {
2696 GPU_CLIENT_SINGLE_THREAD_CHECK();
2697 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2698 << GLES2Util::GetStringStringType(name) << ")");
2699 TRACE_EVENT0("gpu", "GLES2::GetString");
2700 const GLubyte* result = GetStringHelper(name);
2701 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
2702 CheckGLError();
2703 return result;
2706 bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
2707 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2708 GLenum* type, char* name) {
2709 // Clear the bucket so if the command fails nothing will be in it.
2710 helper_->SetBucketSize(kResultBucketId, 0);
2711 typedef cmds::GetTransformFeedbackVarying::Result Result;
2712 Result* result = GetResultAs<Result*>();
2713 if (!result) {
2714 return false;
2716 // Set as failed so if the command fails we'll recover.
2717 result->success = false;
2718 helper_->GetTransformFeedbackVarying(
2719 program, index, kResultBucketId, GetResultShmId(), GetResultShmOffset());
2720 WaitForCmd();
2721 if (result->success) {
2722 if (size) {
2723 *size = result->size;
2725 if (type) {
2726 *type = result->type;
2728 if (length || name) {
2729 std::vector<int8> str;
2730 GetBucketContents(kResultBucketId, &str);
2731 GLsizei max_size = std::min(bufsize, static_cast<GLsizei>(str.size()));
2732 if (max_size > 0) {
2733 --max_size;
2735 if (length) {
2736 *length = max_size;
2738 if (name) {
2739 if (max_size > 0) {
2740 memcpy(name, &str[0], max_size);
2741 name[max_size] = '\0';
2742 } else if (bufsize > 0) {
2743 name[0] = '\0';
2748 return result->success != 0;
2751 void GLES2Implementation::GetTransformFeedbackVarying(
2752 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2753 GLenum* type, char* name) {
2754 GPU_CLIENT_SINGLE_THREAD_CHECK();
2755 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
2756 << program << ", " << index << ", " << bufsize << ", "
2757 << static_cast<const void*>(length) << ", "
2758 << static_cast<const void*>(size) << ", "
2759 << static_cast<const void*>(type) << ", "
2760 << static_cast<const void*>(name) << ", ");
2761 if (bufsize < 0) {
2762 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVarying",
2763 "bufsize < 0");
2764 return;
2766 TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
2767 bool success =
2768 share_group_->program_info_manager()->GetTransformFeedbackVarying(
2769 this, program, index, bufsize, length, size, type, name);
2770 if (success) {
2771 if (size) {
2772 GPU_CLIENT_LOG(" size: " << *size);
2774 if (type) {
2775 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2777 if (name) {
2778 GPU_CLIENT_LOG(" name: " << name);
2781 CheckGLError();
2784 void GLES2Implementation::GetUniformfv(
2785 GLuint program, GLint location, GLfloat* params) {
2786 GPU_CLIENT_SINGLE_THREAD_CHECK();
2787 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2788 << program << ", " << location << ", "
2789 << static_cast<const void*>(params) << ")");
2790 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2791 typedef cmds::GetUniformfv::Result Result;
2792 Result* result = GetResultAs<Result*>();
2793 if (!result) {
2794 return;
2796 result->SetNumResults(0);
2797 helper_->GetUniformfv(
2798 program, location, GetResultShmId(), GetResultShmOffset());
2799 WaitForCmd();
2800 result->CopyResult(params);
2801 GPU_CLIENT_LOG_CODE_BLOCK({
2802 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2803 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2806 CheckGLError();
2809 void GLES2Implementation::GetUniformiv(
2810 GLuint program, GLint location, GLint* params) {
2811 GPU_CLIENT_SINGLE_THREAD_CHECK();
2812 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2813 << program << ", " << location << ", "
2814 << static_cast<const void*>(params) << ")");
2815 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2816 typedef cmds::GetUniformiv::Result Result;
2817 Result* result = GetResultAs<Result*>();
2818 if (!result) {
2819 return;
2821 result->SetNumResults(0);
2822 helper_->GetUniformiv(
2823 program, location, GetResultShmId(), GetResultShmOffset());
2824 WaitForCmd();
2825 GetResultAs<cmds::GetUniformfv::Result*>()->CopyResult(params);
2826 GPU_CLIENT_LOG_CODE_BLOCK({
2827 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2828 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2831 CheckGLError();
2834 void GLES2Implementation::ReadPixels(
2835 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
2836 GLenum type, void* pixels) {
2837 GPU_CLIENT_SINGLE_THREAD_CHECK();
2838 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2839 << xoffset << ", " << yoffset << ", "
2840 << width << ", " << height << ", "
2841 << GLES2Util::GetStringReadPixelFormat(format) << ", "
2842 << GLES2Util::GetStringPixelType(type) << ", "
2843 << static_cast<const void*>(pixels) << ")");
2844 if (width < 0 || height < 0) {
2845 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
2846 return;
2848 if (width == 0 || height == 0) {
2849 return;
2852 // glReadPixel pads the size of each row of pixels by an amount specified by
2853 // glPixelStorei. So, we have to take that into account both in the fact that
2854 // the pixels returned from the ReadPixel command will include that padding
2855 // and that when we copy the results to the user's buffer we need to not
2856 // write those padding bytes but leave them as they are.
2858 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2859 typedef cmds::ReadPixels::Result Result;
2861 int8* dest = reinterpret_cast<int8*>(pixels);
2862 uint32 temp_size;
2863 uint32 unpadded_row_size;
2864 uint32 padded_row_size;
2865 if (!GLES2Util::ComputeImageDataSizes(
2866 width, 2, 1, format, type, pack_alignment_, &temp_size,
2867 &unpadded_row_size, &padded_row_size)) {
2868 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
2869 return;
2872 if (bound_pixel_pack_transfer_buffer_id_) {
2873 GLuint offset = ToGLuint(pixels);
2874 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2875 bound_pixel_pack_transfer_buffer_id_,
2876 "glReadPixels", offset, padded_row_size * height);
2877 if (buffer && buffer->shm_id() != -1) {
2878 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
2879 buffer->shm_id(), buffer->shm_offset(),
2880 0, 0, true);
2881 CheckGLError();
2883 return;
2886 if (!pixels) {
2887 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
2888 return;
2891 // Transfer by rows.
2892 // The max rows we can transfer.
2893 while (height) {
2894 GLsizei desired_size = padded_row_size * (height - 1) + unpadded_row_size;
2895 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
2896 if (!buffer.valid()) {
2897 return;
2899 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2900 padded_row_size, unpadded_row_size, buffer.size(), height);
2901 num_rows = std::min(num_rows, height);
2902 // NOTE: We must look up the address of the result area AFTER allocation
2903 // of the transfer buffer since the transfer buffer may be reallocated.
2904 Result* result = GetResultAs<Result*>();
2905 if (!result) {
2906 return;
2908 *result = 0; // mark as failed.
2909 helper_->ReadPixels(
2910 xoffset, yoffset, width, num_rows, format, type,
2911 buffer.shm_id(), buffer.offset(),
2912 GetResultShmId(), GetResultShmOffset(),
2913 false);
2914 WaitForCmd();
2915 if (*result != 0) {
2916 // when doing a y-flip we have to iterate through top-to-bottom chunks
2917 // of the dst. The service side handles reversing the rows within a
2918 // chunk.
2919 int8* rows_dst;
2920 if (pack_reverse_row_order_) {
2921 rows_dst = dest + (height - num_rows) * padded_row_size;
2922 } else {
2923 rows_dst = dest;
2925 // We have to copy 1 row at a time to avoid writing pad bytes.
2926 const int8* src = static_cast<const int8*>(buffer.address());
2927 for (GLint yy = 0; yy < num_rows; ++yy) {
2928 memcpy(rows_dst, src, unpadded_row_size);
2929 rows_dst += padded_row_size;
2930 src += padded_row_size;
2932 if (!pack_reverse_row_order_) {
2933 dest = rows_dst;
2936 // If it was not marked as successful exit.
2937 if (*result == 0) {
2938 return;
2940 yoffset += num_rows;
2941 height -= num_rows;
2943 CheckGLError();
2946 void GLES2Implementation::ActiveTexture(GLenum texture) {
2947 GPU_CLIENT_SINGLE_THREAD_CHECK();
2948 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2949 << GLES2Util::GetStringEnum(texture) << ")");
2950 GLuint texture_index = texture - GL_TEXTURE0;
2951 if (texture_index >=
2952 static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
2953 SetGLErrorInvalidEnum(
2954 "glActiveTexture", texture, "texture");
2955 return;
2958 active_texture_unit_ = texture_index;
2959 helper_->ActiveTexture(texture);
2960 CheckGLError();
2963 void GLES2Implementation::GenBuffersHelper(
2964 GLsizei /* n */, const GLuint* /* buffers */) {
2967 void GLES2Implementation::GenFramebuffersHelper(
2968 GLsizei /* n */, const GLuint* /* framebuffers */) {
2971 void GLES2Implementation::GenRenderbuffersHelper(
2972 GLsizei /* n */, const GLuint* /* renderbuffers */) {
2975 void GLES2Implementation::GenTexturesHelper(
2976 GLsizei /* n */, const GLuint* /* textures */) {
2979 void GLES2Implementation::GenVertexArraysOESHelper(
2980 GLsizei n, const GLuint* arrays) {
2981 vertex_array_object_manager_->GenVertexArrays(n, arrays);
2984 void GLES2Implementation::GenQueriesEXTHelper(
2985 GLsizei /* n */, const GLuint* /* queries */) {
2988 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
2989 GLsizei /* n */,
2990 const GLuint* /* valuebuffers */) {
2993 void GLES2Implementation::GenSamplersHelper(
2994 GLsizei /* n */, const GLuint* /* samplers */) {
2997 void GLES2Implementation::GenTransformFeedbacksHelper(
2998 GLsizei /* n */, const GLuint* /* transformfeedbacks */) {
3001 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
3002 // generates a new resource. On newer versions of OpenGL they don't. The code
3003 // related to binding below will need to change if we switch to the new OpenGL
3004 // model. Specifically it assumes a bind will succeed which is always true in
3005 // the old model but possibly not true in the new model if another context has
3006 // deleted the resource.
3008 // NOTE #2: There is a bug in some BindXXXHelpers, that IDs might be marked as
3009 // used even when Bind has failed. However, the bug is minor compared to the
3010 // overhead & duplicated checking in client side.
3012 void GLES2Implementation::BindBufferHelper(
3013 GLenum target, GLuint buffer_id) {
3014 // TODO(gman): See note #1 above.
3015 bool changed = false;
3016 switch (target) {
3017 case GL_ARRAY_BUFFER:
3018 if (bound_array_buffer_id_ != buffer_id) {
3019 bound_array_buffer_id_ = buffer_id;
3020 changed = true;
3022 break;
3023 case GL_ELEMENT_ARRAY_BUFFER:
3024 changed = vertex_array_object_manager_->BindElementArray(buffer_id);
3025 break;
3026 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3027 bound_pixel_pack_transfer_buffer_id_ = buffer_id;
3028 break;
3029 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3030 bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
3031 break;
3032 default:
3033 changed = true;
3034 break;
3036 // TODO(gman): See note #2 above.
3037 if (changed) {
3038 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3039 this, target, buffer_id, &GLES2Implementation::BindBufferStub);
3043 void GLES2Implementation::BindBufferStub(GLenum target, GLuint buffer) {
3044 helper_->BindBuffer(target, buffer);
3045 if (share_group_->bind_generates_resource())
3046 helper_->CommandBufferHelper::Flush();
3049 void GLES2Implementation::BindBufferBaseHelper(
3050 GLenum target, GLuint index, GLuint buffer_id) {
3051 // TODO(zmo): See note #1 above.
3052 // TODO(zmo): See note #2 above.
3053 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3054 this, target, index, buffer_id, &GLES2Implementation::BindBufferBaseStub);
3057 void GLES2Implementation::BindBufferBaseStub(
3058 GLenum target, GLuint index, GLuint buffer) {
3059 helper_->BindBufferBase(target, index, buffer);
3060 if (share_group_->bind_generates_resource())
3061 helper_->CommandBufferHelper::Flush();
3064 void GLES2Implementation::BindBufferRangeHelper(
3065 GLenum target, GLuint index, GLuint buffer_id,
3066 GLintptr offset, GLsizeiptr size) {
3067 // TODO(zmo): See note #1 above.
3068 // TODO(zmo): See note #2 above.
3069 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3070 this, target, index, buffer_id, offset, size,
3071 &GLES2Implementation::BindBufferRangeStub);
3074 void GLES2Implementation::BindBufferRangeStub(
3075 GLenum target, GLuint index, GLuint buffer,
3076 GLintptr offset, GLsizeiptr size) {
3077 helper_->BindBufferRange(target, index, buffer, offset, size);
3078 if (share_group_->bind_generates_resource())
3079 helper_->CommandBufferHelper::Flush();
3082 void GLES2Implementation::BindFramebufferHelper(
3083 GLenum target, GLuint framebuffer) {
3084 // TODO(gman): See note #1 above.
3085 bool changed = false;
3086 switch (target) {
3087 case GL_FRAMEBUFFER:
3088 if (bound_framebuffer_ != framebuffer ||
3089 bound_read_framebuffer_ != framebuffer) {
3090 bound_framebuffer_ = framebuffer;
3091 bound_read_framebuffer_ = framebuffer;
3092 changed = true;
3094 break;
3095 case GL_READ_FRAMEBUFFER:
3096 if (!IsChromiumFramebufferMultisampleAvailable()) {
3097 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3098 return;
3100 if (bound_read_framebuffer_ != framebuffer) {
3101 bound_read_framebuffer_ = framebuffer;
3102 changed = true;
3104 break;
3105 case GL_DRAW_FRAMEBUFFER:
3106 if (!IsChromiumFramebufferMultisampleAvailable()) {
3107 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3108 return;
3110 if (bound_framebuffer_ != framebuffer) {
3111 bound_framebuffer_ = framebuffer;
3112 changed = true;
3114 break;
3115 default:
3116 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3117 return;
3120 if (changed) {
3121 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(
3122 this, target, framebuffer, &GLES2Implementation::BindFramebufferStub);
3126 void GLES2Implementation::BindFramebufferStub(GLenum target,
3127 GLuint framebuffer) {
3128 helper_->BindFramebuffer(target, framebuffer);
3129 if (share_group_->bind_generates_resource())
3130 helper_->CommandBufferHelper::Flush();
3133 void GLES2Implementation::BindRenderbufferHelper(
3134 GLenum target, GLuint renderbuffer) {
3135 // TODO(gman): See note #1 above.
3136 bool changed = false;
3137 switch (target) {
3138 case GL_RENDERBUFFER:
3139 if (bound_renderbuffer_ != renderbuffer) {
3140 bound_renderbuffer_ = renderbuffer;
3141 changed = true;
3143 break;
3144 default:
3145 changed = true;
3146 break;
3148 // TODO(zmo): See note #2 above.
3149 if (changed) {
3150 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(
3151 this, target, renderbuffer,
3152 &GLES2Implementation::BindRenderbufferStub);
3156 void GLES2Implementation::BindRenderbufferStub(GLenum target,
3157 GLuint renderbuffer) {
3158 helper_->BindRenderbuffer(target, renderbuffer);
3159 if (share_group_->bind_generates_resource())
3160 helper_->CommandBufferHelper::Flush();
3163 void GLES2Implementation::BindSamplerHelper(GLuint unit,
3164 GLuint sampler) {
3165 helper_->BindSampler(unit, sampler);
3168 void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
3169 // TODO(gman): See note #1 above.
3170 // TODO(gman): Change this to false once we figure out why it's failing
3171 // on daisy.
3172 bool changed = true;
3173 TextureUnit& unit = texture_units_[active_texture_unit_];
3174 switch (target) {
3175 case GL_TEXTURE_2D:
3176 if (unit.bound_texture_2d != texture) {
3177 unit.bound_texture_2d = texture;
3178 changed = true;
3180 break;
3181 case GL_TEXTURE_CUBE_MAP:
3182 if (unit.bound_texture_cube_map != texture) {
3183 unit.bound_texture_cube_map = texture;
3184 changed = true;
3186 break;
3187 case GL_TEXTURE_EXTERNAL_OES:
3188 if (unit.bound_texture_external_oes != texture) {
3189 unit.bound_texture_external_oes = texture;
3190 changed = true;
3192 break;
3193 default:
3194 changed = true;
3195 break;
3197 // TODO(gman): See note #2 above.
3198 if (changed) {
3199 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(
3200 this, target, texture, &GLES2Implementation::BindTextureStub);
3204 void GLES2Implementation::BindTextureStub(GLenum target, GLuint texture) {
3205 helper_->BindTexture(target, texture);
3206 if (share_group_->bind_generates_resource())
3207 helper_->CommandBufferHelper::Flush();
3210 void GLES2Implementation::BindTransformFeedbackHelper(
3211 GLenum target, GLuint transformfeedback) {
3212 helper_->BindTransformFeedback(target, transformfeedback);
3215 void GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
3216 bool changed = false;
3217 if (vertex_array_object_manager_->BindVertexArray(array, &changed)) {
3218 if (changed) {
3219 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
3220 // because unlike other resources VertexArrayObject ids must
3221 // be generated by GenVertexArrays. A random id to Bind will not
3222 // generate a new object.
3223 helper_->BindVertexArrayOES(array);
3225 } else {
3226 SetGLError(
3227 GL_INVALID_OPERATION, "glBindVertexArrayOES",
3228 "id was not generated with glGenVertexArrayOES");
3232 void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
3233 GLuint valuebuffer) {
3234 bool changed = false;
3235 switch (target) {
3236 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
3237 if (bound_valuebuffer_ != valuebuffer) {
3238 bound_valuebuffer_ = valuebuffer;
3239 changed = true;
3241 break;
3242 default:
3243 changed = true;
3244 break;
3246 // TODO(gman): See note #2 above.
3247 if (changed) {
3248 GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(
3249 this, target, valuebuffer,
3250 &GLES2Implementation::BindValuebufferCHROMIUMStub);
3254 void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target,
3255 GLuint valuebuffer) {
3256 helper_->BindValuebufferCHROMIUM(target, valuebuffer);
3257 if (share_group_->bind_generates_resource())
3258 helper_->CommandBufferHelper::Flush();
3261 void GLES2Implementation::UseProgramHelper(GLuint program) {
3262 if (current_program_ != program) {
3263 current_program_ = program;
3264 helper_->UseProgram(program);
3268 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
3269 return vertex_array_object_manager_->IsReservedId(id);
3272 void GLES2Implementation::DeleteBuffersHelper(
3273 GLsizei n, const GLuint* buffers) {
3274 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
3275 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
3276 SetGLError(
3277 GL_INVALID_VALUE,
3278 "glDeleteBuffers", "id not created by this context.");
3279 return;
3281 for (GLsizei ii = 0; ii < n; ++ii) {
3282 if (buffers[ii] == bound_array_buffer_id_) {
3283 bound_array_buffer_id_ = 0;
3285 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
3287 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
3288 if (buffer)
3289 RemoveTransferBuffer(buffer);
3291 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
3292 bound_pixel_unpack_transfer_buffer_id_ = 0;
3297 void GLES2Implementation::DeleteBuffersStub(
3298 GLsizei n, const GLuint* buffers) {
3299 helper_->DeleteBuffersImmediate(n, buffers);
3303 void GLES2Implementation::DeleteFramebuffersHelper(
3304 GLsizei n, const GLuint* framebuffers) {
3305 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
3306 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
3307 SetGLError(
3308 GL_INVALID_VALUE,
3309 "glDeleteFramebuffers", "id not created by this context.");
3310 return;
3312 for (GLsizei ii = 0; ii < n; ++ii) {
3313 if (framebuffers[ii] == bound_framebuffer_) {
3314 bound_framebuffer_ = 0;
3316 if (framebuffers[ii] == bound_read_framebuffer_) {
3317 bound_read_framebuffer_ = 0;
3322 void GLES2Implementation::DeleteFramebuffersStub(
3323 GLsizei n, const GLuint* framebuffers) {
3324 helper_->DeleteFramebuffersImmediate(n, framebuffers);
3327 void GLES2Implementation::DeleteRenderbuffersHelper(
3328 GLsizei n, const GLuint* renderbuffers) {
3329 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
3330 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
3331 SetGLError(
3332 GL_INVALID_VALUE,
3333 "glDeleteRenderbuffers", "id not created by this context.");
3334 return;
3336 for (GLsizei ii = 0; ii < n; ++ii) {
3337 if (renderbuffers[ii] == bound_renderbuffer_) {
3338 bound_renderbuffer_ = 0;
3343 void GLES2Implementation::DeleteRenderbuffersStub(
3344 GLsizei n, const GLuint* renderbuffers) {
3345 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
3348 void GLES2Implementation::DeleteTexturesHelper(
3349 GLsizei n, const GLuint* textures) {
3350 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
3351 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
3352 SetGLError(
3353 GL_INVALID_VALUE,
3354 "glDeleteTextures", "id not created by this context.");
3355 return;
3357 for (GLsizei ii = 0; ii < n; ++ii) {
3358 for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
3359 ++tt) {
3360 TextureUnit& unit = texture_units_[tt];
3361 if (textures[ii] == unit.bound_texture_2d) {
3362 unit.bound_texture_2d = 0;
3364 if (textures[ii] == unit.bound_texture_cube_map) {
3365 unit.bound_texture_cube_map = 0;
3367 if (textures[ii] == unit.bound_texture_external_oes) {
3368 unit.bound_texture_external_oes = 0;
3374 void GLES2Implementation::DeleteTexturesStub(GLsizei n,
3375 const GLuint* textures) {
3376 helper_->DeleteTexturesImmediate(n, textures);
3379 void GLES2Implementation::DeleteVertexArraysOESHelper(
3380 GLsizei n, const GLuint* arrays) {
3381 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
3382 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
3383 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
3384 SetGLError(
3385 GL_INVALID_VALUE,
3386 "glDeleteVertexArraysOES", "id not created by this context.");
3387 return;
3391 void GLES2Implementation::DeleteVertexArraysOESStub(
3392 GLsizei n, const GLuint* arrays) {
3393 helper_->DeleteVertexArraysOESImmediate(n, arrays);
3396 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
3397 GLsizei n,
3398 const GLuint* valuebuffers) {
3399 if (!GetIdHandler(id_namespaces::kValuebuffers)
3400 ->FreeIds(this, n, valuebuffers,
3401 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
3402 SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
3403 "id not created by this context.");
3404 return;
3406 for (GLsizei ii = 0; ii < n; ++ii) {
3407 if (valuebuffers[ii] == bound_valuebuffer_) {
3408 bound_valuebuffer_ = 0;
3413 void GLES2Implementation::DeleteSamplersStub(
3414 GLsizei n, const GLuint* samplers) {
3415 helper_->DeleteSamplersImmediate(n, samplers);
3418 void GLES2Implementation::DeleteSamplersHelper(
3419 GLsizei n, const GLuint* samplers) {
3420 if (!GetIdHandler(id_namespaces::kSamplers)->FreeIds(
3421 this, n, samplers, &GLES2Implementation::DeleteSamplersStub)) {
3422 SetGLError(
3423 GL_INVALID_VALUE,
3424 "glDeleteSamplers", "id not created by this context.");
3425 return;
3429 void GLES2Implementation::DeleteTransformFeedbacksStub(
3430 GLsizei n, const GLuint* transformfeedbacks) {
3431 helper_->DeleteTransformFeedbacksImmediate(n, transformfeedbacks);
3434 void GLES2Implementation::DeleteTransformFeedbacksHelper(
3435 GLsizei n, const GLuint* transformfeedbacks) {
3436 if (!GetIdHandler(id_namespaces::kTransformFeedbacks)->FreeIds(
3437 this, n, transformfeedbacks,
3438 &GLES2Implementation::DeleteTransformFeedbacksStub)) {
3439 SetGLError(
3440 GL_INVALID_VALUE,
3441 "glDeleteTransformFeedbacks", "id not created by this context.");
3442 return;
3446 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
3447 GLsizei n,
3448 const GLuint* valuebuffers) {
3449 helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
3452 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
3453 GPU_CLIENT_SINGLE_THREAD_CHECK();
3454 GPU_CLIENT_LOG(
3455 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
3456 vertex_array_object_manager_->SetAttribEnable(index, false);
3457 helper_->DisableVertexAttribArray(index);
3458 CheckGLError();
3461 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
3462 GPU_CLIENT_SINGLE_THREAD_CHECK();
3463 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
3464 << index << ")");
3465 vertex_array_object_manager_->SetAttribEnable(index, true);
3466 helper_->EnableVertexAttribArray(index);
3467 CheckGLError();
3470 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
3471 GPU_CLIENT_SINGLE_THREAD_CHECK();
3472 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
3473 << GLES2Util::GetStringDrawMode(mode) << ", "
3474 << first << ", " << count << ")");
3475 if (count < 0) {
3476 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
3477 return;
3479 bool simulated = false;
3480 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
3481 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
3482 return;
3484 helper_->DrawArrays(mode, first, count);
3485 RestoreArrayBuffer(simulated);
3486 CheckGLError();
3489 void GLES2Implementation::GetVertexAttribfv(
3490 GLuint index, GLenum pname, GLfloat* params) {
3491 GPU_CLIENT_SINGLE_THREAD_CHECK();
3492 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
3493 << index << ", "
3494 << GLES2Util::GetStringVertexAttribute(pname) << ", "
3495 << static_cast<const void*>(params) << ")");
3496 uint32 value = 0;
3497 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
3498 *params = static_cast<float>(value);
3499 return;
3501 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
3502 typedef cmds::GetVertexAttribfv::Result Result;
3503 Result* result = GetResultAs<Result*>();
3504 if (!result) {
3505 return;
3507 result->SetNumResults(0);
3508 helper_->GetVertexAttribfv(
3509 index, pname, GetResultShmId(), GetResultShmOffset());
3510 WaitForCmd();
3511 result->CopyResult(params);
3512 GPU_CLIENT_LOG_CODE_BLOCK({
3513 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3514 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3517 CheckGLError();
3520 void GLES2Implementation::GetVertexAttribiv(
3521 GLuint index, GLenum pname, GLint* params) {
3522 GPU_CLIENT_SINGLE_THREAD_CHECK();
3523 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
3524 << index << ", "
3525 << GLES2Util::GetStringVertexAttribute(pname) << ", "
3526 << static_cast<const void*>(params) << ")");
3527 uint32 value = 0;
3528 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
3529 *params = value;
3530 return;
3532 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
3533 typedef cmds::GetVertexAttribiv::Result Result;
3534 Result* result = GetResultAs<Result*>();
3535 if (!result) {
3536 return;
3538 result->SetNumResults(0);
3539 helper_->GetVertexAttribiv(
3540 index, pname, GetResultShmId(), GetResultShmOffset());
3541 WaitForCmd();
3542 result->CopyResult(params);
3543 GPU_CLIENT_LOG_CODE_BLOCK({
3544 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3545 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3548 CheckGLError();
3551 void GLES2Implementation::Swap() {
3552 SwapBuffers();
3555 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
3556 PostSubBufferCHROMIUM(
3557 sub_buffer.x(), sub_buffer.y(), sub_buffer.width(), sub_buffer.height());
3560 static GLenum GetGLESOverlayTransform(gfx::OverlayTransform plane_transform) {
3561 switch (plane_transform) {
3562 case gfx::OVERLAY_TRANSFORM_INVALID:
3563 break;
3564 case gfx::OVERLAY_TRANSFORM_NONE:
3565 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
3566 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
3567 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM;
3568 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
3569 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM;
3570 case gfx::OVERLAY_TRANSFORM_ROTATE_90:
3571 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM;
3572 case gfx::OVERLAY_TRANSFORM_ROTATE_180:
3573 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM;
3574 case gfx::OVERLAY_TRANSFORM_ROTATE_270:
3575 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM;
3577 NOTREACHED();
3578 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
3581 void GLES2Implementation::ScheduleOverlayPlane(
3582 int plane_z_order,
3583 gfx::OverlayTransform plane_transform,
3584 unsigned overlay_texture_id,
3585 const gfx::Rect& display_bounds,
3586 const gfx::RectF& uv_rect) {
3587 ScheduleOverlayPlaneCHROMIUM(plane_z_order,
3588 GetGLESOverlayTransform(plane_transform),
3589 overlay_texture_id,
3590 display_bounds.x(),
3591 display_bounds.y(),
3592 display_bounds.width(),
3593 display_bounds.height(),
3594 uv_rect.x(),
3595 uv_rect.y(),
3596 uv_rect.width(),
3597 uv_rect.height());
3600 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
3601 const char* feature) {
3602 GPU_CLIENT_SINGLE_THREAD_CHECK();
3603 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
3604 << feature << ")");
3605 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
3606 typedef cmds::EnableFeatureCHROMIUM::Result Result;
3607 Result* result = GetResultAs<Result*>();
3608 if (!result) {
3609 return false;
3611 *result = 0;
3612 SetBucketAsCString(kResultBucketId, feature);
3613 helper_->EnableFeatureCHROMIUM(
3614 kResultBucketId, GetResultShmId(), GetResultShmOffset());
3615 WaitForCmd();
3616 helper_->SetBucketSize(kResultBucketId, 0);
3617 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
3618 return *result != 0;
3621 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
3622 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
3623 GPU_CLIENT_SINGLE_THREAD_CHECK();
3624 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
3625 << target << ", " << offset << ", " << size << ", "
3626 << GLES2Util::GetStringEnum(access) << ")");
3627 // NOTE: target is NOT checked because the service will check it
3628 // and we don't know what targets are valid.
3629 if (access != GL_WRITE_ONLY) {
3630 SetGLErrorInvalidEnum(
3631 "glMapBufferSubDataCHROMIUM", access, "access");
3632 return NULL;
3634 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
3635 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
3636 return NULL;
3639 int32 shm_id;
3640 unsigned int shm_offset;
3641 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
3642 if (!mem) {
3643 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
3644 return NULL;
3647 std::pair<MappedBufferMap::iterator, bool> result =
3648 mapped_buffers_.insert(std::make_pair(
3649 mem,
3650 MappedBuffer(
3651 access, shm_id, mem, shm_offset, target, offset, size)));
3652 DCHECK(result.second);
3653 GPU_CLIENT_LOG(" returned " << mem);
3654 return mem;
3657 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
3658 GPU_CLIENT_SINGLE_THREAD_CHECK();
3659 GPU_CLIENT_LOG(
3660 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
3661 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
3662 if (it == mapped_buffers_.end()) {
3663 SetGLError(
3664 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
3665 return;
3667 const MappedBuffer& mb = it->second;
3668 helper_->BufferSubData(
3669 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
3670 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
3671 mapped_buffers_.erase(it);
3672 CheckGLError();
3675 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
3676 GLenum target,
3677 GLint level,
3678 GLint xoffset,
3679 GLint yoffset,
3680 GLsizei width,
3681 GLsizei height,
3682 GLenum format,
3683 GLenum type,
3684 GLenum access) {
3685 GPU_CLIENT_SINGLE_THREAD_CHECK();
3686 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
3687 << target << ", " << level << ", "
3688 << xoffset << ", " << yoffset << ", "
3689 << width << ", " << height << ", "
3690 << GLES2Util::GetStringTextureFormat(format) << ", "
3691 << GLES2Util::GetStringPixelType(type) << ", "
3692 << GLES2Util::GetStringEnum(access) << ")");
3693 if (access != GL_WRITE_ONLY) {
3694 SetGLErrorInvalidEnum(
3695 "glMapTexSubImage2DCHROMIUM", access, "access");
3696 return NULL;
3698 // NOTE: target is NOT checked because the service will check it
3699 // and we don't know what targets are valid.
3700 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
3701 SetGLError(
3702 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
3703 return NULL;
3705 uint32 size;
3706 if (!GLES2Util::ComputeImageDataSizes(
3707 width, height, 1, format, type, unpack_alignment_, &size, NULL, NULL)) {
3708 SetGLError(
3709 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
3710 return NULL;
3712 int32 shm_id;
3713 unsigned int shm_offset;
3714 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
3715 if (!mem) {
3716 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
3717 return NULL;
3720 std::pair<MappedTextureMap::iterator, bool> result =
3721 mapped_textures_.insert(std::make_pair(
3722 mem,
3723 MappedTexture(
3724 access, shm_id, mem, shm_offset,
3725 target, level, xoffset, yoffset, width, height, format, type)));
3726 DCHECK(result.second);
3727 GPU_CLIENT_LOG(" returned " << mem);
3728 return mem;
3731 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
3732 GPU_CLIENT_SINGLE_THREAD_CHECK();
3733 GPU_CLIENT_LOG(
3734 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
3735 MappedTextureMap::iterator it = mapped_textures_.find(mem);
3736 if (it == mapped_textures_.end()) {
3737 SetGLError(
3738 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
3739 return;
3741 const MappedTexture& mt = it->second;
3742 helper_->TexSubImage2D(
3743 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
3744 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
3745 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
3746 mapped_textures_.erase(it);
3747 CheckGLError();
3750 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
3751 float scale_factor) {
3752 GPU_CLIENT_SINGLE_THREAD_CHECK();
3753 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
3754 << width << ", " << height << ", " << scale_factor << ")");
3755 helper_->ResizeCHROMIUM(width, height, scale_factor);
3756 CheckGLError();
3759 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
3760 GPU_CLIENT_SINGLE_THREAD_CHECK();
3761 GPU_CLIENT_LOG("[" << GetLogPrefix()
3762 << "] glGetRequestableExtensionsCHROMIUM()");
3763 TRACE_EVENT0("gpu",
3764 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
3765 const char* result = NULL;
3766 // Clear the bucket so if the command fails nothing will be in it.
3767 helper_->SetBucketSize(kResultBucketId, 0);
3768 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
3769 std::string str;
3770 if (GetBucketAsString(kResultBucketId, &str)) {
3771 // The set of requestable extensions shrinks as we enable
3772 // them. Because we don't know when the client will stop referring
3773 // to a previous one it queries (see GetString) we need to cache
3774 // the unique results.
3775 std::set<std::string>::const_iterator sit =
3776 requestable_extensions_set_.find(str);
3777 if (sit != requestable_extensions_set_.end()) {
3778 result = sit->c_str();
3779 } else {
3780 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
3781 requestable_extensions_set_.insert(str);
3782 DCHECK(insert_result.second);
3783 result = insert_result.first->c_str();
3786 GPU_CLIENT_LOG(" returned " << result);
3787 return reinterpret_cast<const GLchar*>(result);
3790 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
3791 // with VirtualGL contexts.
3792 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
3793 GPU_CLIENT_SINGLE_THREAD_CHECK();
3794 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
3795 << extension << ")");
3796 SetBucketAsCString(kResultBucketId, extension);
3797 helper_->RequestExtensionCHROMIUM(kResultBucketId);
3798 helper_->SetBucketSize(kResultBucketId, 0);
3800 struct ExtensionCheck {
3801 const char* extension;
3802 ExtensionStatus* status;
3804 const ExtensionCheck checks[] = {
3806 "GL_ANGLE_pack_reverse_row_order",
3807 &angle_pack_reverse_row_order_status_,
3810 "GL_CHROMIUM_framebuffer_multisample",
3811 &chromium_framebuffer_multisample_,
3814 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
3815 for (size_t ii = 0; ii < kNumChecks; ++ii) {
3816 const ExtensionCheck& check = checks[ii];
3817 if (*check.status == kUnavailableExtensionStatus &&
3818 !strcmp(extension, check.extension)) {
3819 *check.status = kUnknownExtensionStatus;
3824 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
3825 GPU_CLIENT_SINGLE_THREAD_CHECK();
3826 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
3827 // Wait if this would add too many rate limit tokens.
3828 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
3829 helper_->WaitForToken(rate_limit_tokens_.front());
3830 rate_limit_tokens_.pop();
3832 rate_limit_tokens_.push(helper_->InsertToken());
3835 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3836 GLuint program, std::vector<int8>* result) {
3837 DCHECK(result);
3838 // Clear the bucket so if the command fails nothing will be in it.
3839 helper_->SetBucketSize(kResultBucketId, 0);
3840 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
3841 GetBucketContents(kResultBucketId, result);
3844 void GLES2Implementation::GetProgramInfoCHROMIUM(
3845 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3846 GPU_CLIENT_SINGLE_THREAD_CHECK();
3847 if (bufsize < 0) {
3848 SetGLError(
3849 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3850 return;
3852 if (size == NULL) {
3853 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
3854 return;
3856 // Make sure they've set size to 0 else the value will be undefined on
3857 // lost context.
3858 DCHECK_EQ(0, *size);
3859 std::vector<int8> result;
3860 GetProgramInfoCHROMIUMHelper(program, &result);
3861 if (result.empty()) {
3862 return;
3864 *size = result.size();
3865 if (!info) {
3866 return;
3868 if (static_cast<size_t>(bufsize) < result.size()) {
3869 SetGLError(GL_INVALID_OPERATION,
3870 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3871 return;
3873 memcpy(info, &result[0], result.size());
3876 void GLES2Implementation::GetUniformBlocksCHROMIUMHelper(
3877 GLuint program, std::vector<int8>* result) {
3878 DCHECK(result);
3879 // Clear the bucket so if the command fails nothing will be in it.
3880 helper_->SetBucketSize(kResultBucketId, 0);
3881 helper_->GetUniformBlocksCHROMIUM(program, kResultBucketId);
3882 GetBucketContents(kResultBucketId, result);
3885 void GLES2Implementation::GetUniformBlocksCHROMIUM(
3886 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3887 GPU_CLIENT_SINGLE_THREAD_CHECK();
3888 if (bufsize < 0) {
3889 SetGLError(
3890 GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "bufsize less than 0.");
3891 return;
3893 if (size == NULL) {
3894 SetGLError(GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "size is null.");
3895 return;
3897 // Make sure they've set size to 0 else the value will be undefined on
3898 // lost context.
3899 DCHECK_EQ(0, *size);
3900 std::vector<int8> result;
3901 GetUniformBlocksCHROMIUMHelper(program, &result);
3902 if (result.empty()) {
3903 return;
3905 *size = result.size();
3906 if (!info) {
3907 return;
3909 if (static_cast<size_t>(bufsize) < result.size()) {
3910 SetGLError(GL_INVALID_OPERATION, "glGetUniformBlocksCHROMIUM",
3911 "bufsize is too small for result.");
3912 return;
3914 memcpy(info, &result[0], result.size());
3917 void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
3918 GLuint program, std::vector<int8>* result) {
3919 DCHECK(result);
3920 // Clear the bucket so if the command fails nothing will be in it.
3921 helper_->SetBucketSize(kResultBucketId, 0);
3922 helper_->GetUniformsES3CHROMIUM(program, kResultBucketId);
3923 GetBucketContents(kResultBucketId, result);
3926 void GLES2Implementation::GetUniformsES3CHROMIUM(
3927 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3928 GPU_CLIENT_SINGLE_THREAD_CHECK();
3929 if (bufsize < 0) {
3930 SetGLError(
3931 GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "bufsize less than 0.");
3932 return;
3934 if (size == NULL) {
3935 SetGLError(GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "size is null.");
3936 return;
3938 // Make sure they've set size to 0 else the value will be undefined on
3939 // lost context.
3940 DCHECK_EQ(0, *size);
3941 std::vector<int8> result;
3942 GetUniformsES3CHROMIUMHelper(program, &result);
3943 if (result.empty()) {
3944 return;
3946 *size = result.size();
3947 if (!info) {
3948 return;
3950 if (static_cast<size_t>(bufsize) < result.size()) {
3951 SetGLError(GL_INVALID_OPERATION,
3952 "glGetUniformsES3CHROMIUM", "bufsize is too small for result.");
3953 return;
3955 memcpy(info, &result[0], result.size());
3958 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
3959 GLuint program, std::vector<int8>* result) {
3960 DCHECK(result);
3961 // Clear the bucket so if the command fails nothing will be in it.
3962 helper_->SetBucketSize(kResultBucketId, 0);
3963 helper_->GetTransformFeedbackVaryingsCHROMIUM(program, kResultBucketId);
3964 GetBucketContents(kResultBucketId, result);
3967 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(
3968 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3969 GPU_CLIENT_SINGLE_THREAD_CHECK();
3970 if (bufsize < 0) {
3971 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
3972 "bufsize less than 0.");
3973 return;
3975 if (size == NULL) {
3976 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
3977 "size is null.");
3978 return;
3980 // Make sure they've set size to 0 else the value will be undefined on
3981 // lost context.
3982 DCHECK_EQ(0, *size);
3983 std::vector<int8> result;
3984 GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
3985 if (result.empty()) {
3986 return;
3988 *size = result.size();
3989 if (!info) {
3990 return;
3992 if (static_cast<size_t>(bufsize) < result.size()) {
3993 SetGLError(GL_INVALID_OPERATION, "glGetTransformFeedbackVaryingsCHROMIUM",
3994 "bufsize is too small for result.");
3995 return;
3997 memcpy(info, &result[0], result.size());
4000 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
4001 GPU_CLIENT_SINGLE_THREAD_CHECK();
4002 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
4003 << texture << ")");
4004 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
4005 helper_->CommandBufferHelper::Flush();
4006 return gpu_control_->CreateStreamTexture(texture);
4009 void GLES2Implementation::PostSubBufferCHROMIUM(
4010 GLint x, GLint y, GLint width, GLint height) {
4011 GPU_CLIENT_SINGLE_THREAD_CHECK();
4012 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
4013 << x << ", " << y << ", " << width << ", " << height << ")");
4014 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
4015 "width", width, "height", height);
4017 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
4018 swap_buffers_tokens_.push(helper_->InsertToken());
4019 helper_->PostSubBufferCHROMIUM(x, y, width, height);
4020 helper_->CommandBufferHelper::Flush();
4021 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
4022 helper_->WaitForToken(swap_buffers_tokens_.front());
4023 swap_buffers_tokens_.pop();
4027 void GLES2Implementation::DeleteQueriesEXTHelper(
4028 GLsizei n, const GLuint* queries) {
4029 for (GLsizei ii = 0; ii < n; ++ii) {
4030 query_tracker_->RemoveQuery(queries[ii]);
4031 query_id_allocator_->FreeID(queries[ii]);
4034 helper_->DeleteQueriesEXTImmediate(n, queries);
4037 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
4038 GPU_CLIENT_SINGLE_THREAD_CHECK();
4039 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
4041 // TODO(gman): To be spec compliant IDs from other contexts sharing
4042 // resources need to return true here even though you can't share
4043 // queries across contexts?
4044 return query_tracker_->GetQuery(id) != NULL;
4047 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
4048 GPU_CLIENT_SINGLE_THREAD_CHECK();
4049 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
4050 << GLES2Util::GetStringQueryTarget(target)
4051 << ", " << id << ")");
4053 // if any outstanding queries INV_OP
4054 QueryMap::iterator it = current_queries_.find(target);
4055 if (it != current_queries_.end()) {
4056 SetGLError(
4057 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
4058 return;
4061 // id = 0 INV_OP
4062 if (id == 0) {
4063 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
4064 return;
4067 // if not GENned INV_OPERATION
4068 if (!query_id_allocator_->InUse(id)) {
4069 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "invalid id");
4070 return;
4073 // if id does not have an object
4074 QueryTracker::Query* query = query_tracker_->GetQuery(id);
4075 if (!query) {
4076 query = query_tracker_->CreateQuery(id, target);
4077 if (!query) {
4078 SetGLError(GL_OUT_OF_MEMORY,
4079 "glBeginQueryEXT",
4080 "transfer buffer allocation failed");
4081 return;
4083 } else if (query->target() != target) {
4084 SetGLError(
4085 GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
4086 return;
4089 current_queries_[target] = query;
4091 query->Begin(this);
4092 CheckGLError();
4095 void GLES2Implementation::EndQueryEXT(GLenum target) {
4096 GPU_CLIENT_SINGLE_THREAD_CHECK();
4097 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
4098 << GLES2Util::GetStringQueryTarget(target) << ")");
4099 // Don't do anything if the context is lost.
4100 if (helper_->IsContextLost()) {
4101 return;
4104 QueryMap::iterator it = current_queries_.find(target);
4105 if (it == current_queries_.end()) {
4106 SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
4107 return;
4110 QueryTracker::Query* query = it->second;
4111 query->End(this);
4112 current_queries_.erase(it);
4113 CheckGLError();
4116 void GLES2Implementation::GetQueryivEXT(
4117 GLenum target, GLenum pname, GLint* params) {
4118 GPU_CLIENT_SINGLE_THREAD_CHECK();
4119 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
4120 << GLES2Util::GetStringQueryTarget(target) << ", "
4121 << GLES2Util::GetStringQueryParameter(pname) << ", "
4122 << static_cast<const void*>(params) << ")");
4124 if (pname != GL_CURRENT_QUERY_EXT) {
4125 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
4126 return;
4128 QueryMap::iterator it = current_queries_.find(target);
4129 if (it != current_queries_.end()) {
4130 QueryTracker::Query* query = it->second;
4131 *params = query->id();
4132 } else {
4133 *params = 0;
4135 GPU_CLIENT_LOG(" " << *params);
4136 CheckGLError();
4139 void GLES2Implementation::GetQueryObjectuivEXT(
4140 GLuint id, GLenum pname, GLuint* params) {
4141 GPU_CLIENT_SINGLE_THREAD_CHECK();
4142 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
4143 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
4144 << static_cast<const void*>(params) << ")");
4146 QueryTracker::Query* query = query_tracker_->GetQuery(id);
4147 if (!query) {
4148 SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
4149 return;
4152 QueryMap::iterator it = current_queries_.find(query->target());
4153 if (it != current_queries_.end()) {
4154 SetGLError(
4155 GL_INVALID_OPERATION,
4156 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
4157 return;
4160 if (query->NeverUsed()) {
4161 SetGLError(
4162 GL_INVALID_OPERATION,
4163 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
4164 return;
4167 switch (pname) {
4168 case GL_QUERY_RESULT_EXT:
4169 if (!query->CheckResultsAvailable(helper_)) {
4170 helper_->WaitForToken(query->token());
4171 if (!query->CheckResultsAvailable(helper_)) {
4172 FinishHelper();
4173 CHECK(query->CheckResultsAvailable(helper_));
4176 *params = query->GetResult();
4177 break;
4178 case GL_QUERY_RESULT_AVAILABLE_EXT:
4179 *params = query->CheckResultsAvailable(helper_);
4180 break;
4181 default:
4182 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
4183 break;
4185 GPU_CLIENT_LOG(" " << *params);
4186 CheckGLError();
4189 void GLES2Implementation::DrawArraysInstancedANGLE(
4190 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
4191 GPU_CLIENT_SINGLE_THREAD_CHECK();
4192 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
4193 << GLES2Util::GetStringDrawMode(mode) << ", "
4194 << first << ", " << count << ", " << primcount << ")");
4195 if (count < 0) {
4196 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
4197 return;
4199 if (primcount < 0) {
4200 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
4201 return;
4203 if (primcount == 0) {
4204 return;
4206 bool simulated = false;
4207 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
4208 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
4209 &simulated)) {
4210 return;
4212 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
4213 RestoreArrayBuffer(simulated);
4214 CheckGLError();
4217 void GLES2Implementation::DrawElementsInstancedANGLE(
4218 GLenum mode, GLsizei count, GLenum type, const void* indices,
4219 GLsizei primcount) {
4220 GPU_CLIENT_SINGLE_THREAD_CHECK();
4221 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
4222 << GLES2Util::GetStringDrawMode(mode) << ", "
4223 << count << ", "
4224 << GLES2Util::GetStringIndexType(type) << ", "
4225 << static_cast<const void*>(indices) << ", "
4226 << primcount << ")");
4227 if (count < 0) {
4228 SetGLError(GL_INVALID_VALUE,
4229 "glDrawElementsInstancedANGLE", "count less than 0.");
4230 return;
4232 if (count == 0) {
4233 return;
4235 if (primcount < 0) {
4236 SetGLError(GL_INVALID_VALUE,
4237 "glDrawElementsInstancedANGLE", "primcount < 0");
4238 return;
4240 if (primcount == 0) {
4241 return;
4243 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
4244 !ValidateOffset("glDrawElementsInstancedANGLE",
4245 reinterpret_cast<GLintptr>(indices))) {
4246 return;
4248 GLuint offset = 0;
4249 bool simulated = false;
4250 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
4251 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
4252 indices, &offset, &simulated)) {
4253 return;
4255 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
4256 RestoreElementAndArrayBuffers(simulated);
4257 CheckGLError();
4260 void GLES2Implementation::GenMailboxCHROMIUM(
4261 GLbyte* mailbox) {
4262 GPU_CLIENT_SINGLE_THREAD_CHECK();
4263 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
4264 << static_cast<const void*>(mailbox) << ")");
4265 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
4267 gpu::Mailbox result = gpu::Mailbox::Generate();
4268 memcpy(mailbox, result.name, sizeof(result.name));
4271 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target,
4272 const GLbyte* data) {
4273 GPU_CLIENT_SINGLE_THREAD_CHECK();
4274 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
4275 << static_cast<const void*>(data) << ")");
4276 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4277 DCHECK(mailbox.Verify()) << "ProduceTextureCHROMIUM was passed a "
4278 "mailbox that was not generated by "
4279 "GenMailboxCHROMIUM.";
4280 helper_->ProduceTextureCHROMIUMImmediate(target, data);
4281 CheckGLError();
4284 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
4285 GLuint texture, GLenum target, const GLbyte* data) {
4286 GPU_CLIENT_SINGLE_THREAD_CHECK();
4287 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
4288 << static_cast<const void*>(data) << ")");
4289 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4290 DCHECK(mailbox.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
4291 "mailbox that was not generated by "
4292 "GenMailboxCHROMIUM.";
4293 helper_->ProduceTextureDirectCHROMIUMImmediate(texture, target, data);
4294 CheckGLError();
4297 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target,
4298 const GLbyte* data) {
4299 GPU_CLIENT_SINGLE_THREAD_CHECK();
4300 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
4301 << static_cast<const void*>(data) << ")");
4302 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4303 DCHECK(mailbox.Verify()) << "ConsumeTextureCHROMIUM was passed a "
4304 "mailbox that was not generated by "
4305 "GenMailboxCHROMIUM.";
4306 helper_->ConsumeTextureCHROMIUMImmediate(target, data);
4307 CheckGLError();
4310 GLuint GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
4311 GLenum target, const GLbyte* data) {
4312 GPU_CLIENT_SINGLE_THREAD_CHECK();
4313 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
4314 << static_cast<const void*>(data) << ")");
4315 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4316 DCHECK(mailbox.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
4317 "mailbox that was not generated by "
4318 "GenMailboxCHROMIUM.";
4319 GLuint client_id;
4320 GetIdHandler(id_namespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
4321 helper_->CreateAndConsumeTextureCHROMIUMImmediate(target,
4322 client_id, data);
4323 if (share_group_->bind_generates_resource())
4324 helper_->CommandBufferHelper::Flush();
4325 CheckGLError();
4326 return client_id;
4329 void GLES2Implementation::PushGroupMarkerEXT(
4330 GLsizei length, const GLchar* marker) {
4331 GPU_CLIENT_SINGLE_THREAD_CHECK();
4332 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
4333 << length << ", " << marker << ")");
4334 if (!marker) {
4335 marker = "";
4337 SetBucketAsString(
4338 kResultBucketId,
4339 (length ? std::string(marker, length) : std::string(marker)));
4340 helper_->PushGroupMarkerEXT(kResultBucketId);
4341 helper_->SetBucketSize(kResultBucketId, 0);
4342 debug_marker_manager_.PushGroup(
4343 length ? std::string(marker, length) : std::string(marker));
4346 void GLES2Implementation::InsertEventMarkerEXT(
4347 GLsizei length, const GLchar* marker) {
4348 GPU_CLIENT_SINGLE_THREAD_CHECK();
4349 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
4350 << length << ", " << marker << ")");
4351 if (!marker) {
4352 marker = "";
4354 SetBucketAsString(
4355 kResultBucketId,
4356 (length ? std::string(marker, length) : std::string(marker)));
4357 helper_->InsertEventMarkerEXT(kResultBucketId);
4358 helper_->SetBucketSize(kResultBucketId, 0);
4359 debug_marker_manager_.SetMarker(
4360 length ? std::string(marker, length) : std::string(marker));
4363 void GLES2Implementation::PopGroupMarkerEXT() {
4364 GPU_CLIENT_SINGLE_THREAD_CHECK();
4365 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
4366 helper_->PopGroupMarkerEXT();
4367 debug_marker_manager_.PopGroup();
4370 void GLES2Implementation::TraceBeginCHROMIUM(
4371 const char* category_name, const char* trace_name) {
4372 GPU_CLIENT_SINGLE_THREAD_CHECK();
4373 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
4374 << category_name << ", " << trace_name << ")");
4375 SetBucketAsCString(kResultBucketId, category_name);
4376 SetBucketAsCString(kResultBucketId + 1, trace_name);
4377 helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1);
4378 helper_->SetBucketSize(kResultBucketId, 0);
4379 helper_->SetBucketSize(kResultBucketId + 1, 0);
4380 current_trace_stack_++;
4383 void GLES2Implementation::TraceEndCHROMIUM() {
4384 GPU_CLIENT_SINGLE_THREAD_CHECK();
4385 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
4386 if (current_trace_stack_ == 0) {
4387 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
4388 "missing begin trace");
4389 return;
4391 helper_->TraceEndCHROMIUM();
4392 current_trace_stack_--;
4395 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
4396 GPU_CLIENT_SINGLE_THREAD_CHECK();
4397 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
4398 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
4399 switch (target) {
4400 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
4401 if (access != GL_READ_ONLY) {
4402 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
4403 return NULL;
4405 break;
4406 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
4407 if (access != GL_WRITE_ONLY) {
4408 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
4409 return NULL;
4411 break;
4412 default:
4413 SetGLError(
4414 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
4415 return NULL;
4417 GLuint buffer_id;
4418 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
4419 if (!buffer_id) {
4420 return NULL;
4422 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
4423 if (!buffer) {
4424 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
4425 return NULL;
4427 if (buffer->mapped()) {
4428 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
4429 return NULL;
4431 // Here we wait for previous transfer operations to be finished.
4432 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
4433 // with this method of synchronization. Until this is fixed,
4434 // MapBufferCHROMIUM will not block even if the transfer is not ready
4435 // for these calls.
4436 if (buffer->last_usage_token()) {
4437 helper_->WaitForToken(buffer->last_usage_token());
4438 buffer->set_last_usage_token(0);
4440 buffer->set_mapped(true);
4442 GPU_CLIENT_LOG(" returned " << buffer->address());
4443 CheckGLError();
4444 return buffer->address();
4447 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
4448 GPU_CLIENT_SINGLE_THREAD_CHECK();
4449 GPU_CLIENT_LOG(
4450 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
4451 GLuint buffer_id;
4452 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
4453 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
4455 if (!buffer_id) {
4456 return false;
4458 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
4459 if (!buffer) {
4460 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
4461 return false;
4463 if (!buffer->mapped()) {
4464 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
4465 return false;
4467 buffer->set_mapped(false);
4468 CheckGLError();
4469 return true;
4472 bool GLES2Implementation::EnsureAsyncUploadSync() {
4473 if (async_upload_sync_)
4474 return true;
4476 int32 shm_id;
4477 unsigned int shm_offset;
4478 void* mem = mapped_memory_->Alloc(sizeof(AsyncUploadSync),
4479 &shm_id,
4480 &shm_offset);
4481 if (!mem)
4482 return false;
4484 async_upload_sync_shm_id_ = shm_id;
4485 async_upload_sync_shm_offset_ = shm_offset;
4486 async_upload_sync_ = static_cast<AsyncUploadSync*>(mem);
4487 async_upload_sync_->Reset();
4489 return true;
4492 uint32 GLES2Implementation::NextAsyncUploadToken() {
4493 async_upload_token_++;
4494 if (async_upload_token_ == 0)
4495 async_upload_token_++;
4496 return async_upload_token_;
4499 void GLES2Implementation::PollAsyncUploads() {
4500 if (!async_upload_sync_)
4501 return;
4503 if (helper_->IsContextLost()) {
4504 DetachedAsyncUploadMemoryList::iterator it =
4505 detached_async_upload_memory_.begin();
4506 while (it != detached_async_upload_memory_.end()) {
4507 mapped_memory_->Free(it->first);
4508 it = detached_async_upload_memory_.erase(it);
4510 return;
4513 DetachedAsyncUploadMemoryList::iterator it =
4514 detached_async_upload_memory_.begin();
4515 while (it != detached_async_upload_memory_.end()) {
4516 if (HasAsyncUploadTokenPassed(it->second)) {
4517 mapped_memory_->Free(it->first);
4518 it = detached_async_upload_memory_.erase(it);
4519 } else {
4520 break;
4525 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
4526 // Free all completed unmanaged async uploads buffers.
4527 PollAsyncUploads();
4529 // Synchronously free rest of the unmanaged async upload buffers.
4530 if (!detached_async_upload_memory_.empty()) {
4531 WaitAllAsyncTexImage2DCHROMIUM();
4532 WaitForCmd();
4533 PollAsyncUploads();
4537 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
4538 GLenum target, GLint level, GLenum internalformat, GLsizei width,
4539 GLsizei height, GLint border, GLenum format, GLenum type,
4540 const void* pixels) {
4541 GPU_CLIENT_SINGLE_THREAD_CHECK();
4542 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
4543 << GLES2Util::GetStringTextureTarget(target) << ", "
4544 << level << ", "
4545 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
4546 << width << ", " << height << ", " << border << ", "
4547 << GLES2Util::GetStringTextureFormat(format) << ", "
4548 << GLES2Util::GetStringPixelType(type) << ", "
4549 << static_cast<const void*>(pixels) << ")");
4550 if (level < 0 || height < 0 || width < 0) {
4551 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
4552 return;
4554 if (border != 0) {
4555 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
4556 return;
4558 uint32 size;
4559 uint32 unpadded_row_size;
4560 uint32 padded_row_size;
4561 if (!GLES2Util::ComputeImageDataSizes(
4562 width, height, 1, format, type, unpack_alignment_, &size,
4563 &unpadded_row_size, &padded_row_size)) {
4564 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
4565 return;
4568 // If there's no data/buffer just issue the AsyncTexImage2D
4569 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
4570 helper_->AsyncTexImage2DCHROMIUM(
4571 target, level, internalformat, width, height, format, type,
4572 0, 0, 0, 0, 0);
4573 return;
4576 if (!EnsureAsyncUploadSync()) {
4577 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
4578 return;
4581 // Otherwise, async uploads require a transfer buffer to be bound.
4582 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
4583 // the buffer before the transfer is finished. (Currently such
4584 // synchronization has to be handled manually.)
4585 GLuint offset = ToGLuint(pixels);
4586 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
4587 bound_pixel_unpack_transfer_buffer_id_,
4588 "glAsyncTexImage2DCHROMIUM", offset, size);
4589 if (buffer && buffer->shm_id() != -1) {
4590 uint32 async_token = NextAsyncUploadToken();
4591 buffer->set_last_async_upload_token(async_token);
4592 helper_->AsyncTexImage2DCHROMIUM(
4593 target, level, internalformat, width, height, format, type,
4594 buffer->shm_id(), buffer->shm_offset() + offset,
4595 async_token,
4596 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
4600 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
4601 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
4602 GLsizei height, GLenum format, GLenum type, const void* pixels) {
4603 GPU_CLIENT_SINGLE_THREAD_CHECK();
4604 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
4605 << GLES2Util::GetStringTextureTarget(target) << ", "
4606 << level << ", "
4607 << xoffset << ", " << yoffset << ", "
4608 << width << ", " << height << ", "
4609 << GLES2Util::GetStringTextureFormat(format) << ", "
4610 << GLES2Util::GetStringPixelType(type) << ", "
4611 << static_cast<const void*>(pixels) << ")");
4612 if (level < 0 || height < 0 || width < 0) {
4613 SetGLError(
4614 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
4615 return;
4618 uint32 size;
4619 uint32 unpadded_row_size;
4620 uint32 padded_row_size;
4621 if (!GLES2Util::ComputeImageDataSizes(
4622 width, height, 1, format, type, unpack_alignment_, &size,
4623 &unpadded_row_size, &padded_row_size)) {
4624 SetGLError(
4625 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
4626 return;
4629 if (!EnsureAsyncUploadSync()) {
4630 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
4631 return;
4634 // Async uploads require a transfer buffer to be bound.
4635 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
4636 // the buffer before the transfer is finished. (Currently such
4637 // synchronization has to be handled manually.)
4638 GLuint offset = ToGLuint(pixels);
4639 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
4640 bound_pixel_unpack_transfer_buffer_id_,
4641 "glAsyncTexSubImage2DCHROMIUM", offset, size);
4642 if (buffer && buffer->shm_id() != -1) {
4643 uint32 async_token = NextAsyncUploadToken();
4644 buffer->set_last_async_upload_token(async_token);
4645 helper_->AsyncTexSubImage2DCHROMIUM(
4646 target, level, xoffset, yoffset, width, height, format, type,
4647 buffer->shm_id(), buffer->shm_offset() + offset,
4648 async_token,
4649 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
4653 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
4654 GPU_CLIENT_SINGLE_THREAD_CHECK();
4655 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
4656 << GLES2Util::GetStringTextureTarget(target) << ")");
4657 helper_->WaitAsyncTexImage2DCHROMIUM(target);
4658 CheckGLError();
4661 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
4662 GPU_CLIENT_SINGLE_THREAD_CHECK();
4663 GPU_CLIENT_LOG("[" << GetLogPrefix()
4664 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
4665 helper_->WaitAllAsyncTexImage2DCHROMIUM();
4666 CheckGLError();
4669 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
4670 GPU_CLIENT_SINGLE_THREAD_CHECK();
4671 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
4672 helper_->CommandBufferHelper::Flush();
4673 return gpu_control_->InsertSyncPoint();
4676 GLuint GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
4677 GPU_CLIENT_SINGLE_THREAD_CHECK();
4678 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
4679 DCHECK(capabilities_.future_sync_points);
4680 return gpu_control_->InsertFutureSyncPoint();
4683 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point) {
4684 GPU_CLIENT_SINGLE_THREAD_CHECK();
4685 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
4686 << sync_point << ")");
4687 DCHECK(capabilities_.future_sync_points);
4688 helper_->CommandBufferHelper::Flush();
4689 gpu_control_->RetireSyncPoint(sync_point);
4692 namespace {
4694 bool ValidImageFormat(GLenum internalformat) {
4695 switch (internalformat) {
4696 case GL_RGB:
4697 case GL_RGBA:
4698 return true;
4699 default:
4700 return false;
4704 bool ValidImageUsage(GLenum usage) {
4705 switch (usage) {
4706 case GL_MAP_CHROMIUM:
4707 case GL_SCANOUT_CHROMIUM:
4708 return true;
4709 default:
4710 return false;
4714 } // namespace
4716 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer,
4717 GLsizei width,
4718 GLsizei height,
4719 GLenum internalformat) {
4720 if (width <= 0) {
4721 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
4722 return 0;
4725 if (height <= 0) {
4726 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
4727 return 0;
4730 if (!ValidImageFormat(internalformat)) {
4731 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "invalid format");
4732 return 0;
4735 int32_t image_id =
4736 gpu_control_->CreateImage(buffer, width, height, internalformat);
4737 if (image_id < 0) {
4738 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "image_id < 0");
4739 return 0;
4741 return image_id;
4744 GLuint GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer,
4745 GLsizei width,
4746 GLsizei height,
4747 GLenum internalformat) {
4748 GPU_CLIENT_SINGLE_THREAD_CHECK();
4749 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
4750 << ", " << height << ", "
4751 << GLES2Util::GetStringImageInternalFormat(internalformat)
4752 << ")");
4753 GLuint image_id =
4754 CreateImageCHROMIUMHelper(buffer, width, height, internalformat);
4755 CheckGLError();
4756 return image_id;
4759 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
4760 // Flush the command stream to make sure all pending commands
4761 // that may refer to the image_id are executed on the service side.
4762 helper_->CommandBufferHelper::Flush();
4763 gpu_control_->DestroyImage(image_id);
4766 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
4767 GPU_CLIENT_SINGLE_THREAD_CHECK();
4768 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
4769 << image_id << ")");
4770 DestroyImageCHROMIUMHelper(image_id);
4771 CheckGLError();
4774 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
4775 GLsizei width,
4776 GLsizei height,
4777 GLenum internalformat,
4778 GLenum usage) {
4779 if (width <= 0) {
4780 SetGLError(
4781 GL_INVALID_VALUE, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
4782 return 0;
4785 if (height <= 0) {
4786 SetGLError(GL_INVALID_VALUE,
4787 "glCreateGpuMemoryBufferImageCHROMIUM",
4788 "height <= 0");
4789 return 0;
4792 if (!ValidImageFormat(internalformat)) {
4793 SetGLError(GL_INVALID_VALUE,
4794 "glCreateGpuMemoryBufferImageCHROMIUM",
4795 "invalid format");
4796 return 0;
4799 if (!ValidImageUsage(usage)) {
4800 SetGLError(GL_INVALID_VALUE,
4801 "glCreateGpuMemoryBufferImageCHROMIUM",
4802 "invalid usage");
4803 return 0;
4806 // Flush the command stream to ensure ordering in case the newly
4807 // returned image_id has recently been in use with a different buffer.
4808 helper_->CommandBufferHelper::Flush();
4809 int32_t image_id = gpu_control_->CreateGpuMemoryBufferImage(
4810 width, height, internalformat, usage);
4811 if (image_id < 0) {
4812 SetGLError(GL_OUT_OF_MEMORY,
4813 "glCreateGpuMemoryBufferImageCHROMIUM",
4814 "image_id < 0");
4815 return 0;
4817 return image_id;
4820 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
4821 GLsizei width,
4822 GLsizei height,
4823 GLenum internalformat,
4824 GLenum usage) {
4825 GPU_CLIENT_SINGLE_THREAD_CHECK();
4826 GPU_CLIENT_LOG("[" << GetLogPrefix()
4827 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
4828 << ", " << height << ", "
4829 << GLES2Util::GetStringImageInternalFormat(internalformat)
4830 << ", " << GLES2Util::GetStringImageUsage(usage) << ")");
4831 GLuint image_id = CreateGpuMemoryBufferImageCHROMIUMHelper(
4832 width, height, internalformat, usage);
4833 CheckGLError();
4834 return image_id;
4837 bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
4838 if (size < 0) {
4839 SetGLError(GL_INVALID_VALUE, func, "size < 0");
4840 return false;
4842 if (!FitInt32NonNegative<GLsizeiptr>(size)) {
4843 SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
4844 return false;
4846 return true;
4849 bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
4850 if (offset < 0) {
4851 SetGLError(GL_INVALID_VALUE, func, "offset < 0");
4852 return false;
4854 if (!FitInt32NonNegative<GLintptr>(offset)) {
4855 SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
4856 return false;
4858 return true;
4861 bool GLES2Implementation::GetSamplerParameterfvHelper(
4862 GLuint /* sampler */, GLenum /* pname */, GLfloat* /* params */) {
4863 // TODO(zmo): Implement client side caching.
4864 return false;
4867 bool GLES2Implementation::GetSamplerParameterivHelper(
4868 GLuint /* sampler */, GLenum /* pname */, GLint* /* params */) {
4869 // TODO(zmo): Implement client side caching.
4870 return false;
4873 bool GLES2Implementation::PackStringsToBucket(GLsizei count,
4874 const char* const* str,
4875 const GLint* length,
4876 const char* func_name) {
4877 DCHECK_LE(0, count);
4878 // Compute the total size.
4879 base::CheckedNumeric<size_t> total_size = count;
4880 total_size += 1;
4881 total_size *= sizeof(GLint);
4882 if (!total_size.IsValid()) {
4883 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
4884 return false;
4886 size_t header_size = total_size.ValueOrDefault(0);
4887 std::vector<GLint> header(count + 1);
4888 header[0] = static_cast<GLint>(count);
4889 for (GLsizei ii = 0; ii < count; ++ii) {
4890 GLint len = 0;
4891 if (str[ii]) {
4892 len = (length && length[ii] >= 0)
4893 ? length[ii]
4894 : base::checked_cast<GLint>(strlen(str[ii]));
4896 total_size += len;
4897 total_size += 1; // NULL at the end of each char array.
4898 if (!total_size.IsValid()) {
4899 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
4900 return false;
4902 header[ii + 1] = len;
4904 // Pack data into a bucket on the service.
4905 helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
4906 size_t offset = 0;
4907 for (GLsizei ii = 0; ii <= count; ++ii) {
4908 const char* src =
4909 (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
4910 base::CheckedNumeric<size_t> checked_size =
4911 (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
4912 if (ii > 0) {
4913 checked_size += 1; // NULL in the end.
4915 if (!checked_size.IsValid()) {
4916 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
4917 return false;
4919 size_t size = checked_size.ValueOrDefault(0);
4920 while (size) {
4921 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
4922 if (!buffer.valid() || buffer.size() == 0) {
4923 SetGLError(GL_OUT_OF_MEMORY, func_name, "too large");
4924 return false;
4926 size_t copy_size = buffer.size();
4927 if (ii > 0 && buffer.size() == size)
4928 --copy_size;
4929 if (copy_size)
4930 memcpy(buffer.address(), src, copy_size);
4931 if (copy_size < buffer.size()) {
4932 // Append NULL in the end.
4933 DCHECK(copy_size + 1 == buffer.size());
4934 char* str = reinterpret_cast<char*>(buffer.address());
4935 str[copy_size] = 0;
4937 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
4938 buffer.shm_id(), buffer.offset());
4939 offset += buffer.size();
4940 src += buffer.size();
4941 size -= buffer.size();
4944 DCHECK_EQ(total_size.ValueOrDefault(0), offset);
4945 return true;
4948 void GLES2Implementation::UniformBlockBinding(GLuint program,
4949 GLuint index,
4950 GLuint binding) {
4951 GPU_CLIENT_SINGLE_THREAD_CHECK();
4952 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
4953 << ", " << index << ", " << binding << ")");
4954 share_group_->program_info_manager()->UniformBlockBinding(
4955 this, program, index, binding);
4956 helper_->UniformBlockBinding(program, index, binding);
4957 CheckGLError();
4960 GLenum GLES2Implementation::ClientWaitSync(
4961 GLsync sync, GLbitfield flags, GLuint64 timeout) {
4962 GPU_CLIENT_SINGLE_THREAD_CHECK();
4963 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync
4964 << ", " << flags << ", " << timeout << ")");
4965 typedef cmds::ClientWaitSync::Result Result;
4966 Result* result = GetResultAs<Result*>();
4967 if (!result) {
4968 SetGLError(GL_OUT_OF_MEMORY, "ClientWaitSync", "");
4969 return GL_WAIT_FAILED;
4971 *result = GL_WAIT_FAILED;
4972 uint32_t v32_0 = 0, v32_1 = 0;
4973 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
4974 helper_->ClientWaitSync(
4975 ToGLuint(sync), flags, v32_0, v32_1,
4976 GetResultShmId(), GetResultShmOffset());
4977 WaitForCmd();
4978 GPU_CLIENT_LOG("returned " << *result);
4979 CheckGLError();
4980 return *result;
4983 void GLES2Implementation::WaitSync(
4984 GLsync sync, GLbitfield flags, GLuint64 timeout) {
4985 GPU_CLIENT_SINGLE_THREAD_CHECK();
4986 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync << ", "
4987 << flags << ", " << timeout << ")");
4988 uint32_t v32_0 = 0, v32_1 = 0;
4989 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
4990 helper_->WaitSync(ToGLuint(sync), flags, v32_0, v32_1);
4991 CheckGLError();
4994 // Include the auto-generated part of this file. We split this because it means
4995 // we can easily edit the non-auto generated parts right here in this file
4996 // instead of having to edit some template or the code generator.
4997 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
4999 } // namespace gles2
5000 } // namespace gpu