Fix crash on app list start page keyboard navigation with <4 apps.
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blob2dd95ec410850613d8279ef3ba12b7d0bb884469
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 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
751 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
752 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
753 Result* result = GetResultAs<Result*>();
754 if (!result) {
755 return 0;
757 *result = 0;
758 helper_->GetMaxValueInBufferCHROMIUM(
759 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
760 WaitForCmd();
761 return *result;
764 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
765 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
766 GPU_CLIENT_SINGLE_THREAD_CHECK();
767 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
768 << buffer_id << ", " << count << ", "
769 << GLES2Util::GetStringGetMaxIndexType(type)
770 << ", " << offset << ")");
771 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
772 buffer_id, count, type, offset);
773 GPU_CLIENT_LOG("returned " << result);
774 CheckGLError();
775 return result;
778 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
779 if (restore) {
780 RestoreArrayBuffer(restore);
781 // Restore the element array binding.
782 // We only need to restore it if it wasn't a client side array.
783 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
784 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
789 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
790 if (restore) {
791 // Restore the user's current binding.
792 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_);
796 void GLES2Implementation::DrawElements(
797 GLenum mode, GLsizei count, GLenum type, const void* indices) {
798 GPU_CLIENT_SINGLE_THREAD_CHECK();
799 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
800 << GLES2Util::GetStringDrawMode(mode) << ", "
801 << count << ", "
802 << GLES2Util::GetStringIndexType(type) << ", "
803 << static_cast<const void*>(indices) << ")");
804 if (count < 0) {
805 SetGLError(GL_INVALID_VALUE, "glDrawElements", "count less than 0.");
806 return;
808 if (count == 0) {
809 return;
811 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
812 !ValidateOffset("glDrawElements", reinterpret_cast<GLintptr>(indices))) {
813 return;
815 GLuint offset = 0;
816 bool simulated = false;
817 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
818 "glDrawElements", this, helper_, count, type, 0, indices,
819 &offset, &simulated)) {
820 return;
822 helper_->DrawElements(mode, count, type, offset);
823 RestoreElementAndArrayBuffers(simulated);
824 CheckGLError();
827 void GLES2Implementation::Flush() {
828 GPU_CLIENT_SINGLE_THREAD_CHECK();
829 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
830 // Insert the cmd to call glFlush
831 helper_->Flush();
832 // Flush our command buffer
833 // (tell the service to execute up to the flush cmd.)
834 helper_->CommandBufferHelper::Flush();
837 void GLES2Implementation::ShallowFlushCHROMIUM() {
838 GPU_CLIENT_SINGLE_THREAD_CHECK();
839 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
840 // Flush our command buffer
841 // (tell the service to execute up to the flush cmd.)
842 helper_->CommandBufferHelper::Flush();
843 // TODO(piman): Add the FreeEverything() logic here.
846 void GLES2Implementation::OrderingBarrierCHROMIUM() {
847 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOrderingBarrierCHROMIUM");
848 // Flush command buffer at the GPU channel level. May be implemented as
849 // Flush().
850 helper_->CommandBufferHelper::OrderingBarrier();
853 void GLES2Implementation::Finish() {
854 GPU_CLIENT_SINGLE_THREAD_CHECK();
855 FinishHelper();
858 void GLES2Implementation::ShallowFinishCHROMIUM() {
859 GPU_CLIENT_SINGLE_THREAD_CHECK();
860 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
861 // Flush our command buffer (tell the service to execute up to the flush cmd
862 // and don't return until it completes).
863 helper_->CommandBufferHelper::Finish();
866 void GLES2Implementation::FinishHelper() {
867 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
868 TRACE_EVENT0("gpu", "GLES2::Finish");
869 // Insert the cmd to call glFinish
870 helper_->Finish();
871 // Finish our command buffer
872 // (tell the service to execute up to the Finish cmd and wait for it to
873 // execute.)
874 helper_->CommandBufferHelper::Finish();
877 void GLES2Implementation::SwapBuffers() {
878 GPU_CLIENT_SINGLE_THREAD_CHECK();
879 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
880 // TODO(piman): Strictly speaking we'd want to insert the token after the
881 // swap, but the state update with the updated token might not have happened
882 // by the time the SwapBuffer callback gets called, forcing us to synchronize
883 // with the GPU process more than needed. So instead, make it happen before.
884 // All it means is that we could be slightly looser on the kMaxSwapBuffers
885 // semantics if the client doesn't use the callback mechanism, and by chance
886 // the scheduler yields between the InsertToken and the SwapBuffers.
887 swap_buffers_tokens_.push(helper_->InsertToken());
888 helper_->SwapBuffers();
889 helper_->CommandBufferHelper::Flush();
890 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
891 // compensate for TODO above.
892 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
893 helper_->WaitForToken(swap_buffers_tokens_.front());
894 swap_buffers_tokens_.pop();
898 void GLES2Implementation::SwapInterval(int interval) {
899 GPU_CLIENT_SINGLE_THREAD_CHECK();
900 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapInterval("
901 << interval << ")");
902 helper_->SwapInterval(interval);
905 void GLES2Implementation::BindAttribLocation(
906 GLuint program, GLuint index, const char* name) {
907 GPU_CLIENT_SINGLE_THREAD_CHECK();
908 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
909 << program << ", " << index << ", " << name << ")");
910 SetBucketAsString(kResultBucketId, name);
911 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
912 helper_->SetBucketSize(kResultBucketId, 0);
913 CheckGLError();
916 void GLES2Implementation::BindUniformLocationCHROMIUM(
917 GLuint program, GLint location, const char* name) {
918 GPU_CLIENT_SINGLE_THREAD_CHECK();
919 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
920 << program << ", " << location << ", " << name << ")");
921 SetBucketAsString(kResultBucketId, name);
922 helper_->BindUniformLocationCHROMIUMBucket(
923 program, location, kResultBucketId);
924 helper_->SetBucketSize(kResultBucketId, 0);
925 CheckGLError();
928 void GLES2Implementation::GetVertexAttribPointerv(
929 GLuint index, GLenum pname, void** ptr) {
930 GPU_CLIENT_SINGLE_THREAD_CHECK();
931 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
932 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
933 << static_cast<void*>(ptr) << ")");
934 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
935 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
936 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
937 typedef cmds::GetVertexAttribPointerv::Result Result;
938 Result* result = GetResultAs<Result*>();
939 if (!result) {
940 return;
942 result->SetNumResults(0);
943 helper_->GetVertexAttribPointerv(
944 index, pname, GetResultShmId(), GetResultShmOffset());
945 WaitForCmd();
946 result->CopyResult(ptr);
947 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
949 GPU_CLIENT_LOG_CODE_BLOCK({
950 for (int32 i = 0; i < num_results; ++i) {
951 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
954 CheckGLError();
957 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
958 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
959 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
960 SetGLError(
961 GL_INVALID_VALUE,
962 "glDeleteProgram", "id not created by this context.");
963 return false;
965 if (program == current_program_) {
966 current_program_ = 0;
968 return true;
971 void GLES2Implementation::DeleteProgramStub(
972 GLsizei n, const GLuint* programs) {
973 DCHECK_EQ(1, n);
974 share_group_->program_info_manager()->DeleteInfo(programs[0]);
975 helper_->DeleteProgram(programs[0]);
978 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
979 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
980 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
981 SetGLError(
982 GL_INVALID_VALUE,
983 "glDeleteShader", "id not created by this context.");
984 return false;
986 return true;
989 void GLES2Implementation::DeleteShaderStub(
990 GLsizei n, const GLuint* shaders) {
991 DCHECK_EQ(1, n);
992 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
993 helper_->DeleteShader(shaders[0]);
996 void GLES2Implementation::DeleteSyncHelper(GLsync sync) {
997 GLuint sync_uint = ToGLuint(sync);
998 if (!GetIdHandler(id_namespaces::kSyncs)->FreeIds(
999 this, 1, &sync_uint, &GLES2Implementation::DeleteSyncStub)) {
1000 SetGLError(
1001 GL_INVALID_VALUE,
1002 "glDeleteSync", "id not created by this context.");
1006 void GLES2Implementation::DeleteSyncStub(GLsizei n, const GLuint* syncs) {
1007 DCHECK_EQ(1, n);
1008 helper_->DeleteSync(syncs[0]);
1011 GLint GLES2Implementation::GetAttribLocationHelper(
1012 GLuint program, const char* name) {
1013 typedef cmds::GetAttribLocation::Result Result;
1014 Result* result = GetResultAs<Result*>();
1015 if (!result) {
1016 return -1;
1018 *result = -1;
1019 SetBucketAsCString(kResultBucketId, name);
1020 helper_->GetAttribLocation(
1021 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1022 WaitForCmd();
1023 helper_->SetBucketSize(kResultBucketId, 0);
1024 return *result;
1027 GLint GLES2Implementation::GetAttribLocation(
1028 GLuint program, const char* name) {
1029 GPU_CLIENT_SINGLE_THREAD_CHECK();
1030 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1031 << ", " << name << ")");
1032 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1033 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1034 this, program, name);
1035 GPU_CLIENT_LOG("returned " << loc);
1036 CheckGLError();
1037 return loc;
1040 GLint GLES2Implementation::GetUniformLocationHelper(
1041 GLuint program, const char* name) {
1042 typedef cmds::GetUniformLocation::Result Result;
1043 Result* result = GetResultAs<Result*>();
1044 if (!result) {
1045 return -1;
1047 *result = -1;
1048 SetBucketAsCString(kResultBucketId, name);
1049 helper_->GetUniformLocation(program, kResultBucketId,
1050 GetResultShmId(), GetResultShmOffset());
1051 WaitForCmd();
1052 helper_->SetBucketSize(kResultBucketId, 0);
1053 return *result;
1056 GLint GLES2Implementation::GetUniformLocation(
1057 GLuint program, const char* name) {
1058 GPU_CLIENT_SINGLE_THREAD_CHECK();
1059 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1060 << ", " << name << ")");
1061 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1062 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1063 this, program, name);
1064 GPU_CLIENT_LOG("returned " << loc);
1065 CheckGLError();
1066 return loc;
1069 bool GLES2Implementation::GetUniformIndicesHelper(
1070 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1071 typedef cmds::GetUniformIndices::Result Result;
1072 Result* result = GetResultAs<Result*>();
1073 if (!result) {
1074 return false;
1076 result->SetNumResults(0);
1077 if (!PackStringsToBucket(count, names, NULL, "glGetUniformIndices")) {
1078 return false;
1080 helper_->GetUniformIndices(program, kResultBucketId,
1081 GetResultShmId(), GetResultShmOffset());
1082 WaitForCmd();
1083 if (result->GetNumResults() != count) {
1084 return false;
1086 result->CopyResult(indices);
1087 return true;
1090 void GLES2Implementation::GetUniformIndices(
1091 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1092 GPU_CLIENT_SINGLE_THREAD_CHECK();
1093 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
1094 << ", " << count << ", " << names << ", " << indices << ")");
1095 TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
1096 if (count < 0) {
1097 SetGLError(GL_INVALID_VALUE, "glGetUniformIndices", "count < 0");
1098 return;
1100 if (count == 0) {
1101 return;
1103 bool success = share_group_->program_info_manager()->GetUniformIndices(
1104 this, program, count, names, indices);
1105 if (success) {
1106 GPU_CLIENT_LOG_CODE_BLOCK({
1107 for (GLsizei ii = 0; ii < count; ++ii) {
1108 GPU_CLIENT_LOG(" " << ii << ": " << indices[ii]);
1112 CheckGLError();
1115 bool GLES2Implementation::GetProgramivHelper(
1116 GLuint program, GLenum pname, GLint* params) {
1117 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1118 this, program, pname, params);
1119 GPU_CLIENT_LOG_CODE_BLOCK({
1120 if (got_value) {
1121 GPU_CLIENT_LOG(" 0: " << *params);
1124 return got_value;
1127 GLint GLES2Implementation::GetFragDataLocationHelper(
1128 GLuint program, const char* name) {
1129 typedef cmds::GetFragDataLocation::Result Result;
1130 Result* result = GetResultAs<Result*>();
1131 if (!result) {
1132 return -1;
1134 *result = -1;
1135 SetBucketAsCString(kResultBucketId, name);
1136 helper_->GetFragDataLocation(
1137 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1138 WaitForCmd();
1139 helper_->SetBucketSize(kResultBucketId, 0);
1140 return *result;
1143 GLint GLES2Implementation::GetFragDataLocation(
1144 GLuint program, const char* name) {
1145 GPU_CLIENT_SINGLE_THREAD_CHECK();
1146 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataLocation("
1147 << program << ", " << name << ")");
1148 TRACE_EVENT0("gpu", "GLES2::GetFragDataLocation");
1149 GLint loc = share_group_->program_info_manager()->GetFragDataLocation(
1150 this, program, name);
1151 GPU_CLIENT_LOG("returned " << loc);
1152 CheckGLError();
1153 return loc;
1156 GLuint GLES2Implementation::GetUniformBlockIndexHelper(
1157 GLuint program, const char* name) {
1158 typedef cmds::GetUniformBlockIndex::Result Result;
1159 Result* result = GetResultAs<Result*>();
1160 if (!result) {
1161 return GL_INVALID_INDEX;
1163 *result = GL_INVALID_INDEX;
1164 SetBucketAsCString(kResultBucketId, name);
1165 helper_->GetUniformBlockIndex(
1166 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1167 WaitForCmd();
1168 helper_->SetBucketSize(kResultBucketId, 0);
1169 return *result;
1172 GLuint GLES2Implementation::GetUniformBlockIndex(
1173 GLuint program, const char* name) {
1174 GPU_CLIENT_SINGLE_THREAD_CHECK();
1175 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformBlockIndex("
1176 << program << ", " << name << ")");
1177 TRACE_EVENT0("gpu", "GLES2::GetUniformBlockIndex");
1178 GLuint index = share_group_->program_info_manager()->GetUniformBlockIndex(
1179 this, program, name);
1180 GPU_CLIENT_LOG("returned " << index);
1181 CheckGLError();
1182 return index;
1185 void GLES2Implementation::LinkProgram(GLuint program) {
1186 GPU_CLIENT_SINGLE_THREAD_CHECK();
1187 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1188 helper_->LinkProgram(program);
1189 share_group_->program_info_manager()->CreateInfo(program);
1190 CheckGLError();
1193 void GLES2Implementation::ShaderBinary(
1194 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1195 GLsizei length) {
1196 GPU_CLIENT_SINGLE_THREAD_CHECK();
1197 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1198 << static_cast<const void*>(shaders) << ", "
1199 << GLES2Util::GetStringEnum(binaryformat) << ", "
1200 << static_cast<const void*>(binary) << ", "
1201 << length << ")");
1202 if (n < 0) {
1203 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1204 return;
1206 if (length < 0) {
1207 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1208 return;
1210 // TODO(gman): ShaderBinary should use buckets.
1211 unsigned int shader_id_size = n * sizeof(*shaders);
1212 ScopedTransferBufferArray<GLint> buffer(
1213 shader_id_size + length, helper_, transfer_buffer_);
1214 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1215 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1216 return;
1218 void* shader_ids = buffer.elements();
1219 void* shader_data = buffer.elements() + shader_id_size;
1220 memcpy(shader_ids, shaders, shader_id_size);
1221 memcpy(shader_data, binary, length);
1222 helper_->ShaderBinary(
1224 buffer.shm_id(),
1225 buffer.offset(),
1226 binaryformat,
1227 buffer.shm_id(),
1228 buffer.offset() + shader_id_size,
1229 length);
1230 CheckGLError();
1233 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1234 GPU_CLIENT_SINGLE_THREAD_CHECK();
1235 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1236 << GLES2Util::GetStringPixelStore(pname) << ", "
1237 << param << ")");
1238 switch (pname) {
1239 case GL_PACK_ALIGNMENT:
1240 pack_alignment_ = param;
1241 break;
1242 case GL_UNPACK_ALIGNMENT:
1243 unpack_alignment_ = param;
1244 break;
1245 case GL_UNPACK_ROW_LENGTH_EXT:
1246 unpack_row_length_ = param;
1247 return;
1248 case GL_UNPACK_IMAGE_HEIGHT:
1249 unpack_image_height_ = param;
1250 return;
1251 case GL_UNPACK_SKIP_ROWS_EXT:
1252 unpack_skip_rows_ = param;
1253 return;
1254 case GL_UNPACK_SKIP_PIXELS_EXT:
1255 unpack_skip_pixels_ = param;
1256 return;
1257 case GL_UNPACK_SKIP_IMAGES:
1258 unpack_skip_images_ = param;
1259 return;
1260 case GL_UNPACK_FLIP_Y_CHROMIUM:
1261 unpack_flip_y_ = (param != 0);
1262 break;
1263 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1264 pack_reverse_row_order_ =
1265 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1266 break;
1267 default:
1268 break;
1270 helper_->PixelStorei(pname, param);
1271 CheckGLError();
1274 void GLES2Implementation::VertexAttribIPointer(
1275 GLuint index, GLint size, GLenum type, GLsizei stride, const void* ptr) {
1276 GPU_CLIENT_SINGLE_THREAD_CHECK();
1277 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1278 << index << ", "
1279 << size << ", "
1280 << GLES2Util::GetStringVertexAttribType(type) << ", "
1281 << stride << ", "
1282 << ptr << ")");
1283 helper_->VertexAttribIPointer(index, size, type, stride, ToGLuint(ptr));
1284 CheckGLError();
1287 void GLES2Implementation::VertexAttribPointer(
1288 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1289 const void* ptr) {
1290 GPU_CLIENT_SINGLE_THREAD_CHECK();
1291 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1292 << index << ", "
1293 << size << ", "
1294 << GLES2Util::GetStringVertexAttribType(type) << ", "
1295 << GLES2Util::GetStringBool(normalized) << ", "
1296 << stride << ", "
1297 << ptr << ")");
1298 // Record the info on the client side.
1299 if (!vertex_array_object_manager_->SetAttribPointer(
1300 bound_array_buffer_id_, index, size, type, normalized, stride, ptr)) {
1301 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1302 "client side arrays are not allowed in vertex array objects.");
1303 return;
1305 if (!support_client_side_arrays_ || bound_array_buffer_id_ != 0) {
1306 // Only report NON client side buffers to the service.
1307 if (!ValidateOffset("glVertexAttribPointer",
1308 reinterpret_cast<GLintptr>(ptr))) {
1309 return;
1311 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1312 ToGLuint(ptr));
1314 CheckGLError();
1317 void GLES2Implementation::VertexAttribDivisorANGLE(
1318 GLuint index, GLuint divisor) {
1319 GPU_CLIENT_SINGLE_THREAD_CHECK();
1320 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1321 << index << ", "
1322 << divisor << ") ");
1323 // Record the info on the client side.
1324 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1325 helper_->VertexAttribDivisorANGLE(index, divisor);
1326 CheckGLError();
1329 void GLES2Implementation::BufferDataHelper(
1330 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1331 if (!ValidateSize("glBufferData", size))
1332 return;
1334 #if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
1335 // Do not upload uninitialized data. Even if it's not a bug, it can cause a
1336 // bogus MSan report during a readback later. This is because MSan doesn't
1337 // understand shared memory and would assume we were reading back the same
1338 // unintialized data.
1339 if (data) __msan_check_mem_is_initialized(data, size);
1340 #endif
1342 GLuint buffer_id;
1343 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1344 if (!buffer_id) {
1345 return;
1348 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1349 if (buffer)
1350 RemoveTransferBuffer(buffer);
1352 // Create new buffer.
1353 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1354 DCHECK(buffer);
1355 if (buffer->address() && data)
1356 memcpy(buffer->address(), data, size);
1357 return;
1360 if (size == 0) {
1361 return;
1364 // If there is no data just send BufferData
1365 if (!data) {
1366 helper_->BufferData(target, size, 0, 0, usage);
1367 return;
1370 // See if we can send all at once.
1371 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1372 if (!buffer.valid()) {
1373 return;
1376 if (buffer.size() >= static_cast<unsigned int>(size)) {
1377 memcpy(buffer.address(), data, size);
1378 helper_->BufferData(
1379 target,
1380 size,
1381 buffer.shm_id(),
1382 buffer.offset(),
1383 usage);
1384 return;
1387 // Make the buffer with BufferData then send via BufferSubData
1388 helper_->BufferData(target, size, 0, 0, usage);
1389 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1390 CheckGLError();
1393 void GLES2Implementation::BufferData(
1394 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1395 GPU_CLIENT_SINGLE_THREAD_CHECK();
1396 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1397 << GLES2Util::GetStringBufferTarget(target) << ", "
1398 << size << ", "
1399 << static_cast<const void*>(data) << ", "
1400 << GLES2Util::GetStringBufferUsage(usage) << ")");
1401 BufferDataHelper(target, size, data, usage);
1402 CheckGLError();
1405 void GLES2Implementation::BufferSubDataHelper(
1406 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1407 if (size == 0) {
1408 return;
1411 if (!ValidateSize("glBufferSubData", size) ||
1412 !ValidateOffset("glBufferSubData", offset)) {
1413 return;
1416 GLuint buffer_id;
1417 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1418 if (!buffer_id) {
1419 return;
1421 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1422 if (!buffer) {
1423 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1424 return;
1427 int32 end = 0;
1428 int32 buffer_size = buffer->size();
1429 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1430 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1431 return;
1434 if (buffer->address() && data)
1435 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1436 return;
1439 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1440 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1443 void GLES2Implementation::BufferSubDataHelperImpl(
1444 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1445 ScopedTransferBufferPtr* buffer) {
1446 DCHECK(buffer);
1447 DCHECK_GT(size, 0);
1449 const int8* source = static_cast<const int8*>(data);
1450 while (size) {
1451 if (!buffer->valid() || buffer->size() == 0) {
1452 buffer->Reset(size);
1453 if (!buffer->valid()) {
1454 return;
1457 memcpy(buffer->address(), source, buffer->size());
1458 helper_->BufferSubData(
1459 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1460 offset += buffer->size();
1461 source += buffer->size();
1462 size -= buffer->size();
1463 buffer->Release();
1467 void GLES2Implementation::BufferSubData(
1468 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1469 GPU_CLIENT_SINGLE_THREAD_CHECK();
1470 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1471 << GLES2Util::GetStringBufferTarget(target) << ", "
1472 << offset << ", " << size << ", "
1473 << static_cast<const void*>(data) << ")");
1474 BufferSubDataHelper(target, offset, size, data);
1475 CheckGLError();
1478 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
1479 int32 token = buffer->last_usage_token();
1480 uint32 async_token = buffer->last_async_upload_token();
1482 if (async_token) {
1483 if (HasAsyncUploadTokenPassed(async_token)) {
1484 buffer_tracker_->Free(buffer);
1485 } else {
1486 detached_async_upload_memory_.push_back(
1487 std::make_pair(buffer->address(), async_token));
1488 buffer_tracker_->Unmanage(buffer);
1490 } else if (token) {
1491 if (helper_->HasTokenPassed(token))
1492 buffer_tracker_->Free(buffer);
1493 else
1494 buffer_tracker_->FreePendingToken(buffer, token);
1495 } else {
1496 buffer_tracker_->Free(buffer);
1499 buffer_tracker_->RemoveBuffer(buffer->id());
1502 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1503 GLenum target,
1504 const char* function_name,
1505 GLuint* buffer_id) {
1506 *buffer_id = 0;
1508 switch (target) {
1509 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1510 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1511 break;
1512 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1513 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1514 break;
1515 default:
1516 // Unknown target
1517 return false;
1519 if (!*buffer_id) {
1520 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1522 return true;
1525 BufferTracker::Buffer*
1526 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1527 GLuint buffer_id,
1528 const char* function_name,
1529 GLuint offset, GLsizei size) {
1530 DCHECK(buffer_id);
1531 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1532 if (!buffer) {
1533 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1534 return NULL;
1536 if (buffer->mapped()) {
1537 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1538 return NULL;
1540 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1541 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1542 return NULL;
1544 return buffer;
1547 void GLES2Implementation::CompressedTexImage2D(
1548 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1549 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1550 GPU_CLIENT_SINGLE_THREAD_CHECK();
1551 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1552 << GLES2Util::GetStringTextureTarget(target) << ", "
1553 << level << ", "
1554 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1555 << width << ", " << height << ", " << border << ", "
1556 << image_size << ", "
1557 << static_cast<const void*>(data) << ")");
1558 if (width < 0 || height < 0 || level < 0) {
1559 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1560 return;
1562 if (border != 0) {
1563 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "border != 0");
1564 return;
1566 if (height == 0 || width == 0) {
1567 return;
1569 // If there's a pixel unpack buffer bound use it when issuing
1570 // CompressedTexImage2D.
1571 if (bound_pixel_unpack_transfer_buffer_id_) {
1572 GLuint offset = ToGLuint(data);
1573 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1574 bound_pixel_unpack_transfer_buffer_id_,
1575 "glCompressedTexImage2D", offset, image_size);
1576 if (buffer && buffer->shm_id() != -1) {
1577 helper_->CompressedTexImage2D(
1578 target, level, internalformat, width, height, image_size,
1579 buffer->shm_id(), buffer->shm_offset() + offset);
1580 buffer->set_last_usage_token(helper_->InsertToken());
1582 return;
1584 SetBucketContents(kResultBucketId, data, image_size);
1585 helper_->CompressedTexImage2DBucket(
1586 target, level, internalformat, width, height, kResultBucketId);
1587 // Free the bucket. This is not required but it does free up the memory.
1588 // and we don't have to wait for the result so from the client's perspective
1589 // it's cheap.
1590 helper_->SetBucketSize(kResultBucketId, 0);
1591 CheckGLError();
1594 void GLES2Implementation::CompressedTexSubImage2D(
1595 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1596 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1597 GPU_CLIENT_SINGLE_THREAD_CHECK();
1598 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1599 << GLES2Util::GetStringTextureTarget(target) << ", "
1600 << level << ", "
1601 << xoffset << ", " << yoffset << ", "
1602 << width << ", " << height << ", "
1603 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1604 << image_size << ", "
1605 << static_cast<const void*>(data) << ")");
1606 if (width < 0 || height < 0 || level < 0) {
1607 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1608 return;
1610 // If there's a pixel unpack buffer bound use it when issuing
1611 // CompressedTexSubImage2D.
1612 if (bound_pixel_unpack_transfer_buffer_id_) {
1613 GLuint offset = ToGLuint(data);
1614 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1615 bound_pixel_unpack_transfer_buffer_id_,
1616 "glCompressedTexSubImage2D", offset, image_size);
1617 if (buffer && buffer->shm_id() != -1) {
1618 helper_->CompressedTexSubImage2D(
1619 target, level, xoffset, yoffset, width, height, format, image_size,
1620 buffer->shm_id(), buffer->shm_offset() + offset);
1621 buffer->set_last_usage_token(helper_->InsertToken());
1622 CheckGLError();
1624 return;
1626 SetBucketContents(kResultBucketId, data, image_size);
1627 helper_->CompressedTexSubImage2DBucket(
1628 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1629 // Free the bucket. This is not required but it does free up the memory.
1630 // and we don't have to wait for the result so from the client's perspective
1631 // it's cheap.
1632 helper_->SetBucketSize(kResultBucketId, 0);
1633 CheckGLError();
1636 namespace {
1638 void CopyRectToBuffer(
1639 const void* pixels,
1640 uint32 height,
1641 uint32 unpadded_row_size,
1642 uint32 pixels_padded_row_size,
1643 bool flip_y,
1644 void* buffer,
1645 uint32 buffer_padded_row_size) {
1646 const int8* source = static_cast<const int8*>(pixels);
1647 int8* dest = static_cast<int8*>(buffer);
1648 if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
1649 if (flip_y) {
1650 dest += buffer_padded_row_size * (height - 1);
1652 // the last row is copied unpadded at the end
1653 for (; height > 1; --height) {
1654 memcpy(dest, source, buffer_padded_row_size);
1655 if (flip_y) {
1656 dest -= buffer_padded_row_size;
1657 } else {
1658 dest += buffer_padded_row_size;
1660 source += pixels_padded_row_size;
1662 memcpy(dest, source, unpadded_row_size);
1663 } else {
1664 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
1665 memcpy(dest, source, size);
1669 } // anonymous namespace
1671 void GLES2Implementation::TexImage2D(
1672 GLenum target, GLint level, GLint internalformat, GLsizei width,
1673 GLsizei height, GLint border, GLenum format, GLenum type,
1674 const void* pixels) {
1675 GPU_CLIENT_SINGLE_THREAD_CHECK();
1676 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1677 << GLES2Util::GetStringTextureTarget(target) << ", "
1678 << level << ", "
1679 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1680 << width << ", " << height << ", " << border << ", "
1681 << GLES2Util::GetStringTextureFormat(format) << ", "
1682 << GLES2Util::GetStringPixelType(type) << ", "
1683 << static_cast<const void*>(pixels) << ")");
1684 if (level < 0 || height < 0 || width < 0) {
1685 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
1686 return;
1688 if (border != 0) {
1689 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
1690 return;
1692 uint32 size;
1693 uint32 unpadded_row_size;
1694 uint32 padded_row_size;
1695 if (!GLES2Util::ComputeImageDataSizes(
1696 width, height, 1, format, type, unpack_alignment_, &size,
1697 &unpadded_row_size, &padded_row_size)) {
1698 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
1699 return;
1702 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1703 if (bound_pixel_unpack_transfer_buffer_id_) {
1704 GLuint offset = ToGLuint(pixels);
1705 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1706 bound_pixel_unpack_transfer_buffer_id_,
1707 "glTexImage2D", offset, size);
1708 if (buffer && buffer->shm_id() != -1) {
1709 helper_->TexImage2D(
1710 target, level, internalformat, width, height, format, type,
1711 buffer->shm_id(), buffer->shm_offset() + offset);
1712 buffer->set_last_usage_token(helper_->InsertToken());
1713 CheckGLError();
1715 return;
1718 // If there's no data just issue TexImage2D
1719 if (!pixels) {
1720 helper_->TexImage2D(
1721 target, level, internalformat, width, height, format, type,
1722 0, 0);
1723 CheckGLError();
1724 return;
1727 // compute the advance bytes per row for the src pixels
1728 uint32 src_padded_row_size;
1729 if (unpack_row_length_ > 0) {
1730 if (!GLES2Util::ComputeImagePaddedRowSize(
1731 unpack_row_length_, format, type, unpack_alignment_,
1732 &src_padded_row_size)) {
1733 SetGLError(
1734 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1735 return;
1737 } else {
1738 src_padded_row_size = padded_row_size;
1741 // advance pixels pointer past the skip rows and skip pixels
1742 pixels = reinterpret_cast<const int8*>(pixels) +
1743 unpack_skip_rows_ * src_padded_row_size;
1744 if (unpack_skip_pixels_) {
1745 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1746 pixels = reinterpret_cast<const int8*>(pixels) +
1747 unpack_skip_pixels_ * group_size;
1750 // Check if we can send it all at once.
1751 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1752 if (!buffer.valid()) {
1753 return;
1756 if (buffer.size() >= size) {
1757 CopyRectToBuffer(
1758 pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
1759 buffer.address(), padded_row_size);
1760 helper_->TexImage2D(
1761 target, level, internalformat, width, height, format, type,
1762 buffer.shm_id(), buffer.offset());
1763 CheckGLError();
1764 return;
1767 // No, so send it using TexSubImage2D.
1768 helper_->TexImage2D(
1769 target, level, internalformat, width, height, format, type,
1770 0, 0);
1771 TexSubImage2DImpl(
1772 target, level, 0, 0, width, height, format, type, unpadded_row_size,
1773 pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
1774 CheckGLError();
1777 void GLES2Implementation::TexImage3D(
1778 GLenum target, GLint level, GLint internalformat, GLsizei width,
1779 GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type,
1780 const void* pixels) {
1781 GPU_CLIENT_SINGLE_THREAD_CHECK();
1782 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D("
1783 << GLES2Util::GetStringTextureTarget(target) << ", "
1784 << level << ", "
1785 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1786 << width << ", " << height << ", " << depth << ", " << border << ", "
1787 << GLES2Util::GetStringTextureFormat(format) << ", "
1788 << GLES2Util::GetStringPixelType(type) << ", "
1789 << static_cast<const void*>(pixels) << ")");
1790 if (level < 0 || height < 0 || width < 0 || depth < 0) {
1791 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "dimension < 0");
1792 return;
1794 if (border != 0) {
1795 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "border != 0");
1796 return;
1798 uint32 size;
1799 uint32 unpadded_row_size;
1800 uint32 padded_row_size;
1801 if (!GLES2Util::ComputeImageDataSizes(
1802 width, height, depth, format, type, unpack_alignment_, &size,
1803 &unpadded_row_size, &padded_row_size)) {
1804 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large");
1805 return;
1808 // If there's a pixel unpack buffer bound use it when issuing TexImage3D.
1809 if (bound_pixel_unpack_transfer_buffer_id_) {
1810 GLuint offset = ToGLuint(pixels);
1811 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1812 bound_pixel_unpack_transfer_buffer_id_,
1813 "glTexImage3D", offset, size);
1814 if (buffer && buffer->shm_id() != -1) {
1815 helper_->TexImage3D(
1816 target, level, internalformat, width, height, depth, format, type,
1817 buffer->shm_id(), buffer->shm_offset() + offset);
1818 buffer->set_last_usage_token(helper_->InsertToken());
1819 CheckGLError();
1821 return;
1824 // If there's no data just issue TexImage3D
1825 if (!pixels) {
1826 helper_->TexImage3D(
1827 target, level, internalformat, width, height, depth, format, type,
1828 0, 0);
1829 CheckGLError();
1830 return;
1833 // compute the advance bytes per row for the src pixels
1834 uint32 src_padded_row_size;
1835 if (unpack_row_length_ > 0) {
1836 if (!GLES2Util::ComputeImagePaddedRowSize(
1837 unpack_row_length_, format, type, unpack_alignment_,
1838 &src_padded_row_size)) {
1839 SetGLError(
1840 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
1841 return;
1843 } else {
1844 src_padded_row_size = padded_row_size;
1846 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
1848 // advance pixels pointer past the skip images/rows/pixels
1849 pixels = reinterpret_cast<const int8*>(pixels) +
1850 unpack_skip_images_ * src_padded_row_size * src_height +
1851 unpack_skip_rows_ * src_padded_row_size;
1852 if (unpack_skip_pixels_) {
1853 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1854 pixels = reinterpret_cast<const int8*>(pixels) +
1855 unpack_skip_pixels_ * group_size;
1858 // Check if we can send it all at once.
1859 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1860 if (!buffer.valid()) {
1861 return;
1864 if (buffer.size() >= size) {
1865 void* buffer_pointer = buffer.address();
1866 for (GLsizei z = 0; z < depth; ++z) {
1867 // Only the last row of the last image is unpadded.
1868 uint32 src_unpadded_row_size =
1869 (z == depth - 1) ? unpadded_row_size : src_padded_row_size;
1870 // TODO(zmo): Ignore flip_y flag for now.
1871 CopyRectToBuffer(
1872 pixels, height, src_unpadded_row_size, src_padded_row_size, false,
1873 buffer_pointer, padded_row_size);
1874 pixels = reinterpret_cast<const int8*>(pixels) +
1875 src_padded_row_size * src_height;
1876 buffer_pointer = reinterpret_cast<int8*>(buffer_pointer) +
1877 padded_row_size * height;
1879 helper_->TexImage3D(
1880 target, level, internalformat, width, height, depth, format, type,
1881 buffer.shm_id(), buffer.offset());
1882 CheckGLError();
1883 return;
1886 // No, so send it using TexSubImage3D.
1887 helper_->TexImage3D(
1888 target, level, internalformat, width, height, depth, format, type,
1889 0, 0);
1890 TexSubImage3DImpl(
1891 target, level, 0, 0, 0, width, height, depth, format, type,
1892 unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &buffer,
1893 padded_row_size);
1894 CheckGLError();
1897 void GLES2Implementation::TexSubImage2D(
1898 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1899 GLsizei height, GLenum format, GLenum type, const void* pixels) {
1900 GPU_CLIENT_SINGLE_THREAD_CHECK();
1901 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1902 << GLES2Util::GetStringTextureTarget(target) << ", "
1903 << level << ", "
1904 << xoffset << ", " << yoffset << ", "
1905 << width << ", " << height << ", "
1906 << GLES2Util::GetStringTextureFormat(format) << ", "
1907 << GLES2Util::GetStringPixelType(type) << ", "
1908 << static_cast<const void*>(pixels) << ")");
1910 if (level < 0 || height < 0 || width < 0) {
1911 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
1912 return;
1914 if (height == 0 || width == 0) {
1915 return;
1918 uint32 temp_size;
1919 uint32 unpadded_row_size;
1920 uint32 padded_row_size;
1921 if (!GLES2Util::ComputeImageDataSizes(
1922 width, height, 1, format, type, unpack_alignment_, &temp_size,
1923 &unpadded_row_size, &padded_row_size)) {
1924 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
1925 return;
1928 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1929 if (bound_pixel_unpack_transfer_buffer_id_) {
1930 GLuint offset = ToGLuint(pixels);
1931 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1932 bound_pixel_unpack_transfer_buffer_id_,
1933 "glTexSubImage2D", offset, temp_size);
1934 if (buffer && buffer->shm_id() != -1) {
1935 helper_->TexSubImage2D(
1936 target, level, xoffset, yoffset, width, height, format, type,
1937 buffer->shm_id(), buffer->shm_offset() + offset, false);
1938 buffer->set_last_usage_token(helper_->InsertToken());
1939 CheckGLError();
1941 return;
1944 // compute the advance bytes per row for the src pixels
1945 uint32 src_padded_row_size;
1946 if (unpack_row_length_ > 0) {
1947 if (!GLES2Util::ComputeImagePaddedRowSize(
1948 unpack_row_length_, format, type, unpack_alignment_,
1949 &src_padded_row_size)) {
1950 SetGLError(
1951 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1952 return;
1954 } else {
1955 src_padded_row_size = padded_row_size;
1958 // advance pixels pointer past the skip rows and skip pixels
1959 pixels = reinterpret_cast<const int8*>(pixels) +
1960 unpack_skip_rows_ * src_padded_row_size;
1961 if (unpack_skip_pixels_) {
1962 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1963 pixels = reinterpret_cast<const int8*>(pixels) +
1964 unpack_skip_pixels_ * group_size;
1967 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
1968 TexSubImage2DImpl(
1969 target, level, xoffset, yoffset, width, height, format, type,
1970 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
1971 padded_row_size);
1972 CheckGLError();
1975 void GLES2Implementation::TexSubImage3D(
1976 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1977 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1978 const void* pixels) {
1979 GPU_CLIENT_SINGLE_THREAD_CHECK();
1980 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D("
1981 << GLES2Util::GetStringTextureTarget(target) << ", "
1982 << level << ", "
1983 << xoffset << ", " << yoffset << ", " << zoffset << ", "
1984 << width << ", " << height << ", " << depth << ", "
1985 << GLES2Util::GetStringTextureFormat(format) << ", "
1986 << GLES2Util::GetStringPixelType(type) << ", "
1987 << static_cast<const void*>(pixels) << ")");
1989 if (level < 0 || height < 0 || width < 0 || depth < 0) {
1990 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "dimension < 0");
1991 return;
1993 if (height == 0 || width == 0 || depth == 0) {
1994 return;
1997 uint32 temp_size;
1998 uint32 unpadded_row_size;
1999 uint32 padded_row_size;
2000 if (!GLES2Util::ComputeImageDataSizes(
2001 width, height, depth, format, type, unpack_alignment_, &temp_size,
2002 &unpadded_row_size, &padded_row_size)) {
2003 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "size to large");
2004 return;
2007 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2008 if (bound_pixel_unpack_transfer_buffer_id_) {
2009 GLuint offset = ToGLuint(pixels);
2010 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2011 bound_pixel_unpack_transfer_buffer_id_,
2012 "glTexSubImage3D", offset, temp_size);
2013 if (buffer && buffer->shm_id() != -1) {
2014 helper_->TexSubImage3D(
2015 target, level, xoffset, yoffset, zoffset, width, height, depth,
2016 format, type, buffer->shm_id(), buffer->shm_offset() + offset, false);
2017 buffer->set_last_usage_token(helper_->InsertToken());
2018 CheckGLError();
2020 return;
2023 // compute the advance bytes per row for the src pixels
2024 uint32 src_padded_row_size;
2025 if (unpack_row_length_ > 0) {
2026 if (!GLES2Util::ComputeImagePaddedRowSize(
2027 unpack_row_length_, format, type, unpack_alignment_,
2028 &src_padded_row_size)) {
2029 SetGLError(
2030 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2031 return;
2033 } else {
2034 src_padded_row_size = padded_row_size;
2036 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2038 // advance pixels pointer past the skip images/rows/pixels
2039 pixels = reinterpret_cast<const int8*>(pixels) +
2040 unpack_skip_images_ * src_padded_row_size * src_height +
2041 unpack_skip_rows_ * src_padded_row_size;
2042 if (unpack_skip_pixels_) {
2043 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2044 pixels = reinterpret_cast<const int8*>(pixels) +
2045 unpack_skip_pixels_ * group_size;
2048 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2049 TexSubImage3DImpl(
2050 target, level, xoffset, yoffset, zoffset, width, height, depth,
2051 format, type, unpadded_row_size, pixels, src_padded_row_size, GL_FALSE,
2052 &buffer, padded_row_size);
2053 CheckGLError();
2056 static GLint ComputeNumRowsThatFitInBuffer(
2057 uint32 padded_row_size, uint32 unpadded_row_size,
2058 unsigned int size, GLsizei remaining_rows) {
2059 DCHECK_GE(unpadded_row_size, 0u);
2060 if (padded_row_size == 0) {
2061 return 1;
2063 GLint num_rows = size / padded_row_size;
2064 if (num_rows + 1 == remaining_rows &&
2065 size - num_rows * padded_row_size >= unpadded_row_size) {
2066 num_rows++;
2068 return num_rows;
2071 void GLES2Implementation::TexSubImage2DImpl(
2072 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2073 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
2074 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
2075 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
2076 DCHECK(buffer);
2077 DCHECK_GE(level, 0);
2078 DCHECK_GT(height, 0);
2079 DCHECK_GT(width, 0);
2081 const int8* source = reinterpret_cast<const int8*>(pixels);
2082 GLint original_yoffset = yoffset;
2083 // Transfer by rows.
2084 while (height) {
2085 unsigned int desired_size =
2086 buffer_padded_row_size * (height - 1) + unpadded_row_size;
2087 if (!buffer->valid() || buffer->size() == 0) {
2088 buffer->Reset(desired_size);
2089 if (!buffer->valid()) {
2090 return;
2094 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2095 buffer_padded_row_size, unpadded_row_size, buffer->size(), height);
2096 num_rows = std::min(num_rows, height);
2097 CopyRectToBuffer(
2098 source, num_rows, unpadded_row_size, pixels_padded_row_size,
2099 unpack_flip_y_, buffer->address(), buffer_padded_row_size);
2100 GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
2101 helper_->TexSubImage2D(
2102 target, level, xoffset, y, width, num_rows, format, type,
2103 buffer->shm_id(), buffer->offset(), internal);
2104 buffer->Release();
2105 yoffset += num_rows;
2106 source += num_rows * pixels_padded_row_size;
2107 height -= num_rows;
2111 void GLES2Implementation::TexSubImage3DImpl(
2112 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei zoffset,
2113 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2114 uint32 unpadded_row_size, const void* pixels, uint32 pixels_padded_row_size,
2115 GLboolean internal, ScopedTransferBufferPtr* buffer,
2116 uint32 buffer_padded_row_size) {
2117 DCHECK(buffer);
2118 DCHECK_GE(level, 0);
2119 DCHECK_GT(height, 0);
2120 DCHECK_GT(width, 0);
2121 DCHECK_GT(depth, 0);
2122 const int8* source = reinterpret_cast<const int8*>(pixels);
2123 GLsizei total_rows = height * depth;
2124 GLint row_index = 0, depth_index = 0;
2125 while (total_rows) {
2126 // Each time, we either copy one or more images, or copy one or more rows
2127 // within a single image, depending on the buffer size limit.
2128 GLsizei max_rows;
2129 unsigned int desired_size;
2130 if (row_index > 0) {
2131 // We are in the middle of an image. Send the remaining of the image.
2132 max_rows = height - row_index;
2133 if (total_rows <= height) {
2134 // Last image, so last row is unpadded.
2135 desired_size = buffer_padded_row_size * (max_rows - 1) +
2136 unpadded_row_size;
2137 } else {
2138 desired_size = buffer_padded_row_size * max_rows;
2140 } else {
2141 // Send all the remaining data if possible.
2142 max_rows = total_rows;
2143 desired_size =
2144 buffer_padded_row_size * (max_rows - 1) + unpadded_row_size;
2146 if (!buffer->valid() || buffer->size() == 0) {
2147 buffer->Reset(desired_size);
2148 if (!buffer->valid()) {
2149 return;
2152 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2153 buffer_padded_row_size, unpadded_row_size, buffer->size(), total_rows);
2154 num_rows = std::min(num_rows, max_rows);
2155 GLint num_images = num_rows / height;
2156 GLsizei my_height, my_depth;
2157 if (num_images > 0) {
2158 num_rows = num_images * height;
2159 my_height = height;
2160 my_depth = num_images;
2161 } else {
2162 my_height = num_rows;
2163 my_depth = 1;
2166 // TODO(zmo): Ignore flip_y flag for now.
2167 if (num_images > 0) {
2168 int8* buffer_pointer = reinterpret_cast<int8*>(buffer->address());
2169 uint32 src_height =
2170 unpack_image_height_ > 0 ? unpack_image_height_ : height;
2171 uint32 image_size_dst = buffer_padded_row_size * height;
2172 uint32 image_size_src = pixels_padded_row_size * src_height;
2173 for (GLint ii = 0; ii < num_images; ++ii) {
2174 uint32 my_unpadded_row_size;
2175 if (total_rows == num_rows && ii + 1 == num_images)
2176 my_unpadded_row_size = unpadded_row_size;
2177 else
2178 my_unpadded_row_size = pixels_padded_row_size;
2179 CopyRectToBuffer(
2180 source + ii * image_size_src, my_height, my_unpadded_row_size,
2181 pixels_padded_row_size, false, buffer_pointer + ii * image_size_dst,
2182 buffer_padded_row_size);
2184 } else {
2185 uint32 my_unpadded_row_size;
2186 if (total_rows == num_rows)
2187 my_unpadded_row_size = unpadded_row_size;
2188 else
2189 my_unpadded_row_size = pixels_padded_row_size;
2190 CopyRectToBuffer(
2191 source, my_height, my_unpadded_row_size, pixels_padded_row_size,
2192 false, buffer->address(), buffer_padded_row_size);
2194 helper_->TexSubImage3D(
2195 target, level, xoffset, yoffset + row_index, zoffset + depth_index,
2196 width, my_height, my_depth,
2197 format, type, buffer->shm_id(), buffer->offset(), internal);
2198 buffer->Release();
2200 total_rows -= num_rows;
2201 if (total_rows > 0) {
2202 GLint num_image_paddings;
2203 if (num_images > 0) {
2204 DCHECK_EQ(row_index, 0);
2205 depth_index += num_images;
2206 num_image_paddings = num_images;
2207 } else {
2208 row_index = (row_index + my_height) % height;
2209 num_image_paddings = 0;
2210 if (my_height > 0 && row_index == 0) {
2211 depth_index++;
2212 num_image_paddings++;
2215 source += num_rows * pixels_padded_row_size;
2216 if (unpack_image_height_ > height && num_image_paddings > 0) {
2217 source += num_image_paddings * (unpack_image_height_ - height) *
2218 pixels_padded_row_size;
2224 bool GLES2Implementation::GetActiveAttribHelper(
2225 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2226 GLenum* type, char* name) {
2227 // Clear the bucket so if the command fails nothing will be in it.
2228 helper_->SetBucketSize(kResultBucketId, 0);
2229 typedef cmds::GetActiveAttrib::Result Result;
2230 Result* result = GetResultAs<Result*>();
2231 if (!result) {
2232 return false;
2234 // Set as failed so if the command fails we'll recover.
2235 result->success = false;
2236 helper_->GetActiveAttrib(program, index, kResultBucketId,
2237 GetResultShmId(), GetResultShmOffset());
2238 WaitForCmd();
2239 if (result->success) {
2240 if (size) {
2241 *size = result->size;
2243 if (type) {
2244 *type = result->type;
2246 if (length || name) {
2247 std::vector<int8> str;
2248 GetBucketContents(kResultBucketId, &str);
2249 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2250 std::max(static_cast<size_t>(0),
2251 str.size() - 1));
2252 if (length) {
2253 *length = max_size;
2255 if (name && bufsize > 0) {
2256 memcpy(name, &str[0], max_size);
2257 name[max_size] = '\0';
2261 return result->success != 0;
2264 void GLES2Implementation::GetActiveAttrib(
2265 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2266 GLenum* type, char* name) {
2267 GPU_CLIENT_SINGLE_THREAD_CHECK();
2268 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2269 << program << ", " << index << ", " << bufsize << ", "
2270 << static_cast<const void*>(length) << ", "
2271 << static_cast<const void*>(size) << ", "
2272 << static_cast<const void*>(type) << ", "
2273 << static_cast<const void*>(name) << ", ");
2274 if (bufsize < 0) {
2275 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
2276 return;
2278 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2279 bool success = share_group_->program_info_manager()->GetActiveAttrib(
2280 this, program, index, bufsize, length, size, type, name);
2281 if (success) {
2282 if (size) {
2283 GPU_CLIENT_LOG(" size: " << *size);
2285 if (type) {
2286 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2288 if (name) {
2289 GPU_CLIENT_LOG(" name: " << name);
2292 CheckGLError();
2295 bool GLES2Implementation::GetActiveUniformHelper(
2296 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2297 GLenum* type, char* name) {
2298 // Clear the bucket so if the command fails nothing will be in it.
2299 helper_->SetBucketSize(kResultBucketId, 0);
2300 typedef cmds::GetActiveUniform::Result Result;
2301 Result* result = GetResultAs<Result*>();
2302 if (!result) {
2303 return false;
2305 // Set as failed so if the command fails we'll recover.
2306 result->success = false;
2307 helper_->GetActiveUniform(program, index, kResultBucketId,
2308 GetResultShmId(), GetResultShmOffset());
2309 WaitForCmd();
2310 if (result->success) {
2311 if (size) {
2312 *size = result->size;
2314 if (type) {
2315 *type = result->type;
2317 if (length || name) {
2318 std::vector<int8> str;
2319 GetBucketContents(kResultBucketId, &str);
2320 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2321 std::max(static_cast<size_t>(0),
2322 str.size() - 1));
2323 if (length) {
2324 *length = max_size;
2326 if (name && bufsize > 0) {
2327 memcpy(name, &str[0], max_size);
2328 name[max_size] = '\0';
2332 return result->success != 0;
2335 void GLES2Implementation::GetActiveUniform(
2336 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2337 GLenum* type, char* name) {
2338 GPU_CLIENT_SINGLE_THREAD_CHECK();
2339 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2340 << program << ", " << index << ", " << bufsize << ", "
2341 << static_cast<const void*>(length) << ", "
2342 << static_cast<const void*>(size) << ", "
2343 << static_cast<const void*>(type) << ", "
2344 << static_cast<const void*>(name) << ", ");
2345 if (bufsize < 0) {
2346 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2347 return;
2349 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2350 bool success = share_group_->program_info_manager()->GetActiveUniform(
2351 this, program, index, bufsize, length, size, type, name);
2352 if (success) {
2353 if (size) {
2354 GPU_CLIENT_LOG(" size: " << *size);
2356 if (type) {
2357 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2359 if (name) {
2360 GPU_CLIENT_LOG(" name: " << name);
2363 CheckGLError();
2366 bool GLES2Implementation::GetActiveUniformBlockNameHelper(
2367 GLuint program, GLuint index, GLsizei bufsize,
2368 GLsizei* length, char* name) {
2369 DCHECK_LE(0, bufsize);
2370 // Clear the bucket so if the command fails nothing will be in it.
2371 helper_->SetBucketSize(kResultBucketId, 0);
2372 typedef cmds::GetActiveUniformBlockName::Result Result;
2373 Result* result = GetResultAs<Result*>();
2374 if (!result) {
2375 return false;
2377 // Set as failed so if the command fails we'll recover.
2378 *result = 0;
2379 helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
2380 GetResultShmId(), GetResultShmOffset());
2381 WaitForCmd();
2382 if (*result) {
2383 if (bufsize == 0) {
2384 if (length) {
2385 *length = 0;
2387 } else if (length || name) {
2388 std::vector<int8> str;
2389 GetBucketContents(kResultBucketId, &str);
2390 DCHECK(str.size() > 0);
2391 GLsizei max_size =
2392 std::min(bufsize, static_cast<GLsizei>(str.size())) - 1;
2393 if (length) {
2394 *length = max_size;
2396 if (name) {
2397 memcpy(name, &str[0], max_size);
2398 name[max_size] = '\0';
2402 return *result != 0;
2405 void GLES2Implementation::GetActiveUniformBlockName(
2406 GLuint program, GLuint index, GLsizei bufsize,
2407 GLsizei* length, char* name) {
2408 GPU_CLIENT_SINGLE_THREAD_CHECK();
2409 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
2410 << program << ", " << index << ", " << bufsize << ", "
2411 << static_cast<const void*>(length) << ", "
2412 << static_cast<const void*>(name) << ")");
2413 if (bufsize < 0) {
2414 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformBlockName", "bufsize < 0");
2415 return;
2417 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockName");
2418 bool success =
2419 share_group_->program_info_manager()->GetActiveUniformBlockName(
2420 this, program, index, bufsize, length, name);
2421 if (success) {
2422 if (name) {
2423 GPU_CLIENT_LOG(" name: " << name);
2426 CheckGLError();
2429 bool GLES2Implementation::GetActiveUniformBlockivHelper(
2430 GLuint program, GLuint index, GLenum pname, GLint* params) {
2431 typedef cmds::GetActiveUniformBlockiv::Result Result;
2432 Result* result = GetResultAs<Result*>();
2433 if (!result) {
2434 return false;
2436 result->SetNumResults(0);
2437 helper_->GetActiveUniformBlockiv(
2438 program, index, pname, GetResultShmId(), GetResultShmOffset());
2439 WaitForCmd();
2440 if (result->GetNumResults() > 0) {
2441 if (params) {
2442 result->CopyResult(params);
2444 GPU_CLIENT_LOG_CODE_BLOCK({
2445 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
2446 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2449 return true;
2451 return false;
2454 void GLES2Implementation::GetActiveUniformBlockiv(
2455 GLuint program, GLuint index, GLenum pname, GLint* params) {
2456 GPU_CLIENT_SINGLE_THREAD_CHECK();
2457 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
2458 << program << ", " << index << ", "
2459 << GLES2Util::GetStringUniformBlockParameter(pname) << ", "
2460 << static_cast<const void*>(params) << ")");
2461 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
2462 bool success =
2463 share_group_->program_info_manager()->GetActiveUniformBlockiv(
2464 this, program, index, pname, params);
2465 if (success) {
2466 if (params) {
2467 // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
2468 // be more than one value returned in params.
2469 GPU_CLIENT_LOG(" params: " << params[0]);
2472 CheckGLError();
2475 bool GLES2Implementation::GetActiveUniformsivHelper(
2476 GLuint program, GLsizei count, const GLuint* indices,
2477 GLenum pname, GLint* params) {
2478 typedef cmds::GetActiveUniformsiv::Result Result;
2479 Result* result = GetResultAs<Result*>();
2480 if (!result) {
2481 return false;
2483 result->SetNumResults(0);
2484 base::CheckedNumeric<size_t> bytes = static_cast<size_t>(count);
2485 bytes *= sizeof(GLuint);
2486 if (!bytes.IsValid()) {
2487 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count overflow");
2488 return false;
2490 SetBucketContents(kResultBucketId, indices, bytes.ValueOrDefault(0));
2491 helper_->GetActiveUniformsiv(
2492 program, kResultBucketId, pname, GetResultShmId(), GetResultShmOffset());
2493 WaitForCmd();
2494 bool success = result->GetNumResults() == count;
2495 if (success) {
2496 if (params) {
2497 result->CopyResult(params);
2499 GPU_CLIENT_LOG_CODE_BLOCK({
2500 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
2501 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2505 helper_->SetBucketSize(kResultBucketId, 0);
2506 return success;
2509 void GLES2Implementation::GetActiveUniformsiv(
2510 GLuint program, GLsizei count, const GLuint* indices,
2511 GLenum pname, GLint* params) {
2512 GPU_CLIENT_SINGLE_THREAD_CHECK();
2513 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv("
2514 << program << ", " << count << ", "
2515 << static_cast<const void*>(indices) << ", "
2516 << GLES2Util::GetStringUniformParameter(pname) << ", "
2517 << static_cast<const void*>(params) << ")");
2518 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
2519 if (count < 0) {
2520 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count < 0");
2521 return;
2523 bool success = share_group_->program_info_manager()->GetActiveUniformsiv(
2524 this, program, count, indices, pname, params);
2525 if (success) {
2526 if (params) {
2527 GPU_CLIENT_LOG_CODE_BLOCK({
2528 for (GLsizei ii = 0; ii < count; ++ii) {
2529 GPU_CLIENT_LOG(" " << ii << ": " << params[ii]);
2534 CheckGLError();
2537 void GLES2Implementation::GetAttachedShaders(
2538 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
2539 GPU_CLIENT_SINGLE_THREAD_CHECK();
2540 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2541 << program << ", " << maxcount << ", "
2542 << static_cast<const void*>(count) << ", "
2543 << static_cast<const void*>(shaders) << ", ");
2544 if (maxcount < 0) {
2545 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
2546 return;
2548 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2549 typedef cmds::GetAttachedShaders::Result Result;
2550 uint32 size = Result::ComputeSize(maxcount);
2551 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
2552 if (!result) {
2553 return;
2555 result->SetNumResults(0);
2556 helper_->GetAttachedShaders(
2557 program,
2558 transfer_buffer_->GetShmId(),
2559 transfer_buffer_->GetOffset(result),
2560 size);
2561 int32 token = helper_->InsertToken();
2562 WaitForCmd();
2563 if (count) {
2564 *count = result->GetNumResults();
2566 result->CopyResult(shaders);
2567 GPU_CLIENT_LOG_CODE_BLOCK({
2568 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2569 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2572 transfer_buffer_->FreePendingToken(result, token);
2573 CheckGLError();
2576 void GLES2Implementation::GetShaderPrecisionFormat(
2577 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
2578 GPU_CLIENT_SINGLE_THREAD_CHECK();
2579 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2580 << GLES2Util::GetStringShaderType(shadertype) << ", "
2581 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
2582 << static_cast<const void*>(range) << ", "
2583 << static_cast<const void*>(precision) << ", ");
2584 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2585 typedef cmds::GetShaderPrecisionFormat::Result Result;
2586 Result* result = GetResultAs<Result*>();
2587 if (!result) {
2588 return;
2591 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
2592 GLStaticState::ShaderPrecisionMap::iterator i =
2593 static_state_.shader_precisions.find(key);
2594 if (i != static_state_.shader_precisions.end()) {
2595 *result = i->second;
2596 } else {
2597 result->success = false;
2598 helper_->GetShaderPrecisionFormat(
2599 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
2600 WaitForCmd();
2601 if (result->success)
2602 static_state_.shader_precisions[key] = *result;
2605 if (result->success) {
2606 if (range) {
2607 range[0] = result->min_range;
2608 range[1] = result->max_range;
2609 GPU_CLIENT_LOG(" min_range: " << range[0]);
2610 GPU_CLIENT_LOG(" min_range: " << range[1]);
2612 if (precision) {
2613 precision[0] = result->precision;
2614 GPU_CLIENT_LOG(" min_range: " << precision[0]);
2617 CheckGLError();
2620 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
2621 const char* result = NULL;
2622 // Clears the bucket so if the command fails nothing will be in it.
2623 helper_->SetBucketSize(kResultBucketId, 0);
2624 helper_->GetString(name, kResultBucketId);
2625 std::string str;
2626 if (GetBucketAsString(kResultBucketId, &str)) {
2627 // Adds extensions implemented on client side only.
2628 switch (name) {
2629 case GL_EXTENSIONS:
2630 str += std::string(str.empty() ? "" : " ") +
2631 "GL_CHROMIUM_flipy "
2632 "GL_EXT_unpack_subimage "
2633 "GL_CHROMIUM_map_sub";
2634 if (capabilities_.image)
2635 str += " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
2636 if (capabilities_.future_sync_points)
2637 str += " GL_CHROMIUM_future_sync_point";
2638 break;
2639 default:
2640 break;
2643 // Because of WebGL the extensions can change. We have to cache each unique
2644 // result since we don't know when the client will stop referring to a
2645 // previous one it queries.
2646 GLStringMap::iterator it = gl_strings_.find(name);
2647 if (it == gl_strings_.end()) {
2648 std::set<std::string> strings;
2649 std::pair<GLStringMap::iterator, bool> insert_result =
2650 gl_strings_.insert(std::make_pair(name, strings));
2651 DCHECK(insert_result.second);
2652 it = insert_result.first;
2654 std::set<std::string>& string_set = it->second;
2655 std::set<std::string>::const_iterator sit = string_set.find(str);
2656 if (sit != string_set.end()) {
2657 result = sit->c_str();
2658 } else {
2659 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2660 string_set.insert(str);
2661 DCHECK(insert_result.second);
2662 result = insert_result.first->c_str();
2665 return reinterpret_cast<const GLubyte*>(result);
2668 const GLubyte* GLES2Implementation::GetString(GLenum name) {
2669 GPU_CLIENT_SINGLE_THREAD_CHECK();
2670 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2671 << GLES2Util::GetStringStringType(name) << ")");
2672 TRACE_EVENT0("gpu", "GLES2::GetString");
2673 const GLubyte* result = GetStringHelper(name);
2674 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
2675 CheckGLError();
2676 return result;
2679 bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
2680 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2681 GLenum* type, char* name) {
2682 // Clear the bucket so if the command fails nothing will be in it.
2683 helper_->SetBucketSize(kResultBucketId, 0);
2684 typedef cmds::GetTransformFeedbackVarying::Result Result;
2685 Result* result = GetResultAs<Result*>();
2686 if (!result) {
2687 return false;
2689 // Set as failed so if the command fails we'll recover.
2690 result->success = false;
2691 helper_->GetTransformFeedbackVarying(
2692 program, index, kResultBucketId, GetResultShmId(), GetResultShmOffset());
2693 WaitForCmd();
2694 if (result->success) {
2695 if (size) {
2696 *size = result->size;
2698 if (type) {
2699 *type = result->type;
2701 if (length || name) {
2702 std::vector<int8> str;
2703 GetBucketContents(kResultBucketId, &str);
2704 GLsizei max_size = std::min(bufsize, static_cast<GLsizei>(str.size()));
2705 if (max_size > 0) {
2706 --max_size;
2708 if (length) {
2709 *length = max_size;
2711 if (name) {
2712 if (max_size > 0) {
2713 memcpy(name, &str[0], max_size);
2714 name[max_size] = '\0';
2715 } else if (bufsize > 0) {
2716 name[0] = '\0';
2721 return result->success != 0;
2724 void GLES2Implementation::GetTransformFeedbackVarying(
2725 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2726 GLenum* type, char* name) {
2727 GPU_CLIENT_SINGLE_THREAD_CHECK();
2728 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
2729 << program << ", " << index << ", " << bufsize << ", "
2730 << static_cast<const void*>(length) << ", "
2731 << static_cast<const void*>(size) << ", "
2732 << static_cast<const void*>(type) << ", "
2733 << static_cast<const void*>(name) << ", ");
2734 if (bufsize < 0) {
2735 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVarying",
2736 "bufsize < 0");
2737 return;
2739 TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
2740 bool success =
2741 share_group_->program_info_manager()->GetTransformFeedbackVarying(
2742 this, program, index, bufsize, length, size, type, name);
2743 if (success) {
2744 if (size) {
2745 GPU_CLIENT_LOG(" size: " << *size);
2747 if (type) {
2748 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2750 if (name) {
2751 GPU_CLIENT_LOG(" name: " << name);
2754 CheckGLError();
2757 void GLES2Implementation::GetUniformfv(
2758 GLuint program, GLint location, GLfloat* params) {
2759 GPU_CLIENT_SINGLE_THREAD_CHECK();
2760 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2761 << program << ", " << location << ", "
2762 << static_cast<const void*>(params) << ")");
2763 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2764 typedef cmds::GetUniformfv::Result Result;
2765 Result* result = GetResultAs<Result*>();
2766 if (!result) {
2767 return;
2769 result->SetNumResults(0);
2770 helper_->GetUniformfv(
2771 program, location, GetResultShmId(), GetResultShmOffset());
2772 WaitForCmd();
2773 result->CopyResult(params);
2774 GPU_CLIENT_LOG_CODE_BLOCK({
2775 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2776 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2779 CheckGLError();
2782 void GLES2Implementation::GetUniformiv(
2783 GLuint program, GLint location, GLint* params) {
2784 GPU_CLIENT_SINGLE_THREAD_CHECK();
2785 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2786 << program << ", " << location << ", "
2787 << static_cast<const void*>(params) << ")");
2788 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2789 typedef cmds::GetUniformiv::Result Result;
2790 Result* result = GetResultAs<Result*>();
2791 if (!result) {
2792 return;
2794 result->SetNumResults(0);
2795 helper_->GetUniformiv(
2796 program, location, GetResultShmId(), GetResultShmOffset());
2797 WaitForCmd();
2798 GetResultAs<cmds::GetUniformfv::Result*>()->CopyResult(params);
2799 GPU_CLIENT_LOG_CODE_BLOCK({
2800 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2801 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2804 CheckGLError();
2807 void GLES2Implementation::ReadPixels(
2808 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
2809 GLenum type, void* pixels) {
2810 GPU_CLIENT_SINGLE_THREAD_CHECK();
2811 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2812 << xoffset << ", " << yoffset << ", "
2813 << width << ", " << height << ", "
2814 << GLES2Util::GetStringReadPixelFormat(format) << ", "
2815 << GLES2Util::GetStringPixelType(type) << ", "
2816 << static_cast<const void*>(pixels) << ")");
2817 if (width < 0 || height < 0) {
2818 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
2819 return;
2821 if (width == 0 || height == 0) {
2822 return;
2825 // glReadPixel pads the size of each row of pixels by an amount specified by
2826 // glPixelStorei. So, we have to take that into account both in the fact that
2827 // the pixels returned from the ReadPixel command will include that padding
2828 // and that when we copy the results to the user's buffer we need to not
2829 // write those padding bytes but leave them as they are.
2831 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2832 typedef cmds::ReadPixels::Result Result;
2834 int8* dest = reinterpret_cast<int8*>(pixels);
2835 uint32 temp_size;
2836 uint32 unpadded_row_size;
2837 uint32 padded_row_size;
2838 if (!GLES2Util::ComputeImageDataSizes(
2839 width, 2, 1, format, type, pack_alignment_, &temp_size,
2840 &unpadded_row_size, &padded_row_size)) {
2841 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
2842 return;
2845 if (bound_pixel_pack_transfer_buffer_id_) {
2846 GLuint offset = ToGLuint(pixels);
2847 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2848 bound_pixel_pack_transfer_buffer_id_,
2849 "glReadPixels", offset, padded_row_size * height);
2850 if (buffer && buffer->shm_id() != -1) {
2851 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
2852 buffer->shm_id(), buffer->shm_offset(),
2853 0, 0, true);
2854 CheckGLError();
2856 return;
2859 if (!pixels) {
2860 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
2861 return;
2864 // Transfer by rows.
2865 // The max rows we can transfer.
2866 while (height) {
2867 GLsizei desired_size = padded_row_size * (height - 1) + unpadded_row_size;
2868 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
2869 if (!buffer.valid()) {
2870 return;
2872 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2873 padded_row_size, unpadded_row_size, buffer.size(), height);
2874 num_rows = std::min(num_rows, height);
2875 // NOTE: We must look up the address of the result area AFTER allocation
2876 // of the transfer buffer since the transfer buffer may be reallocated.
2877 Result* result = GetResultAs<Result*>();
2878 if (!result) {
2879 return;
2881 *result = 0; // mark as failed.
2882 helper_->ReadPixels(
2883 xoffset, yoffset, width, num_rows, format, type,
2884 buffer.shm_id(), buffer.offset(),
2885 GetResultShmId(), GetResultShmOffset(),
2886 false);
2887 WaitForCmd();
2888 if (*result != 0) {
2889 // when doing a y-flip we have to iterate through top-to-bottom chunks
2890 // of the dst. The service side handles reversing the rows within a
2891 // chunk.
2892 int8* rows_dst;
2893 if (pack_reverse_row_order_) {
2894 rows_dst = dest + (height - num_rows) * padded_row_size;
2895 } else {
2896 rows_dst = dest;
2898 // We have to copy 1 row at a time to avoid writing pad bytes.
2899 const int8* src = static_cast<const int8*>(buffer.address());
2900 for (GLint yy = 0; yy < num_rows; ++yy) {
2901 memcpy(rows_dst, src, unpadded_row_size);
2902 rows_dst += padded_row_size;
2903 src += padded_row_size;
2905 if (!pack_reverse_row_order_) {
2906 dest = rows_dst;
2909 // If it was not marked as successful exit.
2910 if (*result == 0) {
2911 return;
2913 yoffset += num_rows;
2914 height -= num_rows;
2916 CheckGLError();
2919 void GLES2Implementation::ActiveTexture(GLenum texture) {
2920 GPU_CLIENT_SINGLE_THREAD_CHECK();
2921 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2922 << GLES2Util::GetStringEnum(texture) << ")");
2923 GLuint texture_index = texture - GL_TEXTURE0;
2924 if (texture_index >=
2925 static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
2926 SetGLErrorInvalidEnum(
2927 "glActiveTexture", texture, "texture");
2928 return;
2931 active_texture_unit_ = texture_index;
2932 helper_->ActiveTexture(texture);
2933 CheckGLError();
2936 void GLES2Implementation::GenBuffersHelper(
2937 GLsizei /* n */, const GLuint* /* buffers */) {
2940 void GLES2Implementation::GenFramebuffersHelper(
2941 GLsizei /* n */, const GLuint* /* framebuffers */) {
2944 void GLES2Implementation::GenRenderbuffersHelper(
2945 GLsizei /* n */, const GLuint* /* renderbuffers */) {
2948 void GLES2Implementation::GenTexturesHelper(
2949 GLsizei /* n */, const GLuint* /* textures */) {
2952 void GLES2Implementation::GenVertexArraysOESHelper(
2953 GLsizei n, const GLuint* arrays) {
2954 vertex_array_object_manager_->GenVertexArrays(n, arrays);
2957 void GLES2Implementation::GenQueriesEXTHelper(
2958 GLsizei /* n */, const GLuint* /* queries */) {
2961 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
2962 GLsizei /* n */,
2963 const GLuint* /* valuebuffers */) {
2966 void GLES2Implementation::GenSamplersHelper(
2967 GLsizei /* n */, const GLuint* /* samplers */) {
2970 void GLES2Implementation::GenTransformFeedbacksHelper(
2971 GLsizei /* n */, const GLuint* /* transformfeedbacks */) {
2974 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
2975 // generates a new resource. On newer versions of OpenGL they don't. The code
2976 // related to binding below will need to change if we switch to the new OpenGL
2977 // model. Specifically it assumes a bind will succeed which is always true in
2978 // the old model but possibly not true in the new model if another context has
2979 // deleted the resource.
2981 // NOTE #2: There is a bug in some BindXXXHelpers, that IDs might be marked as
2982 // used even when Bind has failed. However, the bug is minor compared to the
2983 // overhead & duplicated checking in client side.
2985 void GLES2Implementation::BindBufferHelper(
2986 GLenum target, GLuint buffer_id) {
2987 // TODO(gman): See note #1 above.
2988 bool changed = false;
2989 switch (target) {
2990 case GL_ARRAY_BUFFER:
2991 if (bound_array_buffer_id_ != buffer_id) {
2992 bound_array_buffer_id_ = buffer_id;
2993 changed = true;
2995 break;
2996 case GL_ELEMENT_ARRAY_BUFFER:
2997 changed = vertex_array_object_manager_->BindElementArray(buffer_id);
2998 break;
2999 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3000 bound_pixel_pack_transfer_buffer_id_ = buffer_id;
3001 break;
3002 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3003 bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
3004 break;
3005 default:
3006 changed = true;
3007 break;
3009 // TODO(gman): See note #2 above.
3010 if (changed) {
3011 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3012 this, target, buffer_id, &GLES2Implementation::BindBufferStub);
3016 void GLES2Implementation::BindBufferStub(GLenum target, GLuint buffer) {
3017 helper_->BindBuffer(target, buffer);
3018 if (share_group_->bind_generates_resource())
3019 helper_->CommandBufferHelper::Flush();
3022 void GLES2Implementation::BindBufferBaseHelper(
3023 GLenum target, GLuint index, GLuint buffer_id) {
3024 // TODO(zmo): See note #1 above.
3025 // TODO(zmo): See note #2 above.
3026 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3027 this, target, index, buffer_id, &GLES2Implementation::BindBufferBaseStub);
3030 void GLES2Implementation::BindBufferBaseStub(
3031 GLenum target, GLuint index, GLuint buffer) {
3032 helper_->BindBufferBase(target, index, buffer);
3033 if (share_group_->bind_generates_resource())
3034 helper_->CommandBufferHelper::Flush();
3037 void GLES2Implementation::BindBufferRangeHelper(
3038 GLenum target, GLuint index, GLuint buffer_id,
3039 GLintptr offset, GLsizeiptr size) {
3040 // TODO(zmo): See note #1 above.
3041 // TODO(zmo): See note #2 above.
3042 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3043 this, target, index, buffer_id, offset, size,
3044 &GLES2Implementation::BindBufferRangeStub);
3047 void GLES2Implementation::BindBufferRangeStub(
3048 GLenum target, GLuint index, GLuint buffer,
3049 GLintptr offset, GLsizeiptr size) {
3050 helper_->BindBufferRange(target, index, buffer, offset, size);
3051 if (share_group_->bind_generates_resource())
3052 helper_->CommandBufferHelper::Flush();
3055 void GLES2Implementation::BindFramebufferHelper(
3056 GLenum target, GLuint framebuffer) {
3057 // TODO(gman): See note #1 above.
3058 bool changed = false;
3059 switch (target) {
3060 case GL_FRAMEBUFFER:
3061 if (bound_framebuffer_ != framebuffer ||
3062 bound_read_framebuffer_ != framebuffer) {
3063 bound_framebuffer_ = framebuffer;
3064 bound_read_framebuffer_ = framebuffer;
3065 changed = true;
3067 break;
3068 case GL_READ_FRAMEBUFFER:
3069 if (!IsChromiumFramebufferMultisampleAvailable()) {
3070 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3071 return;
3073 if (bound_read_framebuffer_ != framebuffer) {
3074 bound_read_framebuffer_ = framebuffer;
3075 changed = true;
3077 break;
3078 case GL_DRAW_FRAMEBUFFER:
3079 if (!IsChromiumFramebufferMultisampleAvailable()) {
3080 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3081 return;
3083 if (bound_framebuffer_ != framebuffer) {
3084 bound_framebuffer_ = framebuffer;
3085 changed = true;
3087 break;
3088 default:
3089 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3090 return;
3093 if (changed) {
3094 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(
3095 this, target, framebuffer, &GLES2Implementation::BindFramebufferStub);
3099 void GLES2Implementation::BindFramebufferStub(GLenum target,
3100 GLuint framebuffer) {
3101 helper_->BindFramebuffer(target, framebuffer);
3102 if (share_group_->bind_generates_resource())
3103 helper_->CommandBufferHelper::Flush();
3106 void GLES2Implementation::BindRenderbufferHelper(
3107 GLenum target, GLuint renderbuffer) {
3108 // TODO(gman): See note #1 above.
3109 bool changed = false;
3110 switch (target) {
3111 case GL_RENDERBUFFER:
3112 if (bound_renderbuffer_ != renderbuffer) {
3113 bound_renderbuffer_ = renderbuffer;
3114 changed = true;
3116 break;
3117 default:
3118 changed = true;
3119 break;
3121 // TODO(zmo): See note #2 above.
3122 if (changed) {
3123 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(
3124 this, target, renderbuffer,
3125 &GLES2Implementation::BindRenderbufferStub);
3129 void GLES2Implementation::BindRenderbufferStub(GLenum target,
3130 GLuint renderbuffer) {
3131 helper_->BindRenderbuffer(target, renderbuffer);
3132 if (share_group_->bind_generates_resource())
3133 helper_->CommandBufferHelper::Flush();
3136 void GLES2Implementation::BindSamplerHelper(GLuint unit,
3137 GLuint sampler) {
3138 helper_->BindSampler(unit, sampler);
3141 void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
3142 // TODO(gman): See note #1 above.
3143 // TODO(gman): Change this to false once we figure out why it's failing
3144 // on daisy.
3145 bool changed = true;
3146 TextureUnit& unit = texture_units_[active_texture_unit_];
3147 switch (target) {
3148 case GL_TEXTURE_2D:
3149 if (unit.bound_texture_2d != texture) {
3150 unit.bound_texture_2d = texture;
3151 changed = true;
3153 break;
3154 case GL_TEXTURE_CUBE_MAP:
3155 if (unit.bound_texture_cube_map != texture) {
3156 unit.bound_texture_cube_map = texture;
3157 changed = true;
3159 break;
3160 case GL_TEXTURE_EXTERNAL_OES:
3161 if (unit.bound_texture_external_oes != texture) {
3162 unit.bound_texture_external_oes = texture;
3163 changed = true;
3165 break;
3166 default:
3167 changed = true;
3168 break;
3170 // TODO(gman): See note #2 above.
3171 if (changed) {
3172 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(
3173 this, target, texture, &GLES2Implementation::BindTextureStub);
3177 void GLES2Implementation::BindTextureStub(GLenum target, GLuint texture) {
3178 helper_->BindTexture(target, texture);
3179 if (share_group_->bind_generates_resource())
3180 helper_->CommandBufferHelper::Flush();
3183 void GLES2Implementation::BindTransformFeedbackHelper(
3184 GLenum target, GLuint transformfeedback) {
3185 helper_->BindTransformFeedback(target, transformfeedback);
3188 void GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
3189 bool changed = false;
3190 if (vertex_array_object_manager_->BindVertexArray(array, &changed)) {
3191 if (changed) {
3192 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
3193 // because unlike other resources VertexArrayObject ids must
3194 // be generated by GenVertexArrays. A random id to Bind will not
3195 // generate a new object.
3196 helper_->BindVertexArrayOES(array);
3198 } else {
3199 SetGLError(
3200 GL_INVALID_OPERATION, "glBindVertexArrayOES",
3201 "id was not generated with glGenVertexArrayOES");
3205 void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
3206 GLuint valuebuffer) {
3207 bool changed = false;
3208 switch (target) {
3209 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
3210 if (bound_valuebuffer_ != valuebuffer) {
3211 bound_valuebuffer_ = valuebuffer;
3212 changed = true;
3214 break;
3215 default:
3216 changed = true;
3217 break;
3219 // TODO(gman): See note #2 above.
3220 if (changed) {
3221 GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(
3222 this, target, valuebuffer,
3223 &GLES2Implementation::BindValuebufferCHROMIUMStub);
3227 void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target,
3228 GLuint valuebuffer) {
3229 helper_->BindValuebufferCHROMIUM(target, valuebuffer);
3230 if (share_group_->bind_generates_resource())
3231 helper_->CommandBufferHelper::Flush();
3234 void GLES2Implementation::UseProgramHelper(GLuint program) {
3235 if (current_program_ != program) {
3236 current_program_ = program;
3237 helper_->UseProgram(program);
3241 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
3242 return vertex_array_object_manager_->IsReservedId(id);
3245 void GLES2Implementation::DeleteBuffersHelper(
3246 GLsizei n, const GLuint* buffers) {
3247 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
3248 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
3249 SetGLError(
3250 GL_INVALID_VALUE,
3251 "glDeleteBuffers", "id not created by this context.");
3252 return;
3254 for (GLsizei ii = 0; ii < n; ++ii) {
3255 if (buffers[ii] == bound_array_buffer_id_) {
3256 bound_array_buffer_id_ = 0;
3258 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
3260 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
3261 if (buffer)
3262 RemoveTransferBuffer(buffer);
3264 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
3265 bound_pixel_unpack_transfer_buffer_id_ = 0;
3270 void GLES2Implementation::DeleteBuffersStub(
3271 GLsizei n, const GLuint* buffers) {
3272 helper_->DeleteBuffersImmediate(n, buffers);
3276 void GLES2Implementation::DeleteFramebuffersHelper(
3277 GLsizei n, const GLuint* framebuffers) {
3278 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
3279 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
3280 SetGLError(
3281 GL_INVALID_VALUE,
3282 "glDeleteFramebuffers", "id not created by this context.");
3283 return;
3285 for (GLsizei ii = 0; ii < n; ++ii) {
3286 if (framebuffers[ii] == bound_framebuffer_) {
3287 bound_framebuffer_ = 0;
3289 if (framebuffers[ii] == bound_read_framebuffer_) {
3290 bound_read_framebuffer_ = 0;
3295 void GLES2Implementation::DeleteFramebuffersStub(
3296 GLsizei n, const GLuint* framebuffers) {
3297 helper_->DeleteFramebuffersImmediate(n, framebuffers);
3300 void GLES2Implementation::DeleteRenderbuffersHelper(
3301 GLsizei n, const GLuint* renderbuffers) {
3302 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
3303 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
3304 SetGLError(
3305 GL_INVALID_VALUE,
3306 "glDeleteRenderbuffers", "id not created by this context.");
3307 return;
3309 for (GLsizei ii = 0; ii < n; ++ii) {
3310 if (renderbuffers[ii] == bound_renderbuffer_) {
3311 bound_renderbuffer_ = 0;
3316 void GLES2Implementation::DeleteRenderbuffersStub(
3317 GLsizei n, const GLuint* renderbuffers) {
3318 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
3321 void GLES2Implementation::DeleteTexturesHelper(
3322 GLsizei n, const GLuint* textures) {
3323 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
3324 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
3325 SetGLError(
3326 GL_INVALID_VALUE,
3327 "glDeleteTextures", "id not created by this context.");
3328 return;
3330 for (GLsizei ii = 0; ii < n; ++ii) {
3331 for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
3332 ++tt) {
3333 TextureUnit& unit = texture_units_[tt];
3334 if (textures[ii] == unit.bound_texture_2d) {
3335 unit.bound_texture_2d = 0;
3337 if (textures[ii] == unit.bound_texture_cube_map) {
3338 unit.bound_texture_cube_map = 0;
3340 if (textures[ii] == unit.bound_texture_external_oes) {
3341 unit.bound_texture_external_oes = 0;
3347 void GLES2Implementation::DeleteTexturesStub(GLsizei n,
3348 const GLuint* textures) {
3349 helper_->DeleteTexturesImmediate(n, textures);
3352 void GLES2Implementation::DeleteVertexArraysOESHelper(
3353 GLsizei n, const GLuint* arrays) {
3354 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
3355 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
3356 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
3357 SetGLError(
3358 GL_INVALID_VALUE,
3359 "glDeleteVertexArraysOES", "id not created by this context.");
3360 return;
3364 void GLES2Implementation::DeleteVertexArraysOESStub(
3365 GLsizei n, const GLuint* arrays) {
3366 helper_->DeleteVertexArraysOESImmediate(n, arrays);
3369 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
3370 GLsizei n,
3371 const GLuint* valuebuffers) {
3372 if (!GetIdHandler(id_namespaces::kValuebuffers)
3373 ->FreeIds(this, n, valuebuffers,
3374 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
3375 SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
3376 "id not created by this context.");
3377 return;
3379 for (GLsizei ii = 0; ii < n; ++ii) {
3380 if (valuebuffers[ii] == bound_valuebuffer_) {
3381 bound_valuebuffer_ = 0;
3386 void GLES2Implementation::DeleteSamplersStub(
3387 GLsizei n, const GLuint* samplers) {
3388 helper_->DeleteSamplersImmediate(n, samplers);
3391 void GLES2Implementation::DeleteSamplersHelper(
3392 GLsizei n, const GLuint* samplers) {
3393 if (!GetIdHandler(id_namespaces::kSamplers)->FreeIds(
3394 this, n, samplers, &GLES2Implementation::DeleteSamplersStub)) {
3395 SetGLError(
3396 GL_INVALID_VALUE,
3397 "glDeleteSamplers", "id not created by this context.");
3398 return;
3402 void GLES2Implementation::DeleteTransformFeedbacksStub(
3403 GLsizei n, const GLuint* transformfeedbacks) {
3404 helper_->DeleteTransformFeedbacksImmediate(n, transformfeedbacks);
3407 void GLES2Implementation::DeleteTransformFeedbacksHelper(
3408 GLsizei n, const GLuint* transformfeedbacks) {
3409 if (!GetIdHandler(id_namespaces::kTransformFeedbacks)->FreeIds(
3410 this, n, transformfeedbacks,
3411 &GLES2Implementation::DeleteTransformFeedbacksStub)) {
3412 SetGLError(
3413 GL_INVALID_VALUE,
3414 "glDeleteTransformFeedbacks", "id not created by this context.");
3415 return;
3419 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
3420 GLsizei n,
3421 const GLuint* valuebuffers) {
3422 helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
3425 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
3426 GPU_CLIENT_SINGLE_THREAD_CHECK();
3427 GPU_CLIENT_LOG(
3428 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
3429 vertex_array_object_manager_->SetAttribEnable(index, false);
3430 helper_->DisableVertexAttribArray(index);
3431 CheckGLError();
3434 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
3435 GPU_CLIENT_SINGLE_THREAD_CHECK();
3436 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
3437 << index << ")");
3438 vertex_array_object_manager_->SetAttribEnable(index, true);
3439 helper_->EnableVertexAttribArray(index);
3440 CheckGLError();
3443 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
3444 GPU_CLIENT_SINGLE_THREAD_CHECK();
3445 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
3446 << GLES2Util::GetStringDrawMode(mode) << ", "
3447 << first << ", " << count << ")");
3448 if (count < 0) {
3449 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
3450 return;
3452 bool simulated = false;
3453 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
3454 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
3455 return;
3457 helper_->DrawArrays(mode, first, count);
3458 RestoreArrayBuffer(simulated);
3459 CheckGLError();
3462 void GLES2Implementation::GetVertexAttribfv(
3463 GLuint index, GLenum pname, GLfloat* params) {
3464 GPU_CLIENT_SINGLE_THREAD_CHECK();
3465 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
3466 << index << ", "
3467 << GLES2Util::GetStringVertexAttribute(pname) << ", "
3468 << static_cast<const void*>(params) << ")");
3469 uint32 value = 0;
3470 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
3471 *params = static_cast<float>(value);
3472 return;
3474 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
3475 typedef cmds::GetVertexAttribfv::Result Result;
3476 Result* result = GetResultAs<Result*>();
3477 if (!result) {
3478 return;
3480 result->SetNumResults(0);
3481 helper_->GetVertexAttribfv(
3482 index, pname, GetResultShmId(), GetResultShmOffset());
3483 WaitForCmd();
3484 result->CopyResult(params);
3485 GPU_CLIENT_LOG_CODE_BLOCK({
3486 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3487 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3490 CheckGLError();
3493 void GLES2Implementation::GetVertexAttribiv(
3494 GLuint index, GLenum pname, GLint* params) {
3495 GPU_CLIENT_SINGLE_THREAD_CHECK();
3496 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
3497 << index << ", "
3498 << GLES2Util::GetStringVertexAttribute(pname) << ", "
3499 << static_cast<const void*>(params) << ")");
3500 uint32 value = 0;
3501 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
3502 *params = value;
3503 return;
3505 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
3506 typedef cmds::GetVertexAttribiv::Result Result;
3507 Result* result = GetResultAs<Result*>();
3508 if (!result) {
3509 return;
3511 result->SetNumResults(0);
3512 helper_->GetVertexAttribiv(
3513 index, pname, GetResultShmId(), GetResultShmOffset());
3514 WaitForCmd();
3515 result->CopyResult(params);
3516 GPU_CLIENT_LOG_CODE_BLOCK({
3517 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3518 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3521 CheckGLError();
3524 void GLES2Implementation::Swap() {
3525 SwapBuffers();
3528 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
3529 PostSubBufferCHROMIUM(
3530 sub_buffer.x(), sub_buffer.y(), sub_buffer.width(), sub_buffer.height());
3533 static GLenum GetGLESOverlayTransform(gfx::OverlayTransform plane_transform) {
3534 switch (plane_transform) {
3535 case gfx::OVERLAY_TRANSFORM_INVALID:
3536 break;
3537 case gfx::OVERLAY_TRANSFORM_NONE:
3538 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
3539 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
3540 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM;
3541 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
3542 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM;
3543 case gfx::OVERLAY_TRANSFORM_ROTATE_90:
3544 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM;
3545 case gfx::OVERLAY_TRANSFORM_ROTATE_180:
3546 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM;
3547 case gfx::OVERLAY_TRANSFORM_ROTATE_270:
3548 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM;
3550 NOTREACHED();
3551 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
3554 void GLES2Implementation::ScheduleOverlayPlane(
3555 int plane_z_order,
3556 gfx::OverlayTransform plane_transform,
3557 unsigned overlay_texture_id,
3558 const gfx::Rect& display_bounds,
3559 const gfx::RectF& uv_rect) {
3560 ScheduleOverlayPlaneCHROMIUM(plane_z_order,
3561 GetGLESOverlayTransform(plane_transform),
3562 overlay_texture_id,
3563 display_bounds.x(),
3564 display_bounds.y(),
3565 display_bounds.width(),
3566 display_bounds.height(),
3567 uv_rect.x(),
3568 uv_rect.y(),
3569 uv_rect.width(),
3570 uv_rect.height());
3573 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
3574 const char* feature) {
3575 GPU_CLIENT_SINGLE_THREAD_CHECK();
3576 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
3577 << feature << ")");
3578 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
3579 typedef cmds::EnableFeatureCHROMIUM::Result Result;
3580 Result* result = GetResultAs<Result*>();
3581 if (!result) {
3582 return false;
3584 *result = 0;
3585 SetBucketAsCString(kResultBucketId, feature);
3586 helper_->EnableFeatureCHROMIUM(
3587 kResultBucketId, GetResultShmId(), GetResultShmOffset());
3588 WaitForCmd();
3589 helper_->SetBucketSize(kResultBucketId, 0);
3590 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
3591 return *result != 0;
3594 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
3595 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
3596 GPU_CLIENT_SINGLE_THREAD_CHECK();
3597 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
3598 << target << ", " << offset << ", " << size << ", "
3599 << GLES2Util::GetStringEnum(access) << ")");
3600 // NOTE: target is NOT checked because the service will check it
3601 // and we don't know what targets are valid.
3602 if (access != GL_WRITE_ONLY) {
3603 SetGLErrorInvalidEnum(
3604 "glMapBufferSubDataCHROMIUM", access, "access");
3605 return NULL;
3607 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
3608 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
3609 return NULL;
3612 int32 shm_id;
3613 unsigned int shm_offset;
3614 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
3615 if (!mem) {
3616 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
3617 return NULL;
3620 std::pair<MappedBufferMap::iterator, bool> result =
3621 mapped_buffers_.insert(std::make_pair(
3622 mem,
3623 MappedBuffer(
3624 access, shm_id, mem, shm_offset, target, offset, size)));
3625 DCHECK(result.second);
3626 GPU_CLIENT_LOG(" returned " << mem);
3627 return mem;
3630 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
3631 GPU_CLIENT_SINGLE_THREAD_CHECK();
3632 GPU_CLIENT_LOG(
3633 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
3634 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
3635 if (it == mapped_buffers_.end()) {
3636 SetGLError(
3637 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
3638 return;
3640 const MappedBuffer& mb = it->second;
3641 helper_->BufferSubData(
3642 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
3643 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
3644 mapped_buffers_.erase(it);
3645 CheckGLError();
3648 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
3649 GLenum target,
3650 GLint level,
3651 GLint xoffset,
3652 GLint yoffset,
3653 GLsizei width,
3654 GLsizei height,
3655 GLenum format,
3656 GLenum type,
3657 GLenum access) {
3658 GPU_CLIENT_SINGLE_THREAD_CHECK();
3659 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
3660 << target << ", " << level << ", "
3661 << xoffset << ", " << yoffset << ", "
3662 << width << ", " << height << ", "
3663 << GLES2Util::GetStringTextureFormat(format) << ", "
3664 << GLES2Util::GetStringPixelType(type) << ", "
3665 << GLES2Util::GetStringEnum(access) << ")");
3666 if (access != GL_WRITE_ONLY) {
3667 SetGLErrorInvalidEnum(
3668 "glMapTexSubImage2DCHROMIUM", access, "access");
3669 return NULL;
3671 // NOTE: target is NOT checked because the service will check it
3672 // and we don't know what targets are valid.
3673 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
3674 SetGLError(
3675 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
3676 return NULL;
3678 uint32 size;
3679 if (!GLES2Util::ComputeImageDataSizes(
3680 width, height, 1, format, type, unpack_alignment_, &size, NULL, NULL)) {
3681 SetGLError(
3682 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
3683 return NULL;
3685 int32 shm_id;
3686 unsigned int shm_offset;
3687 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
3688 if (!mem) {
3689 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
3690 return NULL;
3693 std::pair<MappedTextureMap::iterator, bool> result =
3694 mapped_textures_.insert(std::make_pair(
3695 mem,
3696 MappedTexture(
3697 access, shm_id, mem, shm_offset,
3698 target, level, xoffset, yoffset, width, height, format, type)));
3699 DCHECK(result.second);
3700 GPU_CLIENT_LOG(" returned " << mem);
3701 return mem;
3704 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
3705 GPU_CLIENT_SINGLE_THREAD_CHECK();
3706 GPU_CLIENT_LOG(
3707 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
3708 MappedTextureMap::iterator it = mapped_textures_.find(mem);
3709 if (it == mapped_textures_.end()) {
3710 SetGLError(
3711 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
3712 return;
3714 const MappedTexture& mt = it->second;
3715 helper_->TexSubImage2D(
3716 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
3717 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
3718 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
3719 mapped_textures_.erase(it);
3720 CheckGLError();
3723 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
3724 float scale_factor) {
3725 GPU_CLIENT_SINGLE_THREAD_CHECK();
3726 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
3727 << width << ", " << height << ", " << scale_factor << ")");
3728 helper_->ResizeCHROMIUM(width, height, scale_factor);
3729 CheckGLError();
3732 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
3733 GPU_CLIENT_SINGLE_THREAD_CHECK();
3734 GPU_CLIENT_LOG("[" << GetLogPrefix()
3735 << "] glGetRequestableExtensionsCHROMIUM()");
3736 TRACE_EVENT0("gpu",
3737 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
3738 const char* result = NULL;
3739 // Clear the bucket so if the command fails nothing will be in it.
3740 helper_->SetBucketSize(kResultBucketId, 0);
3741 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
3742 std::string str;
3743 if (GetBucketAsString(kResultBucketId, &str)) {
3744 // The set of requestable extensions shrinks as we enable
3745 // them. Because we don't know when the client will stop referring
3746 // to a previous one it queries (see GetString) we need to cache
3747 // the unique results.
3748 std::set<std::string>::const_iterator sit =
3749 requestable_extensions_set_.find(str);
3750 if (sit != requestable_extensions_set_.end()) {
3751 result = sit->c_str();
3752 } else {
3753 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
3754 requestable_extensions_set_.insert(str);
3755 DCHECK(insert_result.second);
3756 result = insert_result.first->c_str();
3759 GPU_CLIENT_LOG(" returned " << result);
3760 return reinterpret_cast<const GLchar*>(result);
3763 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
3764 // with VirtualGL contexts.
3765 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
3766 GPU_CLIENT_SINGLE_THREAD_CHECK();
3767 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
3768 << extension << ")");
3769 SetBucketAsCString(kResultBucketId, extension);
3770 helper_->RequestExtensionCHROMIUM(kResultBucketId);
3771 helper_->SetBucketSize(kResultBucketId, 0);
3773 struct ExtensionCheck {
3774 const char* extension;
3775 ExtensionStatus* status;
3777 const ExtensionCheck checks[] = {
3779 "GL_ANGLE_pack_reverse_row_order",
3780 &angle_pack_reverse_row_order_status_,
3783 "GL_CHROMIUM_framebuffer_multisample",
3784 &chromium_framebuffer_multisample_,
3787 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
3788 for (size_t ii = 0; ii < kNumChecks; ++ii) {
3789 const ExtensionCheck& check = checks[ii];
3790 if (*check.status == kUnavailableExtensionStatus &&
3791 !strcmp(extension, check.extension)) {
3792 *check.status = kUnknownExtensionStatus;
3797 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
3798 GPU_CLIENT_SINGLE_THREAD_CHECK();
3799 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
3800 // Wait if this would add too many rate limit tokens.
3801 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
3802 helper_->WaitForToken(rate_limit_tokens_.front());
3803 rate_limit_tokens_.pop();
3805 rate_limit_tokens_.push(helper_->InsertToken());
3808 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3809 GLuint program, std::vector<int8>* result) {
3810 DCHECK(result);
3811 // Clear the bucket so if the command fails nothing will be in it.
3812 helper_->SetBucketSize(kResultBucketId, 0);
3813 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
3814 GetBucketContents(kResultBucketId, result);
3817 void GLES2Implementation::GetProgramInfoCHROMIUM(
3818 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3819 GPU_CLIENT_SINGLE_THREAD_CHECK();
3820 if (bufsize < 0) {
3821 SetGLError(
3822 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3823 return;
3825 if (size == NULL) {
3826 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
3827 return;
3829 // Make sure they've set size to 0 else the value will be undefined on
3830 // lost context.
3831 DCHECK_EQ(0, *size);
3832 std::vector<int8> result;
3833 GetProgramInfoCHROMIUMHelper(program, &result);
3834 if (result.empty()) {
3835 return;
3837 *size = result.size();
3838 if (!info) {
3839 return;
3841 if (static_cast<size_t>(bufsize) < result.size()) {
3842 SetGLError(GL_INVALID_OPERATION,
3843 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3844 return;
3846 memcpy(info, &result[0], result.size());
3849 void GLES2Implementation::GetUniformBlocksCHROMIUMHelper(
3850 GLuint program, std::vector<int8>* result) {
3851 DCHECK(result);
3852 // Clear the bucket so if the command fails nothing will be in it.
3853 helper_->SetBucketSize(kResultBucketId, 0);
3854 helper_->GetUniformBlocksCHROMIUM(program, kResultBucketId);
3855 GetBucketContents(kResultBucketId, result);
3858 void GLES2Implementation::GetUniformBlocksCHROMIUM(
3859 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3860 GPU_CLIENT_SINGLE_THREAD_CHECK();
3861 if (bufsize < 0) {
3862 SetGLError(
3863 GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "bufsize less than 0.");
3864 return;
3866 if (size == NULL) {
3867 SetGLError(GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "size is null.");
3868 return;
3870 // Make sure they've set size to 0 else the value will be undefined on
3871 // lost context.
3872 DCHECK_EQ(0, *size);
3873 std::vector<int8> result;
3874 GetUniformBlocksCHROMIUMHelper(program, &result);
3875 if (result.empty()) {
3876 return;
3878 *size = result.size();
3879 if (!info) {
3880 return;
3882 if (static_cast<size_t>(bufsize) < result.size()) {
3883 SetGLError(GL_INVALID_OPERATION, "glGetUniformBlocksCHROMIUM",
3884 "bufsize is too small for result.");
3885 return;
3887 memcpy(info, &result[0], result.size());
3890 void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
3891 GLuint program, std::vector<int8>* result) {
3892 DCHECK(result);
3893 // Clear the bucket so if the command fails nothing will be in it.
3894 helper_->SetBucketSize(kResultBucketId, 0);
3895 helper_->GetUniformsES3CHROMIUM(program, kResultBucketId);
3896 GetBucketContents(kResultBucketId, result);
3899 void GLES2Implementation::GetUniformsES3CHROMIUM(
3900 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3901 GPU_CLIENT_SINGLE_THREAD_CHECK();
3902 if (bufsize < 0) {
3903 SetGLError(
3904 GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "bufsize less than 0.");
3905 return;
3907 if (size == NULL) {
3908 SetGLError(GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "size is null.");
3909 return;
3911 // Make sure they've set size to 0 else the value will be undefined on
3912 // lost context.
3913 DCHECK_EQ(0, *size);
3914 std::vector<int8> result;
3915 GetUniformsES3CHROMIUMHelper(program, &result);
3916 if (result.empty()) {
3917 return;
3919 *size = result.size();
3920 if (!info) {
3921 return;
3923 if (static_cast<size_t>(bufsize) < result.size()) {
3924 SetGLError(GL_INVALID_OPERATION,
3925 "glGetUniformsES3CHROMIUM", "bufsize is too small for result.");
3926 return;
3928 memcpy(info, &result[0], result.size());
3931 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
3932 GLuint program, std::vector<int8>* result) {
3933 DCHECK(result);
3934 // Clear the bucket so if the command fails nothing will be in it.
3935 helper_->SetBucketSize(kResultBucketId, 0);
3936 helper_->GetTransformFeedbackVaryingsCHROMIUM(program, kResultBucketId);
3937 GetBucketContents(kResultBucketId, result);
3940 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(
3941 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3942 GPU_CLIENT_SINGLE_THREAD_CHECK();
3943 if (bufsize < 0) {
3944 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
3945 "bufsize less than 0.");
3946 return;
3948 if (size == NULL) {
3949 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
3950 "size is null.");
3951 return;
3953 // Make sure they've set size to 0 else the value will be undefined on
3954 // lost context.
3955 DCHECK_EQ(0, *size);
3956 std::vector<int8> result;
3957 GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
3958 if (result.empty()) {
3959 return;
3961 *size = result.size();
3962 if (!info) {
3963 return;
3965 if (static_cast<size_t>(bufsize) < result.size()) {
3966 SetGLError(GL_INVALID_OPERATION, "glGetTransformFeedbackVaryingsCHROMIUM",
3967 "bufsize is too small for result.");
3968 return;
3970 memcpy(info, &result[0], result.size());
3973 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
3974 GPU_CLIENT_SINGLE_THREAD_CHECK();
3975 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
3976 << texture << ")");
3977 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
3978 helper_->CommandBufferHelper::Flush();
3979 return gpu_control_->CreateStreamTexture(texture);
3982 void GLES2Implementation::PostSubBufferCHROMIUM(
3983 GLint x, GLint y, GLint width, GLint height) {
3984 GPU_CLIENT_SINGLE_THREAD_CHECK();
3985 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
3986 << x << ", " << y << ", " << width << ", " << height << ")");
3987 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
3988 "width", width, "height", height);
3990 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
3991 swap_buffers_tokens_.push(helper_->InsertToken());
3992 helper_->PostSubBufferCHROMIUM(x, y, width, height);
3993 helper_->CommandBufferHelper::Flush();
3994 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
3995 helper_->WaitForToken(swap_buffers_tokens_.front());
3996 swap_buffers_tokens_.pop();
4000 void GLES2Implementation::DeleteQueriesEXTHelper(
4001 GLsizei n, const GLuint* queries) {
4002 for (GLsizei ii = 0; ii < n; ++ii) {
4003 query_tracker_->RemoveQuery(queries[ii]);
4004 query_id_allocator_->FreeID(queries[ii]);
4007 helper_->DeleteQueriesEXTImmediate(n, queries);
4010 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
4011 GPU_CLIENT_SINGLE_THREAD_CHECK();
4012 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
4014 // TODO(gman): To be spec compliant IDs from other contexts sharing
4015 // resources need to return true here even though you can't share
4016 // queries across contexts?
4017 return query_tracker_->GetQuery(id) != NULL;
4020 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
4021 GPU_CLIENT_SINGLE_THREAD_CHECK();
4022 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
4023 << GLES2Util::GetStringQueryTarget(target)
4024 << ", " << id << ")");
4026 // if any outstanding queries INV_OP
4027 QueryMap::iterator it = current_queries_.find(target);
4028 if (it != current_queries_.end()) {
4029 SetGLError(
4030 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
4031 return;
4034 // id = 0 INV_OP
4035 if (id == 0) {
4036 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
4037 return;
4040 // if not GENned INV_OPERATION
4041 if (!query_id_allocator_->InUse(id)) {
4042 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "invalid id");
4043 return;
4046 // if id does not have an object
4047 QueryTracker::Query* query = query_tracker_->GetQuery(id);
4048 if (!query) {
4049 query = query_tracker_->CreateQuery(id, target);
4050 if (!query) {
4051 SetGLError(GL_OUT_OF_MEMORY,
4052 "glBeginQueryEXT",
4053 "transfer buffer allocation failed");
4054 return;
4056 } else if (query->target() != target) {
4057 SetGLError(
4058 GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
4059 return;
4062 current_queries_[target] = query;
4064 query->Begin(this);
4065 CheckGLError();
4068 void GLES2Implementation::EndQueryEXT(GLenum target) {
4069 GPU_CLIENT_SINGLE_THREAD_CHECK();
4070 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
4071 << GLES2Util::GetStringQueryTarget(target) << ")");
4072 // Don't do anything if the context is lost.
4073 if (helper_->IsContextLost()) {
4074 return;
4077 QueryMap::iterator it = current_queries_.find(target);
4078 if (it == current_queries_.end()) {
4079 SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
4080 return;
4083 QueryTracker::Query* query = it->second;
4084 query->End(this);
4085 current_queries_.erase(it);
4086 CheckGLError();
4089 void GLES2Implementation::GetQueryivEXT(
4090 GLenum target, GLenum pname, GLint* params) {
4091 GPU_CLIENT_SINGLE_THREAD_CHECK();
4092 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
4093 << GLES2Util::GetStringQueryTarget(target) << ", "
4094 << GLES2Util::GetStringQueryParameter(pname) << ", "
4095 << static_cast<const void*>(params) << ")");
4097 if (pname != GL_CURRENT_QUERY_EXT) {
4098 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
4099 return;
4101 QueryMap::iterator it = current_queries_.find(target);
4102 if (it != current_queries_.end()) {
4103 QueryTracker::Query* query = it->second;
4104 *params = query->id();
4105 } else {
4106 *params = 0;
4108 GPU_CLIENT_LOG(" " << *params);
4109 CheckGLError();
4112 void GLES2Implementation::GetQueryObjectuivEXT(
4113 GLuint id, GLenum pname, GLuint* params) {
4114 GPU_CLIENT_SINGLE_THREAD_CHECK();
4115 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
4116 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
4117 << static_cast<const void*>(params) << ")");
4119 QueryTracker::Query* query = query_tracker_->GetQuery(id);
4120 if (!query) {
4121 SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
4122 return;
4125 QueryMap::iterator it = current_queries_.find(query->target());
4126 if (it != current_queries_.end()) {
4127 SetGLError(
4128 GL_INVALID_OPERATION,
4129 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
4130 return;
4133 if (query->NeverUsed()) {
4134 SetGLError(
4135 GL_INVALID_OPERATION,
4136 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
4137 return;
4140 switch (pname) {
4141 case GL_QUERY_RESULT_EXT:
4142 if (!query->CheckResultsAvailable(helper_)) {
4143 helper_->WaitForToken(query->token());
4144 if (!query->CheckResultsAvailable(helper_)) {
4145 FinishHelper();
4146 CHECK(query->CheckResultsAvailable(helper_));
4149 *params = query->GetResult();
4150 break;
4151 case GL_QUERY_RESULT_AVAILABLE_EXT:
4152 *params = query->CheckResultsAvailable(helper_);
4153 break;
4154 default:
4155 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
4156 break;
4158 GPU_CLIENT_LOG(" " << *params);
4159 CheckGLError();
4162 void GLES2Implementation::DrawArraysInstancedANGLE(
4163 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
4164 GPU_CLIENT_SINGLE_THREAD_CHECK();
4165 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
4166 << GLES2Util::GetStringDrawMode(mode) << ", "
4167 << first << ", " << count << ", " << primcount << ")");
4168 if (count < 0) {
4169 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
4170 return;
4172 if (primcount < 0) {
4173 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
4174 return;
4176 if (primcount == 0) {
4177 return;
4179 bool simulated = false;
4180 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
4181 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
4182 &simulated)) {
4183 return;
4185 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
4186 RestoreArrayBuffer(simulated);
4187 CheckGLError();
4190 void GLES2Implementation::DrawElementsInstancedANGLE(
4191 GLenum mode, GLsizei count, GLenum type, const void* indices,
4192 GLsizei primcount) {
4193 GPU_CLIENT_SINGLE_THREAD_CHECK();
4194 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
4195 << GLES2Util::GetStringDrawMode(mode) << ", "
4196 << count << ", "
4197 << GLES2Util::GetStringIndexType(type) << ", "
4198 << static_cast<const void*>(indices) << ", "
4199 << primcount << ")");
4200 if (count < 0) {
4201 SetGLError(GL_INVALID_VALUE,
4202 "glDrawElementsInstancedANGLE", "count less than 0.");
4203 return;
4205 if (count == 0) {
4206 return;
4208 if (primcount < 0) {
4209 SetGLError(GL_INVALID_VALUE,
4210 "glDrawElementsInstancedANGLE", "primcount < 0");
4211 return;
4213 if (primcount == 0) {
4214 return;
4216 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
4217 !ValidateOffset("glDrawElementsInstancedANGLE",
4218 reinterpret_cast<GLintptr>(indices))) {
4219 return;
4221 GLuint offset = 0;
4222 bool simulated = false;
4223 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
4224 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
4225 indices, &offset, &simulated)) {
4226 return;
4228 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
4229 RestoreElementAndArrayBuffers(simulated);
4230 CheckGLError();
4233 void GLES2Implementation::GenMailboxCHROMIUM(
4234 GLbyte* mailbox) {
4235 GPU_CLIENT_SINGLE_THREAD_CHECK();
4236 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
4237 << static_cast<const void*>(mailbox) << ")");
4238 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
4240 gpu::Mailbox result = gpu::Mailbox::Generate();
4241 memcpy(mailbox, result.name, sizeof(result.name));
4244 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target,
4245 const GLbyte* data) {
4246 GPU_CLIENT_SINGLE_THREAD_CHECK();
4247 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
4248 << static_cast<const void*>(data) << ")");
4249 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4250 DCHECK(mailbox.Verify()) << "ProduceTextureCHROMIUM was passed a "
4251 "mailbox that was not generated by "
4252 "GenMailboxCHROMIUM.";
4253 helper_->ProduceTextureCHROMIUMImmediate(target, data);
4254 CheckGLError();
4257 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
4258 GLuint texture, GLenum target, const GLbyte* data) {
4259 GPU_CLIENT_SINGLE_THREAD_CHECK();
4260 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
4261 << static_cast<const void*>(data) << ")");
4262 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4263 DCHECK(mailbox.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
4264 "mailbox that was not generated by "
4265 "GenMailboxCHROMIUM.";
4266 helper_->ProduceTextureDirectCHROMIUMImmediate(texture, target, data);
4267 CheckGLError();
4270 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target,
4271 const GLbyte* data) {
4272 GPU_CLIENT_SINGLE_THREAD_CHECK();
4273 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
4274 << static_cast<const void*>(data) << ")");
4275 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4276 DCHECK(mailbox.Verify()) << "ConsumeTextureCHROMIUM was passed a "
4277 "mailbox that was not generated by "
4278 "GenMailboxCHROMIUM.";
4279 helper_->ConsumeTextureCHROMIUMImmediate(target, data);
4280 CheckGLError();
4283 GLuint GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
4284 GLenum target, const GLbyte* data) {
4285 GPU_CLIENT_SINGLE_THREAD_CHECK();
4286 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
4287 << static_cast<const void*>(data) << ")");
4288 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4289 DCHECK(mailbox.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
4290 "mailbox that was not generated by "
4291 "GenMailboxCHROMIUM.";
4292 GLuint client_id;
4293 GetIdHandler(id_namespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
4294 helper_->CreateAndConsumeTextureCHROMIUMImmediate(target,
4295 client_id, data);
4296 if (share_group_->bind_generates_resource())
4297 helper_->CommandBufferHelper::Flush();
4298 CheckGLError();
4299 return client_id;
4302 void GLES2Implementation::PushGroupMarkerEXT(
4303 GLsizei length, const GLchar* marker) {
4304 GPU_CLIENT_SINGLE_THREAD_CHECK();
4305 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
4306 << length << ", " << marker << ")");
4307 if (!marker) {
4308 marker = "";
4310 SetBucketAsString(
4311 kResultBucketId,
4312 (length ? std::string(marker, length) : std::string(marker)));
4313 helper_->PushGroupMarkerEXT(kResultBucketId);
4314 helper_->SetBucketSize(kResultBucketId, 0);
4315 debug_marker_manager_.PushGroup(
4316 length ? std::string(marker, length) : std::string(marker));
4319 void GLES2Implementation::InsertEventMarkerEXT(
4320 GLsizei length, const GLchar* marker) {
4321 GPU_CLIENT_SINGLE_THREAD_CHECK();
4322 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
4323 << length << ", " << marker << ")");
4324 if (!marker) {
4325 marker = "";
4327 SetBucketAsString(
4328 kResultBucketId,
4329 (length ? std::string(marker, length) : std::string(marker)));
4330 helper_->InsertEventMarkerEXT(kResultBucketId);
4331 helper_->SetBucketSize(kResultBucketId, 0);
4332 debug_marker_manager_.SetMarker(
4333 length ? std::string(marker, length) : std::string(marker));
4336 void GLES2Implementation::PopGroupMarkerEXT() {
4337 GPU_CLIENT_SINGLE_THREAD_CHECK();
4338 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
4339 helper_->PopGroupMarkerEXT();
4340 debug_marker_manager_.PopGroup();
4343 void GLES2Implementation::TraceBeginCHROMIUM(
4344 const char* category_name, const char* trace_name) {
4345 GPU_CLIENT_SINGLE_THREAD_CHECK();
4346 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
4347 << category_name << ", " << trace_name << ")");
4348 SetBucketAsCString(kResultBucketId, category_name);
4349 SetBucketAsCString(kResultBucketId + 1, trace_name);
4350 helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1);
4351 helper_->SetBucketSize(kResultBucketId, 0);
4352 helper_->SetBucketSize(kResultBucketId + 1, 0);
4353 current_trace_stack_++;
4356 void GLES2Implementation::TraceEndCHROMIUM() {
4357 GPU_CLIENT_SINGLE_THREAD_CHECK();
4358 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
4359 if (current_trace_stack_ == 0) {
4360 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
4361 "missing begin trace");
4362 return;
4364 helper_->TraceEndCHROMIUM();
4365 current_trace_stack_--;
4368 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
4369 GPU_CLIENT_SINGLE_THREAD_CHECK();
4370 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
4371 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
4372 switch (target) {
4373 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
4374 if (access != GL_READ_ONLY) {
4375 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
4376 return NULL;
4378 break;
4379 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
4380 if (access != GL_WRITE_ONLY) {
4381 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
4382 return NULL;
4384 break;
4385 default:
4386 SetGLError(
4387 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
4388 return NULL;
4390 GLuint buffer_id;
4391 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
4392 if (!buffer_id) {
4393 return NULL;
4395 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
4396 if (!buffer) {
4397 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
4398 return NULL;
4400 if (buffer->mapped()) {
4401 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
4402 return NULL;
4404 // Here we wait for previous transfer operations to be finished.
4405 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
4406 // with this method of synchronization. Until this is fixed,
4407 // MapBufferCHROMIUM will not block even if the transfer is not ready
4408 // for these calls.
4409 if (buffer->last_usage_token()) {
4410 helper_->WaitForToken(buffer->last_usage_token());
4411 buffer->set_last_usage_token(0);
4413 buffer->set_mapped(true);
4415 GPU_CLIENT_LOG(" returned " << buffer->address());
4416 CheckGLError();
4417 return buffer->address();
4420 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
4421 GPU_CLIENT_SINGLE_THREAD_CHECK();
4422 GPU_CLIENT_LOG(
4423 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
4424 GLuint buffer_id;
4425 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
4426 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
4428 if (!buffer_id) {
4429 return false;
4431 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
4432 if (!buffer) {
4433 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
4434 return false;
4436 if (!buffer->mapped()) {
4437 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
4438 return false;
4440 buffer->set_mapped(false);
4441 CheckGLError();
4442 return true;
4445 bool GLES2Implementation::EnsureAsyncUploadSync() {
4446 if (async_upload_sync_)
4447 return true;
4449 int32 shm_id;
4450 unsigned int shm_offset;
4451 void* mem = mapped_memory_->Alloc(sizeof(AsyncUploadSync),
4452 &shm_id,
4453 &shm_offset);
4454 if (!mem)
4455 return false;
4457 async_upload_sync_shm_id_ = shm_id;
4458 async_upload_sync_shm_offset_ = shm_offset;
4459 async_upload_sync_ = static_cast<AsyncUploadSync*>(mem);
4460 async_upload_sync_->Reset();
4462 return true;
4465 uint32 GLES2Implementation::NextAsyncUploadToken() {
4466 async_upload_token_++;
4467 if (async_upload_token_ == 0)
4468 async_upload_token_++;
4469 return async_upload_token_;
4472 void GLES2Implementation::PollAsyncUploads() {
4473 if (!async_upload_sync_)
4474 return;
4476 if (helper_->IsContextLost()) {
4477 DetachedAsyncUploadMemoryList::iterator it =
4478 detached_async_upload_memory_.begin();
4479 while (it != detached_async_upload_memory_.end()) {
4480 mapped_memory_->Free(it->first);
4481 it = detached_async_upload_memory_.erase(it);
4483 return;
4486 DetachedAsyncUploadMemoryList::iterator it =
4487 detached_async_upload_memory_.begin();
4488 while (it != detached_async_upload_memory_.end()) {
4489 if (HasAsyncUploadTokenPassed(it->second)) {
4490 mapped_memory_->Free(it->first);
4491 it = detached_async_upload_memory_.erase(it);
4492 } else {
4493 break;
4498 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
4499 // Free all completed unmanaged async uploads buffers.
4500 PollAsyncUploads();
4502 // Synchronously free rest of the unmanaged async upload buffers.
4503 if (!detached_async_upload_memory_.empty()) {
4504 WaitAllAsyncTexImage2DCHROMIUM();
4505 WaitForCmd();
4506 PollAsyncUploads();
4510 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
4511 GLenum target, GLint level, GLenum internalformat, GLsizei width,
4512 GLsizei height, GLint border, GLenum format, GLenum type,
4513 const void* pixels) {
4514 GPU_CLIENT_SINGLE_THREAD_CHECK();
4515 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
4516 << GLES2Util::GetStringTextureTarget(target) << ", "
4517 << level << ", "
4518 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
4519 << width << ", " << height << ", " << border << ", "
4520 << GLES2Util::GetStringTextureFormat(format) << ", "
4521 << GLES2Util::GetStringPixelType(type) << ", "
4522 << static_cast<const void*>(pixels) << ")");
4523 if (level < 0 || height < 0 || width < 0) {
4524 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
4525 return;
4527 if (border != 0) {
4528 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
4529 return;
4531 uint32 size;
4532 uint32 unpadded_row_size;
4533 uint32 padded_row_size;
4534 if (!GLES2Util::ComputeImageDataSizes(
4535 width, height, 1, format, type, unpack_alignment_, &size,
4536 &unpadded_row_size, &padded_row_size)) {
4537 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
4538 return;
4541 // If there's no data/buffer just issue the AsyncTexImage2D
4542 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
4543 helper_->AsyncTexImage2DCHROMIUM(
4544 target, level, internalformat, width, height, format, type,
4545 0, 0, 0, 0, 0);
4546 return;
4549 if (!EnsureAsyncUploadSync()) {
4550 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
4551 return;
4554 // Otherwise, async uploads require a transfer buffer to be bound.
4555 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
4556 // the buffer before the transfer is finished. (Currently such
4557 // synchronization has to be handled manually.)
4558 GLuint offset = ToGLuint(pixels);
4559 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
4560 bound_pixel_unpack_transfer_buffer_id_,
4561 "glAsyncTexImage2DCHROMIUM", offset, size);
4562 if (buffer && buffer->shm_id() != -1) {
4563 uint32 async_token = NextAsyncUploadToken();
4564 buffer->set_last_async_upload_token(async_token);
4565 helper_->AsyncTexImage2DCHROMIUM(
4566 target, level, internalformat, width, height, format, type,
4567 buffer->shm_id(), buffer->shm_offset() + offset,
4568 async_token,
4569 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
4573 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
4574 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
4575 GLsizei height, GLenum format, GLenum type, const void* pixels) {
4576 GPU_CLIENT_SINGLE_THREAD_CHECK();
4577 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
4578 << GLES2Util::GetStringTextureTarget(target) << ", "
4579 << level << ", "
4580 << xoffset << ", " << yoffset << ", "
4581 << width << ", " << height << ", "
4582 << GLES2Util::GetStringTextureFormat(format) << ", "
4583 << GLES2Util::GetStringPixelType(type) << ", "
4584 << static_cast<const void*>(pixels) << ")");
4585 if (level < 0 || height < 0 || width < 0) {
4586 SetGLError(
4587 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
4588 return;
4591 uint32 size;
4592 uint32 unpadded_row_size;
4593 uint32 padded_row_size;
4594 if (!GLES2Util::ComputeImageDataSizes(
4595 width, height, 1, format, type, unpack_alignment_, &size,
4596 &unpadded_row_size, &padded_row_size)) {
4597 SetGLError(
4598 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
4599 return;
4602 if (!EnsureAsyncUploadSync()) {
4603 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
4604 return;
4607 // Async uploads require a transfer buffer to be bound.
4608 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
4609 // the buffer before the transfer is finished. (Currently such
4610 // synchronization has to be handled manually.)
4611 GLuint offset = ToGLuint(pixels);
4612 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
4613 bound_pixel_unpack_transfer_buffer_id_,
4614 "glAsyncTexSubImage2DCHROMIUM", offset, size);
4615 if (buffer && buffer->shm_id() != -1) {
4616 uint32 async_token = NextAsyncUploadToken();
4617 buffer->set_last_async_upload_token(async_token);
4618 helper_->AsyncTexSubImage2DCHROMIUM(
4619 target, level, xoffset, yoffset, width, height, format, type,
4620 buffer->shm_id(), buffer->shm_offset() + offset,
4621 async_token,
4622 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
4626 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
4627 GPU_CLIENT_SINGLE_THREAD_CHECK();
4628 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
4629 << GLES2Util::GetStringTextureTarget(target) << ")");
4630 helper_->WaitAsyncTexImage2DCHROMIUM(target);
4631 CheckGLError();
4634 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
4635 GPU_CLIENT_SINGLE_THREAD_CHECK();
4636 GPU_CLIENT_LOG("[" << GetLogPrefix()
4637 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
4638 helper_->WaitAllAsyncTexImage2DCHROMIUM();
4639 CheckGLError();
4642 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
4643 GPU_CLIENT_SINGLE_THREAD_CHECK();
4644 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
4645 helper_->CommandBufferHelper::Flush();
4646 return gpu_control_->InsertSyncPoint();
4649 GLuint GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
4650 GPU_CLIENT_SINGLE_THREAD_CHECK();
4651 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
4652 DCHECK(capabilities_.future_sync_points);
4653 return gpu_control_->InsertFutureSyncPoint();
4656 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point) {
4657 GPU_CLIENT_SINGLE_THREAD_CHECK();
4658 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
4659 << sync_point << ")");
4660 DCHECK(capabilities_.future_sync_points);
4661 helper_->CommandBufferHelper::Flush();
4662 gpu_control_->RetireSyncPoint(sync_point);
4665 namespace {
4667 bool ValidImageFormat(GLenum internalformat) {
4668 switch (internalformat) {
4669 case GL_RGB:
4670 case GL_RGBA:
4671 return true;
4672 default:
4673 return false;
4677 bool ValidImageUsage(GLenum usage) {
4678 switch (usage) {
4679 case GL_MAP_CHROMIUM:
4680 case GL_SCANOUT_CHROMIUM:
4681 return true;
4682 default:
4683 return false;
4687 } // namespace
4689 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer,
4690 GLsizei width,
4691 GLsizei height,
4692 GLenum internalformat) {
4693 if (width <= 0) {
4694 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
4695 return 0;
4698 if (height <= 0) {
4699 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
4700 return 0;
4703 if (!ValidImageFormat(internalformat)) {
4704 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "invalid format");
4705 return 0;
4708 int32_t image_id =
4709 gpu_control_->CreateImage(buffer, width, height, internalformat);
4710 if (image_id < 0) {
4711 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "image_id < 0");
4712 return 0;
4714 return image_id;
4717 GLuint GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer,
4718 GLsizei width,
4719 GLsizei height,
4720 GLenum internalformat) {
4721 GPU_CLIENT_SINGLE_THREAD_CHECK();
4722 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
4723 << ", " << height << ", "
4724 << GLES2Util::GetStringImageInternalFormat(internalformat)
4725 << ")");
4726 GLuint image_id =
4727 CreateImageCHROMIUMHelper(buffer, width, height, internalformat);
4728 CheckGLError();
4729 return image_id;
4732 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
4733 // Flush the command stream to make sure all pending commands
4734 // that may refer to the image_id are executed on the service side.
4735 helper_->CommandBufferHelper::Flush();
4736 gpu_control_->DestroyImage(image_id);
4739 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
4740 GPU_CLIENT_SINGLE_THREAD_CHECK();
4741 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
4742 << image_id << ")");
4743 DestroyImageCHROMIUMHelper(image_id);
4744 CheckGLError();
4747 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
4748 GLsizei width,
4749 GLsizei height,
4750 GLenum internalformat,
4751 GLenum usage) {
4752 if (width <= 0) {
4753 SetGLError(
4754 GL_INVALID_VALUE, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
4755 return 0;
4758 if (height <= 0) {
4759 SetGLError(GL_INVALID_VALUE,
4760 "glCreateGpuMemoryBufferImageCHROMIUM",
4761 "height <= 0");
4762 return 0;
4765 if (!ValidImageFormat(internalformat)) {
4766 SetGLError(GL_INVALID_VALUE,
4767 "glCreateGpuMemoryBufferImageCHROMIUM",
4768 "invalid format");
4769 return 0;
4772 if (!ValidImageUsage(usage)) {
4773 SetGLError(GL_INVALID_VALUE,
4774 "glCreateGpuMemoryBufferImageCHROMIUM",
4775 "invalid usage");
4776 return 0;
4779 // Flush the command stream to ensure ordering in case the newly
4780 // returned image_id has recently been in use with a different buffer.
4781 helper_->CommandBufferHelper::Flush();
4782 int32_t image_id = gpu_control_->CreateGpuMemoryBufferImage(
4783 width, height, internalformat, usage);
4784 if (image_id < 0) {
4785 SetGLError(GL_OUT_OF_MEMORY,
4786 "glCreateGpuMemoryBufferImageCHROMIUM",
4787 "image_id < 0");
4788 return 0;
4790 return image_id;
4793 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
4794 GLsizei width,
4795 GLsizei height,
4796 GLenum internalformat,
4797 GLenum usage) {
4798 GPU_CLIENT_SINGLE_THREAD_CHECK();
4799 GPU_CLIENT_LOG("[" << GetLogPrefix()
4800 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
4801 << ", " << height << ", "
4802 << GLES2Util::GetStringImageInternalFormat(internalformat)
4803 << ", " << GLES2Util::GetStringImageUsage(usage) << ")");
4804 GLuint image_id = CreateGpuMemoryBufferImageCHROMIUMHelper(
4805 width, height, internalformat, usage);
4806 CheckGLError();
4807 return image_id;
4810 bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
4811 if (size < 0) {
4812 SetGLError(GL_INVALID_VALUE, func, "size < 0");
4813 return false;
4815 if (!FitInt32NonNegative<GLsizeiptr>(size)) {
4816 SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
4817 return false;
4819 return true;
4822 bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
4823 if (offset < 0) {
4824 SetGLError(GL_INVALID_VALUE, func, "offset < 0");
4825 return false;
4827 if (!FitInt32NonNegative<GLintptr>(offset)) {
4828 SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
4829 return false;
4831 return true;
4834 bool GLES2Implementation::GetSamplerParameterfvHelper(
4835 GLuint /* sampler */, GLenum /* pname */, GLfloat* /* params */) {
4836 // TODO(zmo): Implement client side caching.
4837 return false;
4840 bool GLES2Implementation::GetSamplerParameterivHelper(
4841 GLuint /* sampler */, GLenum /* pname */, GLint* /* params */) {
4842 // TODO(zmo): Implement client side caching.
4843 return false;
4846 bool GLES2Implementation::PackStringsToBucket(GLsizei count,
4847 const char* const* str,
4848 const GLint* length,
4849 const char* func_name) {
4850 DCHECK_LE(0, count);
4851 // Compute the total size.
4852 base::CheckedNumeric<size_t> total_size = count;
4853 total_size += 1;
4854 total_size *= sizeof(GLint);
4855 if (!total_size.IsValid()) {
4856 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
4857 return false;
4859 size_t header_size = total_size.ValueOrDefault(0);
4860 std::vector<GLint> header(count + 1);
4861 header[0] = static_cast<GLint>(count);
4862 for (GLsizei ii = 0; ii < count; ++ii) {
4863 GLint len = 0;
4864 if (str[ii]) {
4865 len = (length && length[ii] >= 0)
4866 ? length[ii]
4867 : base::checked_cast<GLint>(strlen(str[ii]));
4869 total_size += len;
4870 total_size += 1; // NULL at the end of each char array.
4871 if (!total_size.IsValid()) {
4872 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
4873 return false;
4875 header[ii + 1] = len;
4877 // Pack data into a bucket on the service.
4878 helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
4879 size_t offset = 0;
4880 for (GLsizei ii = 0; ii <= count; ++ii) {
4881 const char* src =
4882 (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
4883 base::CheckedNumeric<size_t> checked_size =
4884 (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
4885 if (ii > 0) {
4886 checked_size += 1; // NULL in the end.
4888 if (!checked_size.IsValid()) {
4889 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
4890 return false;
4892 size_t size = checked_size.ValueOrDefault(0);
4893 while (size) {
4894 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
4895 if (!buffer.valid() || buffer.size() == 0) {
4896 SetGLError(GL_OUT_OF_MEMORY, func_name, "too large");
4897 return false;
4899 size_t copy_size = buffer.size();
4900 if (ii > 0 && buffer.size() == size)
4901 --copy_size;
4902 if (copy_size)
4903 memcpy(buffer.address(), src, copy_size);
4904 if (copy_size < buffer.size()) {
4905 // Append NULL in the end.
4906 DCHECK(copy_size + 1 == buffer.size());
4907 char* str = reinterpret_cast<char*>(buffer.address());
4908 str[copy_size] = 0;
4910 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
4911 buffer.shm_id(), buffer.offset());
4912 offset += buffer.size();
4913 src += buffer.size();
4914 size -= buffer.size();
4917 DCHECK_EQ(total_size.ValueOrDefault(0), offset);
4918 return true;
4921 void GLES2Implementation::UniformBlockBinding(GLuint program,
4922 GLuint index,
4923 GLuint binding) {
4924 GPU_CLIENT_SINGLE_THREAD_CHECK();
4925 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
4926 << ", " << index << ", " << binding << ")");
4927 share_group_->program_info_manager()->UniformBlockBinding(
4928 this, program, index, binding);
4929 helper_->UniformBlockBinding(program, index, binding);
4930 CheckGLError();
4933 GLenum GLES2Implementation::ClientWaitSync(
4934 GLsync sync, GLbitfield flags, GLuint64 timeout) {
4935 GPU_CLIENT_SINGLE_THREAD_CHECK();
4936 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync
4937 << ", " << flags << ", " << timeout << ")");
4938 typedef cmds::ClientWaitSync::Result Result;
4939 Result* result = GetResultAs<Result*>();
4940 if (!result) {
4941 SetGLError(GL_OUT_OF_MEMORY, "ClientWaitSync", "");
4942 return GL_WAIT_FAILED;
4944 *result = GL_WAIT_FAILED;
4945 uint32_t v32_0 = 0, v32_1 = 0;
4946 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
4947 helper_->ClientWaitSync(
4948 ToGLuint(sync), flags, v32_0, v32_1,
4949 GetResultShmId(), GetResultShmOffset());
4950 WaitForCmd();
4951 GPU_CLIENT_LOG("returned " << *result);
4952 CheckGLError();
4953 return *result;
4956 void GLES2Implementation::WaitSync(
4957 GLsync sync, GLbitfield flags, GLuint64 timeout) {
4958 GPU_CLIENT_SINGLE_THREAD_CHECK();
4959 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync << ", "
4960 << flags << ", " << timeout << ")");
4961 uint32_t v32_0 = 0, v32_1 = 0;
4962 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
4963 helper_->WaitSync(ToGLuint(sync), flags, v32_0, v32_1);
4964 CheckGLError();
4967 // Include the auto-generated part of this file. We split this because it means
4968 // we can easily edit the non-auto generated parts right here in this file
4969 // instead of having to edit some template or the code generator.
4970 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
4972 } // namespace gles2
4973 } // namespace gpu