Add abhijeet.k@samsung.com to AUTHORS list.
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blobc93017ccc1591fd7aaf28690c583b77570edced8
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 remaining BufferRange mem; This is when a MapBufferRange() is
226 // called but not the UnmapBuffer() pair.
227 ClearMappedBufferRangeMap();
229 // Release any per-context data in share group.
230 share_group_->FreeContext(this);
232 buffer_tracker_.reset();
234 FreeAllAsyncUploadBuffers();
236 if (async_upload_sync_) {
237 mapped_memory_->Free(async_upload_sync_);
238 async_upload_sync_ = NULL;
241 // Make sure the commands make it the service.
242 WaitForCmd();
245 GLES2CmdHelper* GLES2Implementation::helper() const {
246 return helper_;
249 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
250 return share_group_->GetIdHandler(namespace_id);
253 IdAllocator* GLES2Implementation::GetIdAllocator(int namespace_id) const {
254 if (namespace_id == id_namespaces::kQueries)
255 return query_id_allocator_.get();
256 NOTREACHED();
257 return NULL;
260 void* GLES2Implementation::GetResultBuffer() {
261 return transfer_buffer_->GetResultBuffer();
264 int32 GLES2Implementation::GetResultShmId() {
265 return transfer_buffer_->GetShmId();
268 uint32 GLES2Implementation::GetResultShmOffset() {
269 return transfer_buffer_->GetResultOffset();
272 void GLES2Implementation::FreeUnusedSharedMemory() {
273 mapped_memory_->FreeUnused();
276 void GLES2Implementation::FreeEverything() {
277 FreeAllAsyncUploadBuffers();
278 WaitForCmd();
279 query_tracker_->Shrink();
280 FreeUnusedSharedMemory();
281 transfer_buffer_->Free();
282 helper_->FreeRingBuffer();
285 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
286 if (!helper_->IsContextLost())
287 callback.Run();
290 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
291 const base::Closure& callback) {
292 gpu_control_->SignalSyncPoint(
293 sync_point,
294 base::Bind(&GLES2Implementation::RunIfContextNotLost,
295 weak_ptr_factory_.GetWeakPtr(),
296 callback));
299 void GLES2Implementation::SignalQuery(uint32 query,
300 const base::Closure& callback) {
301 // Flush previously entered commands to ensure ordering with any
302 // glBeginQueryEXT() calls that may have been put into the context.
303 ShallowFlushCHROMIUM();
304 gpu_control_->SignalQuery(
305 query,
306 base::Bind(&GLES2Implementation::RunIfContextNotLost,
307 weak_ptr_factory_.GetWeakPtr(),
308 callback));
311 void GLES2Implementation::SetSurfaceVisible(bool visible) {
312 TRACE_EVENT1(
313 "gpu", "GLES2Implementation::SetSurfaceVisible", "visible", visible);
314 // TODO(piman): This probably should be ShallowFlushCHROMIUM().
315 Flush();
316 gpu_control_->SetSurfaceVisible(visible);
317 if (!visible)
318 FreeEverything();
321 void GLES2Implementation::WaitForCmd() {
322 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
323 helper_->CommandBufferHelper::Finish();
326 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
327 const char* extensions =
328 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
329 if (!extensions)
330 return false;
332 int length = strlen(ext);
333 while (true) {
334 int n = strcspn(extensions, " ");
335 if (n == length && 0 == strncmp(ext, extensions, length)) {
336 return true;
338 if ('\0' == extensions[n]) {
339 return false;
341 extensions += n + 1;
345 bool GLES2Implementation::IsExtensionAvailableHelper(
346 const char* extension, ExtensionStatus* status) {
347 switch (*status) {
348 case kAvailableExtensionStatus:
349 return true;
350 case kUnavailableExtensionStatus:
351 return false;
352 default: {
353 bool available = IsExtensionAvailable(extension);
354 *status = available ? kAvailableExtensionStatus :
355 kUnavailableExtensionStatus;
356 return available;
361 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
362 return IsExtensionAvailableHelper(
363 "GL_ANGLE_pack_reverse_row_order",
364 &angle_pack_reverse_row_order_status_);
367 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
368 return IsExtensionAvailableHelper(
369 "GL_CHROMIUM_framebuffer_multisample",
370 &chromium_framebuffer_multisample_);
373 const std::string& GLES2Implementation::GetLogPrefix() const {
374 const std::string& prefix(debug_marker_manager_.GetMarker());
375 return prefix.empty() ? this_in_hex_ : prefix;
378 GLenum GLES2Implementation::GetError() {
379 GPU_CLIENT_SINGLE_THREAD_CHECK();
380 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
381 GLenum err = GetGLError();
382 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
383 return err;
386 GLenum GLES2Implementation::GetClientSideGLError() {
387 if (error_bits_ == 0) {
388 return GL_NO_ERROR;
391 GLenum error = GL_NO_ERROR;
392 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
393 if ((error_bits_ & mask) != 0) {
394 error = GLES2Util::GLErrorBitToGLError(mask);
395 break;
398 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
399 return error;
402 GLenum GLES2Implementation::GetGLError() {
403 TRACE_EVENT0("gpu", "GLES2::GetGLError");
404 // Check the GL error first, then our wrapped error.
405 typedef cmds::GetError::Result Result;
406 Result* result = GetResultAs<Result*>();
407 // If we couldn't allocate a result the context is lost.
408 if (!result) {
409 return GL_NO_ERROR;
411 *result = GL_NO_ERROR;
412 helper_->GetError(GetResultShmId(), GetResultShmOffset());
413 WaitForCmd();
414 GLenum error = *result;
415 if (error == GL_NO_ERROR) {
416 error = GetClientSideGLError();
417 } else {
418 // There was an error, clear the corresponding wrapped error.
419 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
421 return error;
424 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
425 void GLES2Implementation::FailGLError(GLenum error) {
426 if (error != GL_NO_ERROR) {
427 NOTREACHED() << "Error";
430 // NOTE: Calling GetGLError overwrites data in the result buffer.
431 void GLES2Implementation::CheckGLError() {
432 FailGLError(GetGLError());
434 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
436 void GLES2Implementation::SetGLError(
437 GLenum error, const char* function_name, const char* msg) {
438 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
439 << GLES2Util::GetStringError(error) << ": "
440 << function_name << ": " << msg);
441 FailGLError(error);
442 if (msg) {
443 last_error_ = msg;
445 if (error_message_callback_) {
446 std::string temp(GLES2Util::GetStringError(error) + " : " +
447 function_name + ": " + (msg ? msg : ""));
448 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
450 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
452 if (error == GL_OUT_OF_MEMORY && lose_context_when_out_of_memory_) {
453 helper_->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
454 GL_UNKNOWN_CONTEXT_RESET_ARB);
458 void GLES2Implementation::SetGLErrorInvalidEnum(
459 const char* function_name, GLenum value, const char* label) {
460 SetGLError(GL_INVALID_ENUM, function_name,
461 (std::string(label) + " was " +
462 GLES2Util::GetStringEnum(value)).c_str());
465 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
466 std::vector<int8>* data) {
467 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
468 DCHECK(data);
469 const uint32 kStartSize = 32 * 1024;
470 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
471 if (!buffer.valid()) {
472 return false;
474 typedef cmd::GetBucketStart::Result Result;
475 Result* result = GetResultAs<Result*>();
476 if (!result) {
477 return false;
479 *result = 0;
480 helper_->GetBucketStart(
481 bucket_id, GetResultShmId(), GetResultShmOffset(),
482 buffer.size(), buffer.shm_id(), buffer.offset());
483 WaitForCmd();
484 uint32 size = *result;
485 data->resize(size);
486 if (size > 0u) {
487 uint32 offset = 0;
488 while (size) {
489 if (!buffer.valid()) {
490 buffer.Reset(size);
491 if (!buffer.valid()) {
492 return false;
494 helper_->GetBucketData(
495 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
496 WaitForCmd();
498 uint32 size_to_copy = std::min(size, buffer.size());
499 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
500 offset += size_to_copy;
501 size -= size_to_copy;
502 buffer.Release();
504 // Free the bucket. This is not required but it does free up the memory.
505 // and we don't have to wait for the result so from the client's perspective
506 // it's cheap.
507 helper_->SetBucketSize(bucket_id, 0);
509 return true;
512 void GLES2Implementation::SetBucketContents(
513 uint32 bucket_id, const void* data, size_t size) {
514 DCHECK(data);
515 helper_->SetBucketSize(bucket_id, size);
516 if (size > 0u) {
517 uint32 offset = 0;
518 while (size) {
519 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
520 if (!buffer.valid()) {
521 return;
523 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
524 buffer.size());
525 helper_->SetBucketData(
526 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
527 offset += buffer.size();
528 size -= buffer.size();
533 void GLES2Implementation::SetBucketAsCString(
534 uint32 bucket_id, const char* str) {
535 // NOTE: strings are passed NULL terminated. That means the empty
536 // string will have a size of 1 and no-string will have a size of 0
537 if (str) {
538 SetBucketContents(bucket_id, str, strlen(str) + 1);
539 } else {
540 helper_->SetBucketSize(bucket_id, 0);
544 bool GLES2Implementation::GetBucketAsString(
545 uint32 bucket_id, std::string* str) {
546 DCHECK(str);
547 std::vector<int8> data;
548 // NOTE: strings are passed NULL terminated. That means the empty
549 // string will have a size of 1 and no-string will have a size of 0
550 if (!GetBucketContents(bucket_id, &data)) {
551 return false;
553 if (data.empty()) {
554 return false;
556 str->assign(&data[0], &data[0] + data.size() - 1);
557 return true;
560 void GLES2Implementation::SetBucketAsString(
561 uint32 bucket_id, const std::string& str) {
562 // NOTE: strings are passed NULL terminated. That means the empty
563 // string will have a size of 1 and no-string will have a size of 0
564 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
567 void GLES2Implementation::Disable(GLenum cap) {
568 GPU_CLIENT_SINGLE_THREAD_CHECK();
569 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
570 << GLES2Util::GetStringCapability(cap) << ")");
571 bool changed = false;
572 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
573 helper_->Disable(cap);
575 CheckGLError();
578 void GLES2Implementation::Enable(GLenum cap) {
579 GPU_CLIENT_SINGLE_THREAD_CHECK();
580 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
581 << GLES2Util::GetStringCapability(cap) << ")");
582 bool changed = false;
583 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
584 helper_->Enable(cap);
586 CheckGLError();
589 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
590 GPU_CLIENT_SINGLE_THREAD_CHECK();
591 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
592 << GLES2Util::GetStringCapability(cap) << ")");
593 bool state = false;
594 if (!state_.GetEnabled(cap, &state)) {
595 typedef cmds::IsEnabled::Result Result;
596 Result* result = GetResultAs<Result*>();
597 if (!result) {
598 return GL_FALSE;
600 *result = 0;
601 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
602 WaitForCmd();
603 state = (*result) != 0;
606 GPU_CLIENT_LOG("returned " << state);
607 CheckGLError();
608 return state;
611 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
612 // TODO(zmo): For all the BINDING points, there is a possibility where
613 // resources are shared among multiple contexts, that the cached points
614 // are invalid. It is not a problem for now, but once we allow resource
615 // sharing in WebGL, we need to implement a mechanism to allow correct
616 // client side binding points tracking. crbug.com/465562.
617 switch (pname) {
618 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
619 *params = capabilities_.max_combined_texture_image_units;
620 return true;
621 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
622 *params = capabilities_.max_cube_map_texture_size;
623 return true;
624 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
625 *params = capabilities_.max_fragment_uniform_vectors;
626 return true;
627 case GL_MAX_RENDERBUFFER_SIZE:
628 *params = capabilities_.max_renderbuffer_size;
629 return true;
630 case GL_MAX_TEXTURE_IMAGE_UNITS:
631 *params = capabilities_.max_texture_image_units;
632 return true;
633 case GL_MAX_TEXTURE_SIZE:
634 *params = capabilities_.max_texture_size;
635 return true;
636 case GL_MAX_VARYING_VECTORS:
637 *params = capabilities_.max_varying_vectors;
638 return true;
639 case GL_MAX_VERTEX_ATTRIBS:
640 *params = capabilities_.max_vertex_attribs;
641 return true;
642 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
643 *params = capabilities_.max_vertex_texture_image_units;
644 return true;
645 case GL_MAX_VERTEX_UNIFORM_VECTORS:
646 *params = capabilities_.max_vertex_uniform_vectors;
647 return true;
648 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
649 *params = capabilities_.num_compressed_texture_formats;
650 return true;
651 case GL_NUM_SHADER_BINARY_FORMATS:
652 *params = capabilities_.num_shader_binary_formats;
653 return true;
654 case GL_ARRAY_BUFFER_BINDING:
655 *params = bound_array_buffer_id_;
656 return true;
657 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
658 *params =
659 vertex_array_object_manager_->bound_element_array_buffer();
660 return true;
661 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
662 *params = bound_pixel_pack_transfer_buffer_id_;
663 return true;
664 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
665 *params = bound_pixel_unpack_transfer_buffer_id_;
666 return true;
667 case GL_ACTIVE_TEXTURE:
668 *params = active_texture_unit_ + GL_TEXTURE0;
669 return true;
670 case GL_TEXTURE_BINDING_2D:
671 *params = texture_units_[active_texture_unit_].bound_texture_2d;
672 return true;
673 case GL_TEXTURE_BINDING_CUBE_MAP:
674 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
675 return true;
676 case GL_TEXTURE_BINDING_EXTERNAL_OES:
677 *params =
678 texture_units_[active_texture_unit_].bound_texture_external_oes;
679 return true;
680 case GL_FRAMEBUFFER_BINDING:
681 *params = bound_framebuffer_;
682 return true;
683 case GL_READ_FRAMEBUFFER_BINDING:
684 if (IsChromiumFramebufferMultisampleAvailable()) {
685 *params = bound_read_framebuffer_;
686 return true;
688 return false;
689 case GL_RENDERBUFFER_BINDING:
690 *params = bound_renderbuffer_;
691 return true;
692 case GL_MAX_UNIFORM_BUFFER_BINDINGS:
693 *params = capabilities_.max_uniform_buffer_bindings;
694 return true;
695 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
696 *params = capabilities_.max_transform_feedback_separate_attribs;
697 return true;
698 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
699 *params = capabilities_.uniform_buffer_offset_alignment;
700 return true;
701 // TODO(zmo): Support ES3 pnames.
702 default:
703 return false;
707 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
708 // TODO(gman): Make this handle pnames that return more than 1 value.
709 GLint value;
710 if (!GetHelper(pname, &value)) {
711 return false;
713 *params = static_cast<GLboolean>(value);
714 return true;
717 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
718 // TODO(gman): Make this handle pnames that return more than 1 value.
719 GLint value;
720 if (!GetHelper(pname, &value)) {
721 return false;
723 *params = static_cast<GLfloat>(value);
724 return true;
727 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
728 return GetHelper(pname, params);
731 bool GLES2Implementation::GetInternalformativHelper(
732 GLenum target, GLenum format, GLenum pname, GLsizei bufSize,
733 GLint* params) {
734 // TODO(zmo): Implement the client side caching.
735 return false;
738 bool GLES2Implementation::GetSyncivHelper(
739 GLsync sync, GLenum pname, GLsizei bufsize, GLsizei* length,
740 GLint* values) {
741 GLint value = 0;
742 switch (pname) {
743 case GL_OBJECT_TYPE:
744 value = GL_SYNC_FENCE;
745 break;
746 case GL_SYNC_CONDITION:
747 value = GL_SYNC_GPU_COMMANDS_COMPLETE;
748 break;
749 case GL_SYNC_FLAGS:
750 value = 0;
751 break;
752 default:
753 return false;
755 if (bufsize > 0) {
756 DCHECK(values);
757 *values = value;
759 if (length) {
760 *length = 1;
762 return true;
765 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
766 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
767 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
768 Result* result = GetResultAs<Result*>();
769 if (!result) {
770 return 0;
772 *result = 0;
773 helper_->GetMaxValueInBufferCHROMIUM(
774 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
775 WaitForCmd();
776 return *result;
779 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
780 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
781 GPU_CLIENT_SINGLE_THREAD_CHECK();
782 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
783 << buffer_id << ", " << count << ", "
784 << GLES2Util::GetStringGetMaxIndexType(type)
785 << ", " << offset << ")");
786 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
787 buffer_id, count, type, offset);
788 GPU_CLIENT_LOG("returned " << result);
789 CheckGLError();
790 return result;
793 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
794 if (restore) {
795 RestoreArrayBuffer(restore);
796 // Restore the element array binding.
797 // We only need to restore it if it wasn't a client side array.
798 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
799 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
804 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
805 if (restore) {
806 // Restore the user's current binding.
807 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_);
811 void GLES2Implementation::DrawElements(
812 GLenum mode, GLsizei count, GLenum type, const void* indices) {
813 GPU_CLIENT_SINGLE_THREAD_CHECK();
814 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
815 << GLES2Util::GetStringDrawMode(mode) << ", "
816 << count << ", "
817 << GLES2Util::GetStringIndexType(type) << ", "
818 << static_cast<const void*>(indices) << ")");
819 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
822 void GLES2Implementation::DrawRangeElements(
823 GLenum mode, GLuint start, GLuint end,
824 GLsizei count, GLenum type, const void* indices) {
825 GPU_CLIENT_SINGLE_THREAD_CHECK();
826 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawRangeElements("
827 << GLES2Util::GetStringDrawMode(mode) << ", "
828 << start << ", " << end << ", " << count << ", "
829 << GLES2Util::GetStringIndexType(type) << ", "
830 << static_cast<const void*>(indices) << ")");
831 if (end < start) {
832 SetGLError(GL_INVALID_VALUE, "glDrawRangeElements", "end < start");
833 return;
835 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
838 void GLES2Implementation::DrawElementsImpl(
839 GLenum mode, GLsizei count, GLenum type, const void* indices,
840 const char* func_name) {
841 if (count < 0) {
842 SetGLError(GL_INVALID_VALUE, func_name, "count < 0");
843 return;
845 bool simulated = false;
846 GLuint offset = ToGLuint(indices);
847 if (count > 0) {
848 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
849 !ValidateOffset(func_name, reinterpret_cast<GLintptr>(indices))) {
850 return;
852 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
853 func_name, this, helper_, count, type, 0, indices,
854 &offset, &simulated)) {
855 return;
858 helper_->DrawElements(mode, count, type, offset);
859 RestoreElementAndArrayBuffers(simulated);
860 CheckGLError();
863 void GLES2Implementation::Flush() {
864 GPU_CLIENT_SINGLE_THREAD_CHECK();
865 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
866 // Insert the cmd to call glFlush
867 helper_->Flush();
868 // Flush our command buffer
869 // (tell the service to execute up to the flush cmd.)
870 helper_->CommandBufferHelper::Flush();
873 void GLES2Implementation::ShallowFlushCHROMIUM() {
874 GPU_CLIENT_SINGLE_THREAD_CHECK();
875 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
876 // Flush our command buffer
877 // (tell the service to execute up to the flush cmd.)
878 helper_->CommandBufferHelper::Flush();
879 // TODO(piman): Add the FreeEverything() logic here.
882 void GLES2Implementation::OrderingBarrierCHROMIUM() {
883 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOrderingBarrierCHROMIUM");
884 // Flush command buffer at the GPU channel level. May be implemented as
885 // Flush().
886 helper_->CommandBufferHelper::OrderingBarrier();
889 void GLES2Implementation::Finish() {
890 GPU_CLIENT_SINGLE_THREAD_CHECK();
891 FinishHelper();
894 void GLES2Implementation::ShallowFinishCHROMIUM() {
895 GPU_CLIENT_SINGLE_THREAD_CHECK();
896 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
897 // Flush our command buffer (tell the service to execute up to the flush cmd
898 // and don't return until it completes).
899 helper_->CommandBufferHelper::Finish();
902 void GLES2Implementation::FinishHelper() {
903 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
904 TRACE_EVENT0("gpu", "GLES2::Finish");
905 // Insert the cmd to call glFinish
906 helper_->Finish();
907 // Finish our command buffer
908 // (tell the service to execute up to the Finish cmd and wait for it to
909 // execute.)
910 helper_->CommandBufferHelper::Finish();
913 void GLES2Implementation::SwapBuffers() {
914 GPU_CLIENT_SINGLE_THREAD_CHECK();
915 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
916 // TODO(piman): Strictly speaking we'd want to insert the token after the
917 // swap, but the state update with the updated token might not have happened
918 // by the time the SwapBuffer callback gets called, forcing us to synchronize
919 // with the GPU process more than needed. So instead, make it happen before.
920 // All it means is that we could be slightly looser on the kMaxSwapBuffers
921 // semantics if the client doesn't use the callback mechanism, and by chance
922 // the scheduler yields between the InsertToken and the SwapBuffers.
923 swap_buffers_tokens_.push(helper_->InsertToken());
924 helper_->SwapBuffers();
925 helper_->CommandBufferHelper::Flush();
926 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
927 // compensate for TODO above.
928 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
929 helper_->WaitForToken(swap_buffers_tokens_.front());
930 swap_buffers_tokens_.pop();
934 void GLES2Implementation::SwapInterval(int interval) {
935 GPU_CLIENT_SINGLE_THREAD_CHECK();
936 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapInterval("
937 << interval << ")");
938 helper_->SwapInterval(interval);
941 void GLES2Implementation::BindAttribLocation(
942 GLuint program, GLuint index, const char* name) {
943 GPU_CLIENT_SINGLE_THREAD_CHECK();
944 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
945 << program << ", " << index << ", " << name << ")");
946 SetBucketAsString(kResultBucketId, name);
947 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
948 helper_->SetBucketSize(kResultBucketId, 0);
949 CheckGLError();
952 void GLES2Implementation::BindUniformLocationCHROMIUM(
953 GLuint program, GLint location, const char* name) {
954 GPU_CLIENT_SINGLE_THREAD_CHECK();
955 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
956 << program << ", " << location << ", " << name << ")");
957 SetBucketAsString(kResultBucketId, name);
958 helper_->BindUniformLocationCHROMIUMBucket(
959 program, location, kResultBucketId);
960 helper_->SetBucketSize(kResultBucketId, 0);
961 CheckGLError();
964 void GLES2Implementation::GetVertexAttribPointerv(
965 GLuint index, GLenum pname, void** ptr) {
966 GPU_CLIENT_SINGLE_THREAD_CHECK();
967 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
968 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
969 << static_cast<void*>(ptr) << ")");
970 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
971 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
972 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
973 typedef cmds::GetVertexAttribPointerv::Result Result;
974 Result* result = GetResultAs<Result*>();
975 if (!result) {
976 return;
978 result->SetNumResults(0);
979 helper_->GetVertexAttribPointerv(
980 index, pname, GetResultShmId(), GetResultShmOffset());
981 WaitForCmd();
982 result->CopyResult(ptr);
983 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
985 GPU_CLIENT_LOG_CODE_BLOCK({
986 for (int32 i = 0; i < num_results; ++i) {
987 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
990 CheckGLError();
993 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
994 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
995 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
996 SetGLError(
997 GL_INVALID_VALUE,
998 "glDeleteProgram", "id not created by this context.");
999 return false;
1001 if (program == current_program_) {
1002 current_program_ = 0;
1004 return true;
1007 void GLES2Implementation::DeleteProgramStub(
1008 GLsizei n, const GLuint* programs) {
1009 DCHECK_EQ(1, n);
1010 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1011 helper_->DeleteProgram(programs[0]);
1014 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1015 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1016 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1017 SetGLError(
1018 GL_INVALID_VALUE,
1019 "glDeleteShader", "id not created by this context.");
1020 return false;
1022 return true;
1025 void GLES2Implementation::DeleteShaderStub(
1026 GLsizei n, const GLuint* shaders) {
1027 DCHECK_EQ(1, n);
1028 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1029 helper_->DeleteShader(shaders[0]);
1032 void GLES2Implementation::DeleteSyncHelper(GLsync sync) {
1033 GLuint sync_uint = ToGLuint(sync);
1034 if (!GetIdHandler(id_namespaces::kSyncs)->FreeIds(
1035 this, 1, &sync_uint, &GLES2Implementation::DeleteSyncStub)) {
1036 SetGLError(
1037 GL_INVALID_VALUE,
1038 "glDeleteSync", "id not created by this context.");
1042 void GLES2Implementation::DeleteSyncStub(GLsizei n, const GLuint* syncs) {
1043 DCHECK_EQ(1, n);
1044 helper_->DeleteSync(syncs[0]);
1047 GLint GLES2Implementation::GetAttribLocationHelper(
1048 GLuint program, const char* name) {
1049 typedef cmds::GetAttribLocation::Result Result;
1050 Result* result = GetResultAs<Result*>();
1051 if (!result) {
1052 return -1;
1054 *result = -1;
1055 SetBucketAsCString(kResultBucketId, name);
1056 helper_->GetAttribLocation(
1057 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1058 WaitForCmd();
1059 helper_->SetBucketSize(kResultBucketId, 0);
1060 return *result;
1063 GLint GLES2Implementation::GetAttribLocation(
1064 GLuint program, const char* name) {
1065 GPU_CLIENT_SINGLE_THREAD_CHECK();
1066 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1067 << ", " << name << ")");
1068 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1069 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1070 this, program, name);
1071 GPU_CLIENT_LOG("returned " << loc);
1072 CheckGLError();
1073 return loc;
1076 GLint GLES2Implementation::GetUniformLocationHelper(
1077 GLuint program, const char* name) {
1078 typedef cmds::GetUniformLocation::Result Result;
1079 Result* result = GetResultAs<Result*>();
1080 if (!result) {
1081 return -1;
1083 *result = -1;
1084 SetBucketAsCString(kResultBucketId, name);
1085 helper_->GetUniformLocation(program, kResultBucketId,
1086 GetResultShmId(), GetResultShmOffset());
1087 WaitForCmd();
1088 helper_->SetBucketSize(kResultBucketId, 0);
1089 return *result;
1092 GLint GLES2Implementation::GetUniformLocation(
1093 GLuint program, const char* name) {
1094 GPU_CLIENT_SINGLE_THREAD_CHECK();
1095 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1096 << ", " << name << ")");
1097 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1098 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1099 this, program, name);
1100 GPU_CLIENT_LOG("returned " << loc);
1101 CheckGLError();
1102 return loc;
1105 bool GLES2Implementation::GetUniformIndicesHelper(
1106 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1107 typedef cmds::GetUniformIndices::Result Result;
1108 Result* result = GetResultAs<Result*>();
1109 if (!result) {
1110 return false;
1112 result->SetNumResults(0);
1113 if (!PackStringsToBucket(count, names, NULL, "glGetUniformIndices")) {
1114 return false;
1116 helper_->GetUniformIndices(program, kResultBucketId,
1117 GetResultShmId(), GetResultShmOffset());
1118 WaitForCmd();
1119 if (result->GetNumResults() != count) {
1120 return false;
1122 result->CopyResult(indices);
1123 return true;
1126 void GLES2Implementation::GetUniformIndices(
1127 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1128 GPU_CLIENT_SINGLE_THREAD_CHECK();
1129 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
1130 << ", " << count << ", " << names << ", " << indices << ")");
1131 TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
1132 if (count < 0) {
1133 SetGLError(GL_INVALID_VALUE, "glGetUniformIndices", "count < 0");
1134 return;
1136 if (count == 0) {
1137 return;
1139 bool success = share_group_->program_info_manager()->GetUniformIndices(
1140 this, program, count, names, indices);
1141 if (success) {
1142 GPU_CLIENT_LOG_CODE_BLOCK({
1143 for (GLsizei ii = 0; ii < count; ++ii) {
1144 GPU_CLIENT_LOG(" " << ii << ": " << indices[ii]);
1148 CheckGLError();
1151 bool GLES2Implementation::GetProgramivHelper(
1152 GLuint program, GLenum pname, GLint* params) {
1153 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1154 this, program, pname, params);
1155 GPU_CLIENT_LOG_CODE_BLOCK({
1156 if (got_value) {
1157 GPU_CLIENT_LOG(" 0: " << *params);
1160 return got_value;
1163 GLint GLES2Implementation::GetFragDataLocationHelper(
1164 GLuint program, const char* name) {
1165 typedef cmds::GetFragDataLocation::Result Result;
1166 Result* result = GetResultAs<Result*>();
1167 if (!result) {
1168 return -1;
1170 *result = -1;
1171 SetBucketAsCString(kResultBucketId, name);
1172 helper_->GetFragDataLocation(
1173 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1174 WaitForCmd();
1175 helper_->SetBucketSize(kResultBucketId, 0);
1176 return *result;
1179 GLint GLES2Implementation::GetFragDataLocation(
1180 GLuint program, const char* name) {
1181 GPU_CLIENT_SINGLE_THREAD_CHECK();
1182 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataLocation("
1183 << program << ", " << name << ")");
1184 TRACE_EVENT0("gpu", "GLES2::GetFragDataLocation");
1185 GLint loc = share_group_->program_info_manager()->GetFragDataLocation(
1186 this, program, name);
1187 GPU_CLIENT_LOG("returned " << loc);
1188 CheckGLError();
1189 return loc;
1192 GLuint GLES2Implementation::GetUniformBlockIndexHelper(
1193 GLuint program, const char* name) {
1194 typedef cmds::GetUniformBlockIndex::Result Result;
1195 Result* result = GetResultAs<Result*>();
1196 if (!result) {
1197 return GL_INVALID_INDEX;
1199 *result = GL_INVALID_INDEX;
1200 SetBucketAsCString(kResultBucketId, name);
1201 helper_->GetUniformBlockIndex(
1202 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1203 WaitForCmd();
1204 helper_->SetBucketSize(kResultBucketId, 0);
1205 return *result;
1208 GLuint GLES2Implementation::GetUniformBlockIndex(
1209 GLuint program, const char* name) {
1210 GPU_CLIENT_SINGLE_THREAD_CHECK();
1211 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformBlockIndex("
1212 << program << ", " << name << ")");
1213 TRACE_EVENT0("gpu", "GLES2::GetUniformBlockIndex");
1214 GLuint index = share_group_->program_info_manager()->GetUniformBlockIndex(
1215 this, program, name);
1216 GPU_CLIENT_LOG("returned " << index);
1217 CheckGLError();
1218 return index;
1221 void GLES2Implementation::LinkProgram(GLuint program) {
1222 GPU_CLIENT_SINGLE_THREAD_CHECK();
1223 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1224 helper_->LinkProgram(program);
1225 share_group_->program_info_manager()->CreateInfo(program);
1226 CheckGLError();
1229 void GLES2Implementation::ShaderBinary(
1230 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1231 GLsizei length) {
1232 GPU_CLIENT_SINGLE_THREAD_CHECK();
1233 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1234 << static_cast<const void*>(shaders) << ", "
1235 << GLES2Util::GetStringEnum(binaryformat) << ", "
1236 << static_cast<const void*>(binary) << ", "
1237 << length << ")");
1238 if (n < 0) {
1239 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1240 return;
1242 if (length < 0) {
1243 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1244 return;
1246 // TODO(gman): ShaderBinary should use buckets.
1247 unsigned int shader_id_size = n * sizeof(*shaders);
1248 ScopedTransferBufferArray<GLint> buffer(
1249 shader_id_size + length, helper_, transfer_buffer_);
1250 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1251 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1252 return;
1254 void* shader_ids = buffer.elements();
1255 void* shader_data = buffer.elements() + shader_id_size;
1256 memcpy(shader_ids, shaders, shader_id_size);
1257 memcpy(shader_data, binary, length);
1258 helper_->ShaderBinary(
1260 buffer.shm_id(),
1261 buffer.offset(),
1262 binaryformat,
1263 buffer.shm_id(),
1264 buffer.offset() + shader_id_size,
1265 length);
1266 CheckGLError();
1269 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1270 GPU_CLIENT_SINGLE_THREAD_CHECK();
1271 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1272 << GLES2Util::GetStringPixelStore(pname) << ", "
1273 << param << ")");
1274 switch (pname) {
1275 case GL_PACK_ALIGNMENT:
1276 pack_alignment_ = param;
1277 break;
1278 case GL_UNPACK_ALIGNMENT:
1279 unpack_alignment_ = param;
1280 break;
1281 case GL_UNPACK_ROW_LENGTH_EXT:
1282 unpack_row_length_ = param;
1283 return;
1284 case GL_UNPACK_IMAGE_HEIGHT:
1285 unpack_image_height_ = param;
1286 return;
1287 case GL_UNPACK_SKIP_ROWS_EXT:
1288 unpack_skip_rows_ = param;
1289 return;
1290 case GL_UNPACK_SKIP_PIXELS_EXT:
1291 unpack_skip_pixels_ = param;
1292 return;
1293 case GL_UNPACK_SKIP_IMAGES:
1294 unpack_skip_images_ = param;
1295 return;
1296 case GL_UNPACK_FLIP_Y_CHROMIUM:
1297 unpack_flip_y_ = (param != 0);
1298 break;
1299 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1300 pack_reverse_row_order_ =
1301 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1302 break;
1303 default:
1304 break;
1306 helper_->PixelStorei(pname, param);
1307 CheckGLError();
1310 void GLES2Implementation::VertexAttribIPointer(
1311 GLuint index, GLint size, GLenum type, GLsizei stride, const void* ptr) {
1312 GPU_CLIENT_SINGLE_THREAD_CHECK();
1313 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1314 << index << ", "
1315 << size << ", "
1316 << GLES2Util::GetStringVertexAttribType(type) << ", "
1317 << stride << ", "
1318 << ptr << ")");
1319 helper_->VertexAttribIPointer(index, size, type, stride, ToGLuint(ptr));
1320 CheckGLError();
1323 void GLES2Implementation::VertexAttribPointer(
1324 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1325 const void* ptr) {
1326 GPU_CLIENT_SINGLE_THREAD_CHECK();
1327 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1328 << index << ", "
1329 << size << ", "
1330 << GLES2Util::GetStringVertexAttribType(type) << ", "
1331 << GLES2Util::GetStringBool(normalized) << ", "
1332 << stride << ", "
1333 << ptr << ")");
1334 // Record the info on the client side.
1335 if (!vertex_array_object_manager_->SetAttribPointer(
1336 bound_array_buffer_id_, index, size, type, normalized, stride, ptr)) {
1337 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1338 "client side arrays are not allowed in vertex array objects.");
1339 return;
1341 if (!support_client_side_arrays_ || bound_array_buffer_id_ != 0) {
1342 // Only report NON client side buffers to the service.
1343 if (!ValidateOffset("glVertexAttribPointer",
1344 reinterpret_cast<GLintptr>(ptr))) {
1345 return;
1347 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1348 ToGLuint(ptr));
1350 CheckGLError();
1353 void GLES2Implementation::VertexAttribDivisorANGLE(
1354 GLuint index, GLuint divisor) {
1355 GPU_CLIENT_SINGLE_THREAD_CHECK();
1356 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1357 << index << ", "
1358 << divisor << ") ");
1359 // Record the info on the client side.
1360 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1361 helper_->VertexAttribDivisorANGLE(index, divisor);
1362 CheckGLError();
1365 void GLES2Implementation::BufferDataHelper(
1366 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1367 if (!ValidateSize("glBufferData", size))
1368 return;
1370 #if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
1371 // Do not upload uninitialized data. Even if it's not a bug, it can cause a
1372 // bogus MSan report during a readback later. This is because MSan doesn't
1373 // understand shared memory and would assume we were reading back the same
1374 // unintialized data.
1375 if (data) __msan_check_mem_is_initialized(data, size);
1376 #endif
1378 GLuint buffer_id;
1379 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1380 if (!buffer_id) {
1381 return;
1384 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1385 if (buffer)
1386 RemoveTransferBuffer(buffer);
1388 // Create new buffer.
1389 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1390 DCHECK(buffer);
1391 if (buffer->address() && data)
1392 memcpy(buffer->address(), data, size);
1393 return;
1396 RemoveMappedBufferRangeByTarget(target);
1398 // If there is no data just send BufferData
1399 if (size == 0 || !data) {
1400 helper_->BufferData(target, size, 0, 0, usage);
1401 return;
1404 // See if we can send all at once.
1405 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1406 if (!buffer.valid()) {
1407 return;
1410 if (buffer.size() >= static_cast<unsigned int>(size)) {
1411 memcpy(buffer.address(), data, size);
1412 helper_->BufferData(
1413 target,
1414 size,
1415 buffer.shm_id(),
1416 buffer.offset(),
1417 usage);
1418 return;
1421 // Make the buffer with BufferData then send via BufferSubData
1422 helper_->BufferData(target, size, 0, 0, usage);
1423 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1424 CheckGLError();
1427 void GLES2Implementation::BufferData(
1428 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1429 GPU_CLIENT_SINGLE_THREAD_CHECK();
1430 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1431 << GLES2Util::GetStringBufferTarget(target) << ", "
1432 << size << ", "
1433 << static_cast<const void*>(data) << ", "
1434 << GLES2Util::GetStringBufferUsage(usage) << ")");
1435 BufferDataHelper(target, size, data, usage);
1436 CheckGLError();
1439 void GLES2Implementation::BufferSubDataHelper(
1440 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1441 if (size == 0) {
1442 return;
1445 if (!ValidateSize("glBufferSubData", size) ||
1446 !ValidateOffset("glBufferSubData", offset)) {
1447 return;
1450 GLuint buffer_id;
1451 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1452 if (!buffer_id) {
1453 return;
1455 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1456 if (!buffer) {
1457 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1458 return;
1461 int32 end = 0;
1462 int32 buffer_size = buffer->size();
1463 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1464 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1465 return;
1468 if (buffer->address() && data)
1469 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1470 return;
1473 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1474 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1477 void GLES2Implementation::BufferSubDataHelperImpl(
1478 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1479 ScopedTransferBufferPtr* buffer) {
1480 DCHECK(buffer);
1481 DCHECK_GT(size, 0);
1483 const int8* source = static_cast<const int8*>(data);
1484 while (size) {
1485 if (!buffer->valid() || buffer->size() == 0) {
1486 buffer->Reset(size);
1487 if (!buffer->valid()) {
1488 return;
1491 memcpy(buffer->address(), source, buffer->size());
1492 helper_->BufferSubData(
1493 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1494 offset += buffer->size();
1495 source += buffer->size();
1496 size -= buffer->size();
1497 buffer->Release();
1501 void GLES2Implementation::BufferSubData(
1502 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1503 GPU_CLIENT_SINGLE_THREAD_CHECK();
1504 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1505 << GLES2Util::GetStringBufferTarget(target) << ", "
1506 << offset << ", " << size << ", "
1507 << static_cast<const void*>(data) << ")");
1508 BufferSubDataHelper(target, offset, size, data);
1509 CheckGLError();
1512 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
1513 int32 token = buffer->last_usage_token();
1514 uint32 async_token = buffer->last_async_upload_token();
1516 if (async_token) {
1517 if (HasAsyncUploadTokenPassed(async_token)) {
1518 buffer_tracker_->Free(buffer);
1519 } else {
1520 detached_async_upload_memory_.push_back(
1521 std::make_pair(buffer->address(), async_token));
1522 buffer_tracker_->Unmanage(buffer);
1524 } else if (token) {
1525 if (helper_->HasTokenPassed(token))
1526 buffer_tracker_->Free(buffer);
1527 else
1528 buffer_tracker_->FreePendingToken(buffer, token);
1529 } else {
1530 buffer_tracker_->Free(buffer);
1533 buffer_tracker_->RemoveBuffer(buffer->id());
1536 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1537 GLenum target,
1538 const char* function_name,
1539 GLuint* buffer_id) {
1540 *buffer_id = 0;
1542 switch (target) {
1543 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1544 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1545 break;
1546 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1547 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1548 break;
1549 default:
1550 // Unknown target
1551 return false;
1553 if (!*buffer_id) {
1554 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1556 return true;
1559 BufferTracker::Buffer*
1560 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1561 GLuint buffer_id,
1562 const char* function_name,
1563 GLuint offset, GLsizei size) {
1564 DCHECK(buffer_id);
1565 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1566 if (!buffer) {
1567 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1568 return NULL;
1570 if (buffer->mapped()) {
1571 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1572 return NULL;
1574 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1575 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1576 return NULL;
1578 return buffer;
1581 void GLES2Implementation::CompressedTexImage2D(
1582 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1583 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1584 GPU_CLIENT_SINGLE_THREAD_CHECK();
1585 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1586 << GLES2Util::GetStringTextureTarget(target) << ", "
1587 << level << ", "
1588 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1589 << width << ", " << height << ", " << border << ", "
1590 << image_size << ", "
1591 << static_cast<const void*>(data) << ")");
1592 if (width < 0 || height < 0 || level < 0) {
1593 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1594 return;
1596 if (border != 0) {
1597 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "border != 0");
1598 return;
1600 if (height == 0 || width == 0) {
1601 return;
1603 // If there's a pixel unpack buffer bound use it when issuing
1604 // CompressedTexImage2D.
1605 if (bound_pixel_unpack_transfer_buffer_id_) {
1606 GLuint offset = ToGLuint(data);
1607 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1608 bound_pixel_unpack_transfer_buffer_id_,
1609 "glCompressedTexImage2D", offset, image_size);
1610 if (buffer && buffer->shm_id() != -1) {
1611 helper_->CompressedTexImage2D(
1612 target, level, internalformat, width, height, image_size,
1613 buffer->shm_id(), buffer->shm_offset() + offset);
1614 buffer->set_last_usage_token(helper_->InsertToken());
1616 return;
1618 SetBucketContents(kResultBucketId, data, image_size);
1619 helper_->CompressedTexImage2DBucket(
1620 target, level, internalformat, width, height, kResultBucketId);
1621 // Free the bucket. This is not required but it does free up the memory.
1622 // and we don't have to wait for the result so from the client's perspective
1623 // it's cheap.
1624 helper_->SetBucketSize(kResultBucketId, 0);
1625 CheckGLError();
1628 void GLES2Implementation::CompressedTexSubImage2D(
1629 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1630 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1631 GPU_CLIENT_SINGLE_THREAD_CHECK();
1632 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1633 << GLES2Util::GetStringTextureTarget(target) << ", "
1634 << level << ", "
1635 << xoffset << ", " << yoffset << ", "
1636 << width << ", " << height << ", "
1637 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1638 << image_size << ", "
1639 << static_cast<const void*>(data) << ")");
1640 if (width < 0 || height < 0 || level < 0) {
1641 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1642 return;
1644 // If there's a pixel unpack buffer bound use it when issuing
1645 // CompressedTexSubImage2D.
1646 if (bound_pixel_unpack_transfer_buffer_id_) {
1647 GLuint offset = ToGLuint(data);
1648 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1649 bound_pixel_unpack_transfer_buffer_id_,
1650 "glCompressedTexSubImage2D", offset, image_size);
1651 if (buffer && buffer->shm_id() != -1) {
1652 helper_->CompressedTexSubImage2D(
1653 target, level, xoffset, yoffset, width, height, format, image_size,
1654 buffer->shm_id(), buffer->shm_offset() + offset);
1655 buffer->set_last_usage_token(helper_->InsertToken());
1656 CheckGLError();
1658 return;
1660 SetBucketContents(kResultBucketId, data, image_size);
1661 helper_->CompressedTexSubImage2DBucket(
1662 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1663 // Free the bucket. This is not required but it does free up the memory.
1664 // and we don't have to wait for the result so from the client's perspective
1665 // it's cheap.
1666 helper_->SetBucketSize(kResultBucketId, 0);
1667 CheckGLError();
1670 namespace {
1672 void CopyRectToBuffer(
1673 const void* pixels,
1674 uint32 height,
1675 uint32 unpadded_row_size,
1676 uint32 pixels_padded_row_size,
1677 bool flip_y,
1678 void* buffer,
1679 uint32 buffer_padded_row_size) {
1680 const int8* source = static_cast<const int8*>(pixels);
1681 int8* dest = static_cast<int8*>(buffer);
1682 if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
1683 if (flip_y) {
1684 dest += buffer_padded_row_size * (height - 1);
1686 // the last row is copied unpadded at the end
1687 for (; height > 1; --height) {
1688 memcpy(dest, source, buffer_padded_row_size);
1689 if (flip_y) {
1690 dest -= buffer_padded_row_size;
1691 } else {
1692 dest += buffer_padded_row_size;
1694 source += pixels_padded_row_size;
1696 memcpy(dest, source, unpadded_row_size);
1697 } else {
1698 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
1699 memcpy(dest, source, size);
1703 } // anonymous namespace
1705 void GLES2Implementation::TexImage2D(
1706 GLenum target, GLint level, GLint internalformat, GLsizei width,
1707 GLsizei height, GLint border, GLenum format, GLenum type,
1708 const void* pixels) {
1709 GPU_CLIENT_SINGLE_THREAD_CHECK();
1710 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1711 << GLES2Util::GetStringTextureTarget(target) << ", "
1712 << level << ", "
1713 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1714 << width << ", " << height << ", " << border << ", "
1715 << GLES2Util::GetStringTextureFormat(format) << ", "
1716 << GLES2Util::GetStringPixelType(type) << ", "
1717 << static_cast<const void*>(pixels) << ")");
1718 if (level < 0 || height < 0 || width < 0) {
1719 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
1720 return;
1722 if (border != 0) {
1723 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
1724 return;
1726 uint32 size;
1727 uint32 unpadded_row_size;
1728 uint32 padded_row_size;
1729 if (!GLES2Util::ComputeImageDataSizes(
1730 width, height, 1, format, type, unpack_alignment_, &size,
1731 &unpadded_row_size, &padded_row_size)) {
1732 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
1733 return;
1736 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1737 if (bound_pixel_unpack_transfer_buffer_id_) {
1738 GLuint offset = ToGLuint(pixels);
1739 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1740 bound_pixel_unpack_transfer_buffer_id_,
1741 "glTexImage2D", offset, size);
1742 if (buffer && buffer->shm_id() != -1) {
1743 helper_->TexImage2D(
1744 target, level, internalformat, width, height, format, type,
1745 buffer->shm_id(), buffer->shm_offset() + offset);
1746 buffer->set_last_usage_token(helper_->InsertToken());
1747 CheckGLError();
1749 return;
1752 // If there's no data just issue TexImage2D
1753 if (!pixels) {
1754 helper_->TexImage2D(
1755 target, level, internalformat, width, height, format, type,
1756 0, 0);
1757 CheckGLError();
1758 return;
1761 // compute the advance bytes per row for the src pixels
1762 uint32 src_padded_row_size;
1763 if (unpack_row_length_ > 0) {
1764 if (!GLES2Util::ComputeImagePaddedRowSize(
1765 unpack_row_length_, format, type, unpack_alignment_,
1766 &src_padded_row_size)) {
1767 SetGLError(
1768 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1769 return;
1771 } else {
1772 src_padded_row_size = padded_row_size;
1775 // advance pixels pointer past the skip rows and skip pixels
1776 pixels = reinterpret_cast<const int8*>(pixels) +
1777 unpack_skip_rows_ * src_padded_row_size;
1778 if (unpack_skip_pixels_) {
1779 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1780 pixels = reinterpret_cast<const int8*>(pixels) +
1781 unpack_skip_pixels_ * group_size;
1784 // Check if we can send it all at once.
1785 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1786 if (!buffer.valid()) {
1787 return;
1790 if (buffer.size() >= size) {
1791 CopyRectToBuffer(
1792 pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
1793 buffer.address(), padded_row_size);
1794 helper_->TexImage2D(
1795 target, level, internalformat, width, height, format, type,
1796 buffer.shm_id(), buffer.offset());
1797 CheckGLError();
1798 return;
1801 // No, so send it using TexSubImage2D.
1802 helper_->TexImage2D(
1803 target, level, internalformat, width, height, format, type,
1804 0, 0);
1805 TexSubImage2DImpl(
1806 target, level, 0, 0, width, height, format, type, unpadded_row_size,
1807 pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
1808 CheckGLError();
1811 void GLES2Implementation::TexImage3D(
1812 GLenum target, GLint level, GLint internalformat, GLsizei width,
1813 GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type,
1814 const void* pixels) {
1815 GPU_CLIENT_SINGLE_THREAD_CHECK();
1816 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D("
1817 << GLES2Util::GetStringTextureTarget(target) << ", "
1818 << level << ", "
1819 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1820 << width << ", " << height << ", " << depth << ", " << border << ", "
1821 << GLES2Util::GetStringTextureFormat(format) << ", "
1822 << GLES2Util::GetStringPixelType(type) << ", "
1823 << static_cast<const void*>(pixels) << ")");
1824 if (level < 0 || height < 0 || width < 0 || depth < 0) {
1825 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "dimension < 0");
1826 return;
1828 if (border != 0) {
1829 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "border != 0");
1830 return;
1832 uint32 size;
1833 uint32 unpadded_row_size;
1834 uint32 padded_row_size;
1835 if (!GLES2Util::ComputeImageDataSizes(
1836 width, height, depth, format, type, unpack_alignment_, &size,
1837 &unpadded_row_size, &padded_row_size)) {
1838 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large");
1839 return;
1842 // If there's a pixel unpack buffer bound use it when issuing TexImage3D.
1843 if (bound_pixel_unpack_transfer_buffer_id_) {
1844 GLuint offset = ToGLuint(pixels);
1845 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1846 bound_pixel_unpack_transfer_buffer_id_,
1847 "glTexImage3D", offset, size);
1848 if (buffer && buffer->shm_id() != -1) {
1849 helper_->TexImage3D(
1850 target, level, internalformat, width, height, depth, format, type,
1851 buffer->shm_id(), buffer->shm_offset() + offset);
1852 buffer->set_last_usage_token(helper_->InsertToken());
1853 CheckGLError();
1855 return;
1858 // If there's no data just issue TexImage3D
1859 if (!pixels) {
1860 helper_->TexImage3D(
1861 target, level, internalformat, width, height, depth, format, type,
1862 0, 0);
1863 CheckGLError();
1864 return;
1867 // compute the advance bytes per row for the src pixels
1868 uint32 src_padded_row_size;
1869 if (unpack_row_length_ > 0) {
1870 if (!GLES2Util::ComputeImagePaddedRowSize(
1871 unpack_row_length_, format, type, unpack_alignment_,
1872 &src_padded_row_size)) {
1873 SetGLError(
1874 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
1875 return;
1877 } else {
1878 src_padded_row_size = padded_row_size;
1880 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
1882 // advance pixels pointer past the skip images/rows/pixels
1883 pixels = reinterpret_cast<const int8*>(pixels) +
1884 unpack_skip_images_ * src_padded_row_size * src_height +
1885 unpack_skip_rows_ * src_padded_row_size;
1886 if (unpack_skip_pixels_) {
1887 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1888 pixels = reinterpret_cast<const int8*>(pixels) +
1889 unpack_skip_pixels_ * group_size;
1892 // Check if we can send it all at once.
1893 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1894 if (!buffer.valid()) {
1895 return;
1898 if (buffer.size() >= size) {
1899 void* buffer_pointer = buffer.address();
1900 for (GLsizei z = 0; z < depth; ++z) {
1901 // Only the last row of the last image is unpadded.
1902 uint32 src_unpadded_row_size =
1903 (z == depth - 1) ? unpadded_row_size : src_padded_row_size;
1904 // TODO(zmo): Ignore flip_y flag for now.
1905 CopyRectToBuffer(
1906 pixels, height, src_unpadded_row_size, src_padded_row_size, false,
1907 buffer_pointer, padded_row_size);
1908 pixels = reinterpret_cast<const int8*>(pixels) +
1909 src_padded_row_size * src_height;
1910 buffer_pointer = reinterpret_cast<int8*>(buffer_pointer) +
1911 padded_row_size * height;
1913 helper_->TexImage3D(
1914 target, level, internalformat, width, height, depth, format, type,
1915 buffer.shm_id(), buffer.offset());
1916 CheckGLError();
1917 return;
1920 // No, so send it using TexSubImage3D.
1921 helper_->TexImage3D(
1922 target, level, internalformat, width, height, depth, format, type,
1923 0, 0);
1924 TexSubImage3DImpl(
1925 target, level, 0, 0, 0, width, height, depth, format, type,
1926 unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &buffer,
1927 padded_row_size);
1928 CheckGLError();
1931 void GLES2Implementation::TexSubImage2D(
1932 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1933 GLsizei height, GLenum format, GLenum type, const void* pixels) {
1934 GPU_CLIENT_SINGLE_THREAD_CHECK();
1935 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1936 << GLES2Util::GetStringTextureTarget(target) << ", "
1937 << level << ", "
1938 << xoffset << ", " << yoffset << ", "
1939 << width << ", " << height << ", "
1940 << GLES2Util::GetStringTextureFormat(format) << ", "
1941 << GLES2Util::GetStringPixelType(type) << ", "
1942 << static_cast<const void*>(pixels) << ")");
1944 if (level < 0 || height < 0 || width < 0) {
1945 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
1946 return;
1948 if (height == 0 || width == 0) {
1949 return;
1952 uint32 temp_size;
1953 uint32 unpadded_row_size;
1954 uint32 padded_row_size;
1955 if (!GLES2Util::ComputeImageDataSizes(
1956 width, height, 1, format, type, unpack_alignment_, &temp_size,
1957 &unpadded_row_size, &padded_row_size)) {
1958 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
1959 return;
1962 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1963 if (bound_pixel_unpack_transfer_buffer_id_) {
1964 GLuint offset = ToGLuint(pixels);
1965 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1966 bound_pixel_unpack_transfer_buffer_id_,
1967 "glTexSubImage2D", offset, temp_size);
1968 if (buffer && buffer->shm_id() != -1) {
1969 helper_->TexSubImage2D(
1970 target, level, xoffset, yoffset, width, height, format, type,
1971 buffer->shm_id(), buffer->shm_offset() + offset, false);
1972 buffer->set_last_usage_token(helper_->InsertToken());
1973 CheckGLError();
1975 return;
1978 // compute the advance bytes per row for the src pixels
1979 uint32 src_padded_row_size;
1980 if (unpack_row_length_ > 0) {
1981 if (!GLES2Util::ComputeImagePaddedRowSize(
1982 unpack_row_length_, format, type, unpack_alignment_,
1983 &src_padded_row_size)) {
1984 SetGLError(
1985 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1986 return;
1988 } else {
1989 src_padded_row_size = padded_row_size;
1992 // advance pixels pointer past the skip rows and skip pixels
1993 pixels = reinterpret_cast<const int8*>(pixels) +
1994 unpack_skip_rows_ * src_padded_row_size;
1995 if (unpack_skip_pixels_) {
1996 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1997 pixels = reinterpret_cast<const int8*>(pixels) +
1998 unpack_skip_pixels_ * group_size;
2001 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2002 TexSubImage2DImpl(
2003 target, level, xoffset, yoffset, width, height, format, type,
2004 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
2005 padded_row_size);
2006 CheckGLError();
2009 void GLES2Implementation::TexSubImage3D(
2010 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2011 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2012 const void* pixels) {
2013 GPU_CLIENT_SINGLE_THREAD_CHECK();
2014 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D("
2015 << GLES2Util::GetStringTextureTarget(target) << ", "
2016 << level << ", "
2017 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2018 << width << ", " << height << ", " << depth << ", "
2019 << GLES2Util::GetStringTextureFormat(format) << ", "
2020 << GLES2Util::GetStringPixelType(type) << ", "
2021 << static_cast<const void*>(pixels) << ")");
2023 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2024 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "dimension < 0");
2025 return;
2027 if (height == 0 || width == 0 || depth == 0) {
2028 return;
2031 uint32 temp_size;
2032 uint32 unpadded_row_size;
2033 uint32 padded_row_size;
2034 if (!GLES2Util::ComputeImageDataSizes(
2035 width, height, depth, format, type, unpack_alignment_, &temp_size,
2036 &unpadded_row_size, &padded_row_size)) {
2037 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "size to large");
2038 return;
2041 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2042 if (bound_pixel_unpack_transfer_buffer_id_) {
2043 GLuint offset = ToGLuint(pixels);
2044 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2045 bound_pixel_unpack_transfer_buffer_id_,
2046 "glTexSubImage3D", offset, temp_size);
2047 if (buffer && buffer->shm_id() != -1) {
2048 helper_->TexSubImage3D(
2049 target, level, xoffset, yoffset, zoffset, width, height, depth,
2050 format, type, buffer->shm_id(), buffer->shm_offset() + offset, false);
2051 buffer->set_last_usage_token(helper_->InsertToken());
2052 CheckGLError();
2054 return;
2057 // compute the advance bytes per row for the src pixels
2058 uint32 src_padded_row_size;
2059 if (unpack_row_length_ > 0) {
2060 if (!GLES2Util::ComputeImagePaddedRowSize(
2061 unpack_row_length_, format, type, unpack_alignment_,
2062 &src_padded_row_size)) {
2063 SetGLError(
2064 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2065 return;
2067 } else {
2068 src_padded_row_size = padded_row_size;
2070 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2072 // advance pixels pointer past the skip images/rows/pixels
2073 pixels = reinterpret_cast<const int8*>(pixels) +
2074 unpack_skip_images_ * src_padded_row_size * src_height +
2075 unpack_skip_rows_ * src_padded_row_size;
2076 if (unpack_skip_pixels_) {
2077 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2078 pixels = reinterpret_cast<const int8*>(pixels) +
2079 unpack_skip_pixels_ * group_size;
2082 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2083 TexSubImage3DImpl(
2084 target, level, xoffset, yoffset, zoffset, width, height, depth,
2085 format, type, unpadded_row_size, pixels, src_padded_row_size, GL_FALSE,
2086 &buffer, padded_row_size);
2087 CheckGLError();
2090 static GLint ComputeNumRowsThatFitInBuffer(
2091 uint32 padded_row_size, uint32 unpadded_row_size,
2092 unsigned int size, GLsizei remaining_rows) {
2093 DCHECK_GE(unpadded_row_size, 0u);
2094 if (padded_row_size == 0) {
2095 return 1;
2097 GLint num_rows = size / padded_row_size;
2098 if (num_rows + 1 == remaining_rows &&
2099 size - num_rows * padded_row_size >= unpadded_row_size) {
2100 num_rows++;
2102 return num_rows;
2105 void GLES2Implementation::TexSubImage2DImpl(
2106 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2107 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
2108 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
2109 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
2110 DCHECK(buffer);
2111 DCHECK_GE(level, 0);
2112 DCHECK_GT(height, 0);
2113 DCHECK_GT(width, 0);
2115 const int8* source = reinterpret_cast<const int8*>(pixels);
2116 GLint original_yoffset = yoffset;
2117 // Transfer by rows.
2118 while (height) {
2119 unsigned int desired_size =
2120 buffer_padded_row_size * (height - 1) + unpadded_row_size;
2121 if (!buffer->valid() || buffer->size() == 0) {
2122 buffer->Reset(desired_size);
2123 if (!buffer->valid()) {
2124 return;
2128 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2129 buffer_padded_row_size, unpadded_row_size, buffer->size(), height);
2130 num_rows = std::min(num_rows, height);
2131 CopyRectToBuffer(
2132 source, num_rows, unpadded_row_size, pixels_padded_row_size,
2133 unpack_flip_y_, buffer->address(), buffer_padded_row_size);
2134 GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
2135 helper_->TexSubImage2D(
2136 target, level, xoffset, y, width, num_rows, format, type,
2137 buffer->shm_id(), buffer->offset(), internal);
2138 buffer->Release();
2139 yoffset += num_rows;
2140 source += num_rows * pixels_padded_row_size;
2141 height -= num_rows;
2145 void GLES2Implementation::TexSubImage3DImpl(
2146 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei zoffset,
2147 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2148 uint32 unpadded_row_size, const void* pixels, uint32 pixels_padded_row_size,
2149 GLboolean internal, ScopedTransferBufferPtr* buffer,
2150 uint32 buffer_padded_row_size) {
2151 DCHECK(buffer);
2152 DCHECK_GE(level, 0);
2153 DCHECK_GT(height, 0);
2154 DCHECK_GT(width, 0);
2155 DCHECK_GT(depth, 0);
2156 const int8* source = reinterpret_cast<const int8*>(pixels);
2157 GLsizei total_rows = height * depth;
2158 GLint row_index = 0, depth_index = 0;
2159 while (total_rows) {
2160 // Each time, we either copy one or more images, or copy one or more rows
2161 // within a single image, depending on the buffer size limit.
2162 GLsizei max_rows;
2163 unsigned int desired_size;
2164 if (row_index > 0) {
2165 // We are in the middle of an image. Send the remaining of the image.
2166 max_rows = height - row_index;
2167 if (total_rows <= height) {
2168 // Last image, so last row is unpadded.
2169 desired_size = buffer_padded_row_size * (max_rows - 1) +
2170 unpadded_row_size;
2171 } else {
2172 desired_size = buffer_padded_row_size * max_rows;
2174 } else {
2175 // Send all the remaining data if possible.
2176 max_rows = total_rows;
2177 desired_size =
2178 buffer_padded_row_size * (max_rows - 1) + unpadded_row_size;
2180 if (!buffer->valid() || buffer->size() == 0) {
2181 buffer->Reset(desired_size);
2182 if (!buffer->valid()) {
2183 return;
2186 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2187 buffer_padded_row_size, unpadded_row_size, buffer->size(), total_rows);
2188 num_rows = std::min(num_rows, max_rows);
2189 GLint num_images = num_rows / height;
2190 GLsizei my_height, my_depth;
2191 if (num_images > 0) {
2192 num_rows = num_images * height;
2193 my_height = height;
2194 my_depth = num_images;
2195 } else {
2196 my_height = num_rows;
2197 my_depth = 1;
2200 // TODO(zmo): Ignore flip_y flag for now.
2201 if (num_images > 0) {
2202 int8* buffer_pointer = reinterpret_cast<int8*>(buffer->address());
2203 uint32 src_height =
2204 unpack_image_height_ > 0 ? unpack_image_height_ : height;
2205 uint32 image_size_dst = buffer_padded_row_size * height;
2206 uint32 image_size_src = pixels_padded_row_size * src_height;
2207 for (GLint ii = 0; ii < num_images; ++ii) {
2208 uint32 my_unpadded_row_size;
2209 if (total_rows == num_rows && ii + 1 == num_images)
2210 my_unpadded_row_size = unpadded_row_size;
2211 else
2212 my_unpadded_row_size = pixels_padded_row_size;
2213 CopyRectToBuffer(
2214 source + ii * image_size_src, my_height, my_unpadded_row_size,
2215 pixels_padded_row_size, false, buffer_pointer + ii * image_size_dst,
2216 buffer_padded_row_size);
2218 } else {
2219 uint32 my_unpadded_row_size;
2220 if (total_rows == num_rows)
2221 my_unpadded_row_size = unpadded_row_size;
2222 else
2223 my_unpadded_row_size = pixels_padded_row_size;
2224 CopyRectToBuffer(
2225 source, my_height, my_unpadded_row_size, pixels_padded_row_size,
2226 false, buffer->address(), buffer_padded_row_size);
2228 helper_->TexSubImage3D(
2229 target, level, xoffset, yoffset + row_index, zoffset + depth_index,
2230 width, my_height, my_depth,
2231 format, type, buffer->shm_id(), buffer->offset(), internal);
2232 buffer->Release();
2234 total_rows -= num_rows;
2235 if (total_rows > 0) {
2236 GLint num_image_paddings;
2237 if (num_images > 0) {
2238 DCHECK_EQ(row_index, 0);
2239 depth_index += num_images;
2240 num_image_paddings = num_images;
2241 } else {
2242 row_index = (row_index + my_height) % height;
2243 num_image_paddings = 0;
2244 if (my_height > 0 && row_index == 0) {
2245 depth_index++;
2246 num_image_paddings++;
2249 source += num_rows * pixels_padded_row_size;
2250 if (unpack_image_height_ > height && num_image_paddings > 0) {
2251 source += num_image_paddings * (unpack_image_height_ - height) *
2252 pixels_padded_row_size;
2258 bool GLES2Implementation::GetActiveAttribHelper(
2259 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2260 GLenum* type, char* name) {
2261 // Clear the bucket so if the command fails nothing will be in it.
2262 helper_->SetBucketSize(kResultBucketId, 0);
2263 typedef cmds::GetActiveAttrib::Result Result;
2264 Result* result = GetResultAs<Result*>();
2265 if (!result) {
2266 return false;
2268 // Set as failed so if the command fails we'll recover.
2269 result->success = false;
2270 helper_->GetActiveAttrib(program, index, kResultBucketId,
2271 GetResultShmId(), GetResultShmOffset());
2272 WaitForCmd();
2273 if (result->success) {
2274 if (size) {
2275 *size = result->size;
2277 if (type) {
2278 *type = result->type;
2280 if (length || name) {
2281 std::vector<int8> str;
2282 GetBucketContents(kResultBucketId, &str);
2283 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2284 std::max(static_cast<size_t>(0),
2285 str.size() - 1));
2286 if (length) {
2287 *length = max_size;
2289 if (name && bufsize > 0) {
2290 memcpy(name, &str[0], max_size);
2291 name[max_size] = '\0';
2295 return result->success != 0;
2298 void GLES2Implementation::GetActiveAttrib(
2299 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2300 GLenum* type, char* name) {
2301 GPU_CLIENT_SINGLE_THREAD_CHECK();
2302 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2303 << program << ", " << index << ", " << bufsize << ", "
2304 << static_cast<const void*>(length) << ", "
2305 << static_cast<const void*>(size) << ", "
2306 << static_cast<const void*>(type) << ", "
2307 << static_cast<const void*>(name) << ", ");
2308 if (bufsize < 0) {
2309 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
2310 return;
2312 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2313 bool success = share_group_->program_info_manager()->GetActiveAttrib(
2314 this, program, index, bufsize, length, size, type, name);
2315 if (success) {
2316 if (size) {
2317 GPU_CLIENT_LOG(" size: " << *size);
2319 if (type) {
2320 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2322 if (name) {
2323 GPU_CLIENT_LOG(" name: " << name);
2326 CheckGLError();
2329 bool GLES2Implementation::GetActiveUniformHelper(
2330 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2331 GLenum* type, char* name) {
2332 // Clear the bucket so if the command fails nothing will be in it.
2333 helper_->SetBucketSize(kResultBucketId, 0);
2334 typedef cmds::GetActiveUniform::Result Result;
2335 Result* result = GetResultAs<Result*>();
2336 if (!result) {
2337 return false;
2339 // Set as failed so if the command fails we'll recover.
2340 result->success = false;
2341 helper_->GetActiveUniform(program, index, kResultBucketId,
2342 GetResultShmId(), GetResultShmOffset());
2343 WaitForCmd();
2344 if (result->success) {
2345 if (size) {
2346 *size = result->size;
2348 if (type) {
2349 *type = result->type;
2351 if (length || name) {
2352 std::vector<int8> str;
2353 GetBucketContents(kResultBucketId, &str);
2354 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2355 std::max(static_cast<size_t>(0),
2356 str.size() - 1));
2357 if (length) {
2358 *length = max_size;
2360 if (name && bufsize > 0) {
2361 memcpy(name, &str[0], max_size);
2362 name[max_size] = '\0';
2366 return result->success != 0;
2369 void GLES2Implementation::GetActiveUniform(
2370 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2371 GLenum* type, char* name) {
2372 GPU_CLIENT_SINGLE_THREAD_CHECK();
2373 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2374 << program << ", " << index << ", " << bufsize << ", "
2375 << static_cast<const void*>(length) << ", "
2376 << static_cast<const void*>(size) << ", "
2377 << static_cast<const void*>(type) << ", "
2378 << static_cast<const void*>(name) << ", ");
2379 if (bufsize < 0) {
2380 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2381 return;
2383 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2384 bool success = share_group_->program_info_manager()->GetActiveUniform(
2385 this, program, index, bufsize, length, size, type, name);
2386 if (success) {
2387 if (size) {
2388 GPU_CLIENT_LOG(" size: " << *size);
2390 if (type) {
2391 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2393 if (name) {
2394 GPU_CLIENT_LOG(" name: " << name);
2397 CheckGLError();
2400 bool GLES2Implementation::GetActiveUniformBlockNameHelper(
2401 GLuint program, GLuint index, GLsizei bufsize,
2402 GLsizei* length, char* name) {
2403 DCHECK_LE(0, bufsize);
2404 // Clear the bucket so if the command fails nothing will be in it.
2405 helper_->SetBucketSize(kResultBucketId, 0);
2406 typedef cmds::GetActiveUniformBlockName::Result Result;
2407 Result* result = GetResultAs<Result*>();
2408 if (!result) {
2409 return false;
2411 // Set as failed so if the command fails we'll recover.
2412 *result = 0;
2413 helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
2414 GetResultShmId(), GetResultShmOffset());
2415 WaitForCmd();
2416 if (*result) {
2417 if (bufsize == 0) {
2418 if (length) {
2419 *length = 0;
2421 } else if (length || name) {
2422 std::vector<int8> str;
2423 GetBucketContents(kResultBucketId, &str);
2424 DCHECK_GT(str.size(), 0u);
2425 GLsizei max_size =
2426 std::min(bufsize, static_cast<GLsizei>(str.size())) - 1;
2427 if (length) {
2428 *length = max_size;
2430 if (name) {
2431 memcpy(name, &str[0], max_size);
2432 name[max_size] = '\0';
2436 return *result != 0;
2439 void GLES2Implementation::GetActiveUniformBlockName(
2440 GLuint program, GLuint index, GLsizei bufsize,
2441 GLsizei* length, char* name) {
2442 GPU_CLIENT_SINGLE_THREAD_CHECK();
2443 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
2444 << program << ", " << index << ", " << bufsize << ", "
2445 << static_cast<const void*>(length) << ", "
2446 << static_cast<const void*>(name) << ")");
2447 if (bufsize < 0) {
2448 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformBlockName", "bufsize < 0");
2449 return;
2451 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockName");
2452 bool success =
2453 share_group_->program_info_manager()->GetActiveUniformBlockName(
2454 this, program, index, bufsize, length, name);
2455 if (success) {
2456 if (name) {
2457 GPU_CLIENT_LOG(" name: " << name);
2460 CheckGLError();
2463 bool GLES2Implementation::GetActiveUniformBlockivHelper(
2464 GLuint program, GLuint index, GLenum pname, GLint* params) {
2465 typedef cmds::GetActiveUniformBlockiv::Result Result;
2466 Result* result = GetResultAs<Result*>();
2467 if (!result) {
2468 return false;
2470 result->SetNumResults(0);
2471 helper_->GetActiveUniformBlockiv(
2472 program, index, pname, GetResultShmId(), GetResultShmOffset());
2473 WaitForCmd();
2474 if (result->GetNumResults() > 0) {
2475 if (params) {
2476 result->CopyResult(params);
2478 GPU_CLIENT_LOG_CODE_BLOCK({
2479 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
2480 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2483 return true;
2485 return false;
2488 void GLES2Implementation::GetActiveUniformBlockiv(
2489 GLuint program, GLuint index, GLenum pname, GLint* params) {
2490 GPU_CLIENT_SINGLE_THREAD_CHECK();
2491 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
2492 << program << ", " << index << ", "
2493 << GLES2Util::GetStringUniformBlockParameter(pname) << ", "
2494 << static_cast<const void*>(params) << ")");
2495 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
2496 bool success =
2497 share_group_->program_info_manager()->GetActiveUniformBlockiv(
2498 this, program, index, pname, params);
2499 if (success) {
2500 if (params) {
2501 // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
2502 // be more than one value returned in params.
2503 GPU_CLIENT_LOG(" params: " << params[0]);
2506 CheckGLError();
2509 bool GLES2Implementation::GetActiveUniformsivHelper(
2510 GLuint program, GLsizei count, const GLuint* indices,
2511 GLenum pname, GLint* params) {
2512 typedef cmds::GetActiveUniformsiv::Result Result;
2513 Result* result = GetResultAs<Result*>();
2514 if (!result) {
2515 return false;
2517 result->SetNumResults(0);
2518 base::CheckedNumeric<size_t> bytes = static_cast<size_t>(count);
2519 bytes *= sizeof(GLuint);
2520 if (!bytes.IsValid()) {
2521 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count overflow");
2522 return false;
2524 SetBucketContents(kResultBucketId, indices, bytes.ValueOrDefault(0));
2525 helper_->GetActiveUniformsiv(
2526 program, kResultBucketId, pname, GetResultShmId(), GetResultShmOffset());
2527 WaitForCmd();
2528 bool success = result->GetNumResults() == count;
2529 if (success) {
2530 if (params) {
2531 result->CopyResult(params);
2533 GPU_CLIENT_LOG_CODE_BLOCK({
2534 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
2535 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2539 helper_->SetBucketSize(kResultBucketId, 0);
2540 return success;
2543 void GLES2Implementation::GetActiveUniformsiv(
2544 GLuint program, GLsizei count, const GLuint* indices,
2545 GLenum pname, GLint* params) {
2546 GPU_CLIENT_SINGLE_THREAD_CHECK();
2547 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv("
2548 << program << ", " << count << ", "
2549 << static_cast<const void*>(indices) << ", "
2550 << GLES2Util::GetStringUniformParameter(pname) << ", "
2551 << static_cast<const void*>(params) << ")");
2552 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
2553 if (count < 0) {
2554 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count < 0");
2555 return;
2557 bool success = share_group_->program_info_manager()->GetActiveUniformsiv(
2558 this, program, count, indices, pname, params);
2559 if (success) {
2560 if (params) {
2561 GPU_CLIENT_LOG_CODE_BLOCK({
2562 for (GLsizei ii = 0; ii < count; ++ii) {
2563 GPU_CLIENT_LOG(" " << ii << ": " << params[ii]);
2568 CheckGLError();
2571 void GLES2Implementation::GetAttachedShaders(
2572 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
2573 GPU_CLIENT_SINGLE_THREAD_CHECK();
2574 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2575 << program << ", " << maxcount << ", "
2576 << static_cast<const void*>(count) << ", "
2577 << static_cast<const void*>(shaders) << ", ");
2578 if (maxcount < 0) {
2579 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
2580 return;
2582 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2583 typedef cmds::GetAttachedShaders::Result Result;
2584 uint32 size = Result::ComputeSize(maxcount);
2585 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
2586 if (!result) {
2587 return;
2589 result->SetNumResults(0);
2590 helper_->GetAttachedShaders(
2591 program,
2592 transfer_buffer_->GetShmId(),
2593 transfer_buffer_->GetOffset(result),
2594 size);
2595 int32 token = helper_->InsertToken();
2596 WaitForCmd();
2597 if (count) {
2598 *count = result->GetNumResults();
2600 result->CopyResult(shaders);
2601 GPU_CLIENT_LOG_CODE_BLOCK({
2602 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2603 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2606 transfer_buffer_->FreePendingToken(result, token);
2607 CheckGLError();
2610 void GLES2Implementation::GetShaderPrecisionFormat(
2611 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
2612 GPU_CLIENT_SINGLE_THREAD_CHECK();
2613 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2614 << GLES2Util::GetStringShaderType(shadertype) << ", "
2615 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
2616 << static_cast<const void*>(range) << ", "
2617 << static_cast<const void*>(precision) << ", ");
2618 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2619 typedef cmds::GetShaderPrecisionFormat::Result Result;
2620 Result* result = GetResultAs<Result*>();
2621 if (!result) {
2622 return;
2625 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
2626 GLStaticState::ShaderPrecisionMap::iterator i =
2627 static_state_.shader_precisions.find(key);
2628 if (i != static_state_.shader_precisions.end()) {
2629 *result = i->second;
2630 } else {
2631 result->success = false;
2632 helper_->GetShaderPrecisionFormat(
2633 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
2634 WaitForCmd();
2635 if (result->success)
2636 static_state_.shader_precisions[key] = *result;
2639 if (result->success) {
2640 if (range) {
2641 range[0] = result->min_range;
2642 range[1] = result->max_range;
2643 GPU_CLIENT_LOG(" min_range: " << range[0]);
2644 GPU_CLIENT_LOG(" min_range: " << range[1]);
2646 if (precision) {
2647 precision[0] = result->precision;
2648 GPU_CLIENT_LOG(" min_range: " << precision[0]);
2651 CheckGLError();
2654 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
2655 const char* result = NULL;
2656 // Clears the bucket so if the command fails nothing will be in it.
2657 helper_->SetBucketSize(kResultBucketId, 0);
2658 helper_->GetString(name, kResultBucketId);
2659 std::string str;
2660 if (GetBucketAsString(kResultBucketId, &str)) {
2661 // Adds extensions implemented on client side only.
2662 switch (name) {
2663 case GL_EXTENSIONS:
2664 str += std::string(str.empty() ? "" : " ") +
2665 "GL_CHROMIUM_flipy "
2666 "GL_EXT_unpack_subimage "
2667 "GL_CHROMIUM_map_sub";
2668 if (capabilities_.image)
2669 str += " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
2670 if (capabilities_.future_sync_points)
2671 str += " GL_CHROMIUM_future_sync_point";
2672 break;
2673 default:
2674 break;
2677 // Because of WebGL the extensions can change. We have to cache each unique
2678 // result since we don't know when the client will stop referring to a
2679 // previous one it queries.
2680 GLStringMap::iterator it = gl_strings_.find(name);
2681 if (it == gl_strings_.end()) {
2682 std::set<std::string> strings;
2683 std::pair<GLStringMap::iterator, bool> insert_result =
2684 gl_strings_.insert(std::make_pair(name, strings));
2685 DCHECK(insert_result.second);
2686 it = insert_result.first;
2688 std::set<std::string>& string_set = it->second;
2689 std::set<std::string>::const_iterator sit = string_set.find(str);
2690 if (sit != string_set.end()) {
2691 result = sit->c_str();
2692 } else {
2693 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2694 string_set.insert(str);
2695 DCHECK(insert_result.second);
2696 result = insert_result.first->c_str();
2699 return reinterpret_cast<const GLubyte*>(result);
2702 const GLubyte* GLES2Implementation::GetString(GLenum name) {
2703 GPU_CLIENT_SINGLE_THREAD_CHECK();
2704 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2705 << GLES2Util::GetStringStringType(name) << ")");
2706 TRACE_EVENT0("gpu", "GLES2::GetString");
2707 const GLubyte* result = GetStringHelper(name);
2708 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
2709 CheckGLError();
2710 return result;
2713 bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
2714 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2715 GLenum* type, char* name) {
2716 // Clear the bucket so if the command fails nothing will be in it.
2717 helper_->SetBucketSize(kResultBucketId, 0);
2718 typedef cmds::GetTransformFeedbackVarying::Result Result;
2719 Result* result = GetResultAs<Result*>();
2720 if (!result) {
2721 return false;
2723 // Set as failed so if the command fails we'll recover.
2724 result->success = false;
2725 helper_->GetTransformFeedbackVarying(
2726 program, index, kResultBucketId, GetResultShmId(), GetResultShmOffset());
2727 WaitForCmd();
2728 if (result->success) {
2729 if (size) {
2730 *size = result->size;
2732 if (type) {
2733 *type = result->type;
2735 if (length || name) {
2736 std::vector<int8> str;
2737 GetBucketContents(kResultBucketId, &str);
2738 GLsizei max_size = std::min(bufsize, static_cast<GLsizei>(str.size()));
2739 if (max_size > 0) {
2740 --max_size;
2742 if (length) {
2743 *length = max_size;
2745 if (name) {
2746 if (max_size > 0) {
2747 memcpy(name, &str[0], max_size);
2748 name[max_size] = '\0';
2749 } else if (bufsize > 0) {
2750 name[0] = '\0';
2755 return result->success != 0;
2758 void GLES2Implementation::GetTransformFeedbackVarying(
2759 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2760 GLenum* type, char* name) {
2761 GPU_CLIENT_SINGLE_THREAD_CHECK();
2762 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
2763 << program << ", " << index << ", " << bufsize << ", "
2764 << static_cast<const void*>(length) << ", "
2765 << static_cast<const void*>(size) << ", "
2766 << static_cast<const void*>(type) << ", "
2767 << static_cast<const void*>(name) << ", ");
2768 if (bufsize < 0) {
2769 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVarying",
2770 "bufsize < 0");
2771 return;
2773 TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
2774 bool success =
2775 share_group_->program_info_manager()->GetTransformFeedbackVarying(
2776 this, program, index, bufsize, length, size, type, name);
2777 if (success) {
2778 if (size) {
2779 GPU_CLIENT_LOG(" size: " << *size);
2781 if (type) {
2782 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2784 if (name) {
2785 GPU_CLIENT_LOG(" name: " << name);
2788 CheckGLError();
2791 void GLES2Implementation::GetUniformfv(
2792 GLuint program, GLint location, GLfloat* params) {
2793 GPU_CLIENT_SINGLE_THREAD_CHECK();
2794 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2795 << program << ", " << location << ", "
2796 << static_cast<const void*>(params) << ")");
2797 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2798 typedef cmds::GetUniformfv::Result Result;
2799 Result* result = GetResultAs<Result*>();
2800 if (!result) {
2801 return;
2803 result->SetNumResults(0);
2804 helper_->GetUniformfv(
2805 program, location, GetResultShmId(), GetResultShmOffset());
2806 WaitForCmd();
2807 result->CopyResult(params);
2808 GPU_CLIENT_LOG_CODE_BLOCK({
2809 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2810 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2813 CheckGLError();
2816 void GLES2Implementation::GetUniformiv(
2817 GLuint program, GLint location, GLint* params) {
2818 GPU_CLIENT_SINGLE_THREAD_CHECK();
2819 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2820 << program << ", " << location << ", "
2821 << static_cast<const void*>(params) << ")");
2822 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2823 typedef cmds::GetUniformiv::Result Result;
2824 Result* result = GetResultAs<Result*>();
2825 if (!result) {
2826 return;
2828 result->SetNumResults(0);
2829 helper_->GetUniformiv(
2830 program, location, GetResultShmId(), GetResultShmOffset());
2831 WaitForCmd();
2832 GetResultAs<cmds::GetUniformfv::Result*>()->CopyResult(params);
2833 GPU_CLIENT_LOG_CODE_BLOCK({
2834 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2835 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2838 CheckGLError();
2841 void GLES2Implementation::ReadPixels(
2842 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
2843 GLenum type, void* pixels) {
2844 GPU_CLIENT_SINGLE_THREAD_CHECK();
2845 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2846 << xoffset << ", " << yoffset << ", "
2847 << width << ", " << height << ", "
2848 << GLES2Util::GetStringReadPixelFormat(format) << ", "
2849 << GLES2Util::GetStringPixelType(type) << ", "
2850 << static_cast<const void*>(pixels) << ")");
2851 if (width < 0 || height < 0) {
2852 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
2853 return;
2855 if (width == 0 || height == 0) {
2856 return;
2859 // glReadPixel pads the size of each row of pixels by an amount specified by
2860 // glPixelStorei. So, we have to take that into account both in the fact that
2861 // the pixels returned from the ReadPixel command will include that padding
2862 // and that when we copy the results to the user's buffer we need to not
2863 // write those padding bytes but leave them as they are.
2865 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2866 typedef cmds::ReadPixels::Result Result;
2868 int8* dest = reinterpret_cast<int8*>(pixels);
2869 uint32 temp_size;
2870 uint32 unpadded_row_size;
2871 uint32 padded_row_size;
2872 if (!GLES2Util::ComputeImageDataSizes(
2873 width, 2, 1, format, type, pack_alignment_, &temp_size,
2874 &unpadded_row_size, &padded_row_size)) {
2875 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
2876 return;
2879 if (bound_pixel_pack_transfer_buffer_id_) {
2880 GLuint offset = ToGLuint(pixels);
2881 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2882 bound_pixel_pack_transfer_buffer_id_,
2883 "glReadPixels", offset, padded_row_size * height);
2884 if (buffer && buffer->shm_id() != -1) {
2885 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
2886 buffer->shm_id(), buffer->shm_offset(),
2887 0, 0, true);
2888 CheckGLError();
2890 return;
2893 if (!pixels) {
2894 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
2895 return;
2898 // Transfer by rows.
2899 // The max rows we can transfer.
2900 while (height) {
2901 GLsizei desired_size = padded_row_size * (height - 1) + unpadded_row_size;
2902 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
2903 if (!buffer.valid()) {
2904 return;
2906 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2907 padded_row_size, unpadded_row_size, buffer.size(), height);
2908 num_rows = std::min(num_rows, height);
2909 // NOTE: We must look up the address of the result area AFTER allocation
2910 // of the transfer buffer since the transfer buffer may be reallocated.
2911 Result* result = GetResultAs<Result*>();
2912 if (!result) {
2913 return;
2915 *result = 0; // mark as failed.
2916 helper_->ReadPixels(
2917 xoffset, yoffset, width, num_rows, format, type,
2918 buffer.shm_id(), buffer.offset(),
2919 GetResultShmId(), GetResultShmOffset(),
2920 false);
2921 WaitForCmd();
2922 if (*result != 0) {
2923 // when doing a y-flip we have to iterate through top-to-bottom chunks
2924 // of the dst. The service side handles reversing the rows within a
2925 // chunk.
2926 int8* rows_dst;
2927 if (pack_reverse_row_order_) {
2928 rows_dst = dest + (height - num_rows) * padded_row_size;
2929 } else {
2930 rows_dst = dest;
2932 // We have to copy 1 row at a time to avoid writing pad bytes.
2933 const int8* src = static_cast<const int8*>(buffer.address());
2934 for (GLint yy = 0; yy < num_rows; ++yy) {
2935 memcpy(rows_dst, src, unpadded_row_size);
2936 rows_dst += padded_row_size;
2937 src += padded_row_size;
2939 if (!pack_reverse_row_order_) {
2940 dest = rows_dst;
2943 // If it was not marked as successful exit.
2944 if (*result == 0) {
2945 return;
2947 yoffset += num_rows;
2948 height -= num_rows;
2950 CheckGLError();
2953 void GLES2Implementation::ActiveTexture(GLenum texture) {
2954 GPU_CLIENT_SINGLE_THREAD_CHECK();
2955 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2956 << GLES2Util::GetStringEnum(texture) << ")");
2957 GLuint texture_index = texture - GL_TEXTURE0;
2958 if (texture_index >=
2959 static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
2960 SetGLErrorInvalidEnum(
2961 "glActiveTexture", texture, "texture");
2962 return;
2965 active_texture_unit_ = texture_index;
2966 helper_->ActiveTexture(texture);
2967 CheckGLError();
2970 void GLES2Implementation::GenBuffersHelper(
2971 GLsizei /* n */, const GLuint* /* buffers */) {
2974 void GLES2Implementation::GenFramebuffersHelper(
2975 GLsizei /* n */, const GLuint* /* framebuffers */) {
2978 void GLES2Implementation::GenRenderbuffersHelper(
2979 GLsizei /* n */, const GLuint* /* renderbuffers */) {
2982 void GLES2Implementation::GenTexturesHelper(
2983 GLsizei /* n */, const GLuint* /* textures */) {
2986 void GLES2Implementation::GenVertexArraysOESHelper(
2987 GLsizei n, const GLuint* arrays) {
2988 vertex_array_object_manager_->GenVertexArrays(n, arrays);
2991 void GLES2Implementation::GenQueriesEXTHelper(
2992 GLsizei /* n */, const GLuint* /* queries */) {
2995 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
2996 GLsizei /* n */,
2997 const GLuint* /* valuebuffers */) {
3000 void GLES2Implementation::GenSamplersHelper(
3001 GLsizei /* n */, const GLuint* /* samplers */) {
3004 void GLES2Implementation::GenTransformFeedbacksHelper(
3005 GLsizei /* n */, const GLuint* /* transformfeedbacks */) {
3008 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
3009 // generates a new resource. On newer versions of OpenGL they don't. The code
3010 // related to binding below will need to change if we switch to the new OpenGL
3011 // model. Specifically it assumes a bind will succeed which is always true in
3012 // the old model but possibly not true in the new model if another context has
3013 // deleted the resource.
3015 // NOTE #2: There is a bug in some BindXXXHelpers, that IDs might be marked as
3016 // used even when Bind has failed. However, the bug is minor compared to the
3017 // overhead & duplicated checking in client side.
3019 void GLES2Implementation::BindBufferHelper(
3020 GLenum target, GLuint buffer_id) {
3021 // TODO(gman): See note #1 above.
3022 bool changed = false;
3023 switch (target) {
3024 case GL_ARRAY_BUFFER:
3025 if (bound_array_buffer_id_ != buffer_id) {
3026 bound_array_buffer_id_ = buffer_id;
3027 changed = true;
3029 break;
3030 case GL_ELEMENT_ARRAY_BUFFER:
3031 changed = vertex_array_object_manager_->BindElementArray(buffer_id);
3032 break;
3033 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3034 bound_pixel_pack_transfer_buffer_id_ = buffer_id;
3035 break;
3036 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3037 bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
3038 break;
3039 default:
3040 changed = true;
3041 break;
3043 // TODO(gman): See note #2 above.
3044 if (changed) {
3045 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3046 this, target, buffer_id, &GLES2Implementation::BindBufferStub);
3050 void GLES2Implementation::BindBufferStub(GLenum target, GLuint buffer) {
3051 helper_->BindBuffer(target, buffer);
3052 if (share_group_->bind_generates_resource())
3053 helper_->CommandBufferHelper::Flush();
3056 void GLES2Implementation::BindBufferBaseHelper(
3057 GLenum target, GLuint index, GLuint buffer_id) {
3058 // TODO(zmo): See note #1 above.
3059 // TODO(zmo): See note #2 above.
3060 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3061 this, target, index, buffer_id, &GLES2Implementation::BindBufferBaseStub);
3064 void GLES2Implementation::BindBufferBaseStub(
3065 GLenum target, GLuint index, GLuint buffer) {
3066 helper_->BindBufferBase(target, index, buffer);
3067 if (share_group_->bind_generates_resource())
3068 helper_->CommandBufferHelper::Flush();
3071 void GLES2Implementation::BindBufferRangeHelper(
3072 GLenum target, GLuint index, GLuint buffer_id,
3073 GLintptr offset, GLsizeiptr size) {
3074 // TODO(zmo): See note #1 above.
3075 // TODO(zmo): See note #2 above.
3076 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3077 this, target, index, buffer_id, offset, size,
3078 &GLES2Implementation::BindBufferRangeStub);
3081 void GLES2Implementation::BindBufferRangeStub(
3082 GLenum target, GLuint index, GLuint buffer,
3083 GLintptr offset, GLsizeiptr size) {
3084 helper_->BindBufferRange(target, index, buffer, offset, size);
3085 if (share_group_->bind_generates_resource())
3086 helper_->CommandBufferHelper::Flush();
3089 void GLES2Implementation::BindFramebufferHelper(
3090 GLenum target, GLuint framebuffer) {
3091 // TODO(gman): See note #1 above.
3092 bool changed = false;
3093 switch (target) {
3094 case GL_FRAMEBUFFER:
3095 if (bound_framebuffer_ != framebuffer ||
3096 bound_read_framebuffer_ != framebuffer) {
3097 bound_framebuffer_ = framebuffer;
3098 bound_read_framebuffer_ = framebuffer;
3099 changed = true;
3101 break;
3102 case GL_READ_FRAMEBUFFER:
3103 if (!IsChromiumFramebufferMultisampleAvailable()) {
3104 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3105 return;
3107 if (bound_read_framebuffer_ != framebuffer) {
3108 bound_read_framebuffer_ = framebuffer;
3109 changed = true;
3111 break;
3112 case GL_DRAW_FRAMEBUFFER:
3113 if (!IsChromiumFramebufferMultisampleAvailable()) {
3114 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3115 return;
3117 if (bound_framebuffer_ != framebuffer) {
3118 bound_framebuffer_ = framebuffer;
3119 changed = true;
3121 break;
3122 default:
3123 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3124 return;
3127 if (changed) {
3128 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(
3129 this, target, framebuffer, &GLES2Implementation::BindFramebufferStub);
3133 void GLES2Implementation::BindFramebufferStub(GLenum target,
3134 GLuint framebuffer) {
3135 helper_->BindFramebuffer(target, framebuffer);
3136 if (share_group_->bind_generates_resource())
3137 helper_->CommandBufferHelper::Flush();
3140 void GLES2Implementation::BindRenderbufferHelper(
3141 GLenum target, GLuint renderbuffer) {
3142 // TODO(gman): See note #1 above.
3143 bool changed = false;
3144 switch (target) {
3145 case GL_RENDERBUFFER:
3146 if (bound_renderbuffer_ != renderbuffer) {
3147 bound_renderbuffer_ = renderbuffer;
3148 changed = true;
3150 break;
3151 default:
3152 changed = true;
3153 break;
3155 // TODO(zmo): See note #2 above.
3156 if (changed) {
3157 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(
3158 this, target, renderbuffer,
3159 &GLES2Implementation::BindRenderbufferStub);
3163 void GLES2Implementation::BindRenderbufferStub(GLenum target,
3164 GLuint renderbuffer) {
3165 helper_->BindRenderbuffer(target, renderbuffer);
3166 if (share_group_->bind_generates_resource())
3167 helper_->CommandBufferHelper::Flush();
3170 void GLES2Implementation::BindSamplerHelper(GLuint unit,
3171 GLuint sampler) {
3172 helper_->BindSampler(unit, sampler);
3175 void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
3176 // TODO(gman): See note #1 above.
3177 // TODO(gman): Change this to false once we figure out why it's failing
3178 // on daisy.
3179 bool changed = true;
3180 TextureUnit& unit = texture_units_[active_texture_unit_];
3181 switch (target) {
3182 case GL_TEXTURE_2D:
3183 if (unit.bound_texture_2d != texture) {
3184 unit.bound_texture_2d = texture;
3185 changed = true;
3187 break;
3188 case GL_TEXTURE_CUBE_MAP:
3189 if (unit.bound_texture_cube_map != texture) {
3190 unit.bound_texture_cube_map = texture;
3191 changed = true;
3193 break;
3194 case GL_TEXTURE_EXTERNAL_OES:
3195 if (unit.bound_texture_external_oes != texture) {
3196 unit.bound_texture_external_oes = texture;
3197 changed = true;
3199 break;
3200 default:
3201 changed = true;
3202 break;
3204 // TODO(gman): See note #2 above.
3205 if (changed) {
3206 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(
3207 this, target, texture, &GLES2Implementation::BindTextureStub);
3211 void GLES2Implementation::BindTextureStub(GLenum target, GLuint texture) {
3212 helper_->BindTexture(target, texture);
3213 if (share_group_->bind_generates_resource())
3214 helper_->CommandBufferHelper::Flush();
3217 void GLES2Implementation::BindTransformFeedbackHelper(
3218 GLenum target, GLuint transformfeedback) {
3219 helper_->BindTransformFeedback(target, transformfeedback);
3222 void GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
3223 bool changed = false;
3224 if (vertex_array_object_manager_->BindVertexArray(array, &changed)) {
3225 if (changed) {
3226 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
3227 // because unlike other resources VertexArrayObject ids must
3228 // be generated by GenVertexArrays. A random id to Bind will not
3229 // generate a new object.
3230 helper_->BindVertexArrayOES(array);
3232 } else {
3233 SetGLError(
3234 GL_INVALID_OPERATION, "glBindVertexArrayOES",
3235 "id was not generated with glGenVertexArrayOES");
3239 void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
3240 GLuint valuebuffer) {
3241 bool changed = false;
3242 switch (target) {
3243 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
3244 if (bound_valuebuffer_ != valuebuffer) {
3245 bound_valuebuffer_ = valuebuffer;
3246 changed = true;
3248 break;
3249 default:
3250 changed = true;
3251 break;
3253 // TODO(gman): See note #2 above.
3254 if (changed) {
3255 GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(
3256 this, target, valuebuffer,
3257 &GLES2Implementation::BindValuebufferCHROMIUMStub);
3261 void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target,
3262 GLuint valuebuffer) {
3263 helper_->BindValuebufferCHROMIUM(target, valuebuffer);
3264 if (share_group_->bind_generates_resource())
3265 helper_->CommandBufferHelper::Flush();
3268 void GLES2Implementation::UseProgramHelper(GLuint program) {
3269 if (current_program_ != program) {
3270 current_program_ = program;
3271 helper_->UseProgram(program);
3275 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
3276 return vertex_array_object_manager_->IsReservedId(id);
3279 void GLES2Implementation::DeleteBuffersHelper(
3280 GLsizei n, const GLuint* buffers) {
3281 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
3282 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
3283 SetGLError(
3284 GL_INVALID_VALUE,
3285 "glDeleteBuffers", "id not created by this context.");
3286 return;
3288 for (GLsizei ii = 0; ii < n; ++ii) {
3289 if (buffers[ii] == bound_array_buffer_id_) {
3290 bound_array_buffer_id_ = 0;
3292 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
3294 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
3295 if (buffer)
3296 RemoveTransferBuffer(buffer);
3298 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
3299 bound_pixel_unpack_transfer_buffer_id_ = 0;
3302 RemoveMappedBufferRangeById(buffers[ii]);
3306 void GLES2Implementation::DeleteBuffersStub(
3307 GLsizei n, const GLuint* buffers) {
3308 helper_->DeleteBuffersImmediate(n, buffers);
3312 void GLES2Implementation::DeleteFramebuffersHelper(
3313 GLsizei n, const GLuint* framebuffers) {
3314 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
3315 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
3316 SetGLError(
3317 GL_INVALID_VALUE,
3318 "glDeleteFramebuffers", "id not created by this context.");
3319 return;
3321 for (GLsizei ii = 0; ii < n; ++ii) {
3322 if (framebuffers[ii] == bound_framebuffer_) {
3323 bound_framebuffer_ = 0;
3325 if (framebuffers[ii] == bound_read_framebuffer_) {
3326 bound_read_framebuffer_ = 0;
3331 void GLES2Implementation::DeleteFramebuffersStub(
3332 GLsizei n, const GLuint* framebuffers) {
3333 helper_->DeleteFramebuffersImmediate(n, framebuffers);
3336 void GLES2Implementation::DeleteRenderbuffersHelper(
3337 GLsizei n, const GLuint* renderbuffers) {
3338 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
3339 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
3340 SetGLError(
3341 GL_INVALID_VALUE,
3342 "glDeleteRenderbuffers", "id not created by this context.");
3343 return;
3345 for (GLsizei ii = 0; ii < n; ++ii) {
3346 if (renderbuffers[ii] == bound_renderbuffer_) {
3347 bound_renderbuffer_ = 0;
3352 void GLES2Implementation::DeleteRenderbuffersStub(
3353 GLsizei n, const GLuint* renderbuffers) {
3354 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
3357 void GLES2Implementation::DeleteTexturesHelper(
3358 GLsizei n, const GLuint* textures) {
3359 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
3360 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
3361 SetGLError(
3362 GL_INVALID_VALUE,
3363 "glDeleteTextures", "id not created by this context.");
3364 return;
3366 for (GLsizei ii = 0; ii < n; ++ii) {
3367 for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
3368 ++tt) {
3369 TextureUnit& unit = texture_units_[tt];
3370 if (textures[ii] == unit.bound_texture_2d) {
3371 unit.bound_texture_2d = 0;
3373 if (textures[ii] == unit.bound_texture_cube_map) {
3374 unit.bound_texture_cube_map = 0;
3376 if (textures[ii] == unit.bound_texture_external_oes) {
3377 unit.bound_texture_external_oes = 0;
3383 void GLES2Implementation::DeleteTexturesStub(GLsizei n,
3384 const GLuint* textures) {
3385 helper_->DeleteTexturesImmediate(n, textures);
3388 void GLES2Implementation::DeleteVertexArraysOESHelper(
3389 GLsizei n, const GLuint* arrays) {
3390 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
3391 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
3392 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
3393 SetGLError(
3394 GL_INVALID_VALUE,
3395 "glDeleteVertexArraysOES", "id not created by this context.");
3396 return;
3400 void GLES2Implementation::DeleteVertexArraysOESStub(
3401 GLsizei n, const GLuint* arrays) {
3402 helper_->DeleteVertexArraysOESImmediate(n, arrays);
3405 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
3406 GLsizei n,
3407 const GLuint* valuebuffers) {
3408 if (!GetIdHandler(id_namespaces::kValuebuffers)
3409 ->FreeIds(this, n, valuebuffers,
3410 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
3411 SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
3412 "id not created by this context.");
3413 return;
3415 for (GLsizei ii = 0; ii < n; ++ii) {
3416 if (valuebuffers[ii] == bound_valuebuffer_) {
3417 bound_valuebuffer_ = 0;
3422 void GLES2Implementation::DeleteSamplersStub(
3423 GLsizei n, const GLuint* samplers) {
3424 helper_->DeleteSamplersImmediate(n, samplers);
3427 void GLES2Implementation::DeleteSamplersHelper(
3428 GLsizei n, const GLuint* samplers) {
3429 if (!GetIdHandler(id_namespaces::kSamplers)->FreeIds(
3430 this, n, samplers, &GLES2Implementation::DeleteSamplersStub)) {
3431 SetGLError(
3432 GL_INVALID_VALUE,
3433 "glDeleteSamplers", "id not created by this context.");
3434 return;
3438 void GLES2Implementation::DeleteTransformFeedbacksStub(
3439 GLsizei n, const GLuint* transformfeedbacks) {
3440 helper_->DeleteTransformFeedbacksImmediate(n, transformfeedbacks);
3443 void GLES2Implementation::DeleteTransformFeedbacksHelper(
3444 GLsizei n, const GLuint* transformfeedbacks) {
3445 if (!GetIdHandler(id_namespaces::kTransformFeedbacks)->FreeIds(
3446 this, n, transformfeedbacks,
3447 &GLES2Implementation::DeleteTransformFeedbacksStub)) {
3448 SetGLError(
3449 GL_INVALID_VALUE,
3450 "glDeleteTransformFeedbacks", "id not created by this context.");
3451 return;
3455 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
3456 GLsizei n,
3457 const GLuint* valuebuffers) {
3458 helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
3461 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
3462 GPU_CLIENT_SINGLE_THREAD_CHECK();
3463 GPU_CLIENT_LOG(
3464 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
3465 vertex_array_object_manager_->SetAttribEnable(index, false);
3466 helper_->DisableVertexAttribArray(index);
3467 CheckGLError();
3470 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
3471 GPU_CLIENT_SINGLE_THREAD_CHECK();
3472 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
3473 << index << ")");
3474 vertex_array_object_manager_->SetAttribEnable(index, true);
3475 helper_->EnableVertexAttribArray(index);
3476 CheckGLError();
3479 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
3480 GPU_CLIENT_SINGLE_THREAD_CHECK();
3481 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
3482 << GLES2Util::GetStringDrawMode(mode) << ", "
3483 << first << ", " << count << ")");
3484 if (count < 0) {
3485 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
3486 return;
3488 bool simulated = false;
3489 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
3490 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
3491 return;
3493 helper_->DrawArrays(mode, first, count);
3494 RestoreArrayBuffer(simulated);
3495 CheckGLError();
3498 void GLES2Implementation::GetVertexAttribfv(
3499 GLuint index, GLenum pname, GLfloat* params) {
3500 GPU_CLIENT_SINGLE_THREAD_CHECK();
3501 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
3502 << index << ", "
3503 << GLES2Util::GetStringVertexAttribute(pname) << ", "
3504 << static_cast<const void*>(params) << ")");
3505 uint32 value = 0;
3506 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
3507 *params = static_cast<float>(value);
3508 return;
3510 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
3511 typedef cmds::GetVertexAttribfv::Result Result;
3512 Result* result = GetResultAs<Result*>();
3513 if (!result) {
3514 return;
3516 result->SetNumResults(0);
3517 helper_->GetVertexAttribfv(
3518 index, pname, GetResultShmId(), GetResultShmOffset());
3519 WaitForCmd();
3520 result->CopyResult(params);
3521 GPU_CLIENT_LOG_CODE_BLOCK({
3522 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3523 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3526 CheckGLError();
3529 void GLES2Implementation::GetVertexAttribiv(
3530 GLuint index, GLenum pname, GLint* params) {
3531 GPU_CLIENT_SINGLE_THREAD_CHECK();
3532 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
3533 << index << ", "
3534 << GLES2Util::GetStringVertexAttribute(pname) << ", "
3535 << static_cast<const void*>(params) << ")");
3536 uint32 value = 0;
3537 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
3538 *params = value;
3539 return;
3541 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
3542 typedef cmds::GetVertexAttribiv::Result Result;
3543 Result* result = GetResultAs<Result*>();
3544 if (!result) {
3545 return;
3547 result->SetNumResults(0);
3548 helper_->GetVertexAttribiv(
3549 index, pname, GetResultShmId(), GetResultShmOffset());
3550 WaitForCmd();
3551 result->CopyResult(params);
3552 GPU_CLIENT_LOG_CODE_BLOCK({
3553 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3554 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3557 CheckGLError();
3560 void GLES2Implementation::Swap() {
3561 SwapBuffers();
3564 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
3565 PostSubBufferCHROMIUM(
3566 sub_buffer.x(), sub_buffer.y(), sub_buffer.width(), sub_buffer.height());
3569 static GLenum GetGLESOverlayTransform(gfx::OverlayTransform plane_transform) {
3570 switch (plane_transform) {
3571 case gfx::OVERLAY_TRANSFORM_INVALID:
3572 break;
3573 case gfx::OVERLAY_TRANSFORM_NONE:
3574 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
3575 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
3576 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM;
3577 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
3578 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM;
3579 case gfx::OVERLAY_TRANSFORM_ROTATE_90:
3580 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM;
3581 case gfx::OVERLAY_TRANSFORM_ROTATE_180:
3582 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM;
3583 case gfx::OVERLAY_TRANSFORM_ROTATE_270:
3584 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM;
3586 NOTREACHED();
3587 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
3590 void GLES2Implementation::ScheduleOverlayPlane(
3591 int plane_z_order,
3592 gfx::OverlayTransform plane_transform,
3593 unsigned overlay_texture_id,
3594 const gfx::Rect& display_bounds,
3595 const gfx::RectF& uv_rect) {
3596 ScheduleOverlayPlaneCHROMIUM(plane_z_order,
3597 GetGLESOverlayTransform(plane_transform),
3598 overlay_texture_id,
3599 display_bounds.x(),
3600 display_bounds.y(),
3601 display_bounds.width(),
3602 display_bounds.height(),
3603 uv_rect.x(),
3604 uv_rect.y(),
3605 uv_rect.width(),
3606 uv_rect.height());
3609 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
3610 const char* feature) {
3611 GPU_CLIENT_SINGLE_THREAD_CHECK();
3612 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
3613 << feature << ")");
3614 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
3615 typedef cmds::EnableFeatureCHROMIUM::Result Result;
3616 Result* result = GetResultAs<Result*>();
3617 if (!result) {
3618 return false;
3620 *result = 0;
3621 SetBucketAsCString(kResultBucketId, feature);
3622 helper_->EnableFeatureCHROMIUM(
3623 kResultBucketId, GetResultShmId(), GetResultShmOffset());
3624 WaitForCmd();
3625 helper_->SetBucketSize(kResultBucketId, 0);
3626 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
3627 return *result != 0;
3630 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
3631 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
3632 GPU_CLIENT_SINGLE_THREAD_CHECK();
3633 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
3634 << target << ", " << offset << ", " << size << ", "
3635 << GLES2Util::GetStringEnum(access) << ")");
3636 // NOTE: target is NOT checked because the service will check it
3637 // and we don't know what targets are valid.
3638 if (access != GL_WRITE_ONLY) {
3639 SetGLErrorInvalidEnum(
3640 "glMapBufferSubDataCHROMIUM", access, "access");
3641 return NULL;
3643 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
3644 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
3645 return NULL;
3648 int32 shm_id;
3649 unsigned int shm_offset;
3650 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
3651 if (!mem) {
3652 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
3653 return NULL;
3656 std::pair<MappedBufferMap::iterator, bool> result =
3657 mapped_buffers_.insert(std::make_pair(
3658 mem,
3659 MappedBuffer(
3660 access, shm_id, mem, shm_offset, target, offset, size)));
3661 DCHECK(result.second);
3662 GPU_CLIENT_LOG(" returned " << mem);
3663 return mem;
3666 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
3667 GPU_CLIENT_SINGLE_THREAD_CHECK();
3668 GPU_CLIENT_LOG(
3669 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
3670 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
3671 if (it == mapped_buffers_.end()) {
3672 SetGLError(
3673 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
3674 return;
3676 const MappedBuffer& mb = it->second;
3677 helper_->BufferSubData(
3678 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
3679 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
3680 mapped_buffers_.erase(it);
3681 CheckGLError();
3684 GLuint GLES2Implementation::GetBoundBufferHelper(GLenum target) {
3685 GLenum binding = GLES2Util::MapBufferTargetToBindingEnum(target);
3686 GLint id = 0;
3687 bool cached = GetHelper(binding, &id);
3688 DCHECK(cached);
3689 return static_cast<GLuint>(id);
3692 void GLES2Implementation::RemoveMappedBufferRangeByTarget(GLenum target) {
3693 GLuint buffer = GetBoundBufferHelper(target);
3694 RemoveMappedBufferRangeById(buffer);
3697 void GLES2Implementation::RemoveMappedBufferRangeById(GLuint buffer) {
3698 if (buffer > 0) {
3699 auto iter = mapped_buffer_range_map_.find(buffer);
3700 if (iter != mapped_buffer_range_map_.end() && iter->second.shm_memory) {
3701 mapped_memory_->FreePendingToken(
3702 iter->second.shm_memory, helper_->InsertToken());
3703 mapped_buffer_range_map_.erase(iter);
3708 void GLES2Implementation::ClearMappedBufferRangeMap() {
3709 for (auto& buffer_range : mapped_buffer_range_map_) {
3710 if (buffer_range.second.shm_memory) {
3711 mapped_memory_->FreePendingToken(
3712 buffer_range.second.shm_memory, helper_->InsertToken());
3715 mapped_buffer_range_map_.clear();
3718 void* GLES2Implementation::MapBufferRange(
3719 GLenum target, GLintptr offset, GLsizeiptr size, GLbitfield access) {
3720 GPU_CLIENT_SINGLE_THREAD_CHECK();
3721 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferRange("
3722 << GLES2Util::GetStringEnum(target) << ", " << offset << ", "
3723 << size << ", " << access << ")");
3724 if (!ValidateSize("glMapBufferRange", size) ||
3725 !ValidateOffset("glMapBufferRange", offset)) {
3726 return nullptr;
3729 int32 shm_id;
3730 unsigned int shm_offset;
3731 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
3732 if (!mem) {
3733 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferRange", "out of memory");
3734 return nullptr;
3737 typedef cmds::MapBufferRange::Result Result;
3738 Result* result = GetResultAs<Result*>();
3739 *result = 0;
3740 helper_->MapBufferRange(target, offset, size, access, shm_id, shm_offset,
3741 GetResultShmId(), GetResultShmOffset());
3742 // TODO(zmo): For write only mode with MAP_INVALID_*_BIT, we should
3743 // consider an early return without WaitForCmd(). crbug.com/465804.
3744 WaitForCmd();
3745 if (*result) {
3746 const GLbitfield kInvalidateBits =
3747 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
3748 if ((access & kInvalidateBits) != 0) {
3749 // We do not read back from the buffer, therefore, we set the client
3750 // side memory to zero to avoid uninitialized data.
3751 memset(mem, 0, size);
3753 GLuint buffer = GetBoundBufferHelper(target);
3754 DCHECK_NE(0u, buffer);
3755 // glMapBufferRange fails on an already mapped buffer.
3756 DCHECK(mapped_buffer_range_map_.find(buffer) ==
3757 mapped_buffer_range_map_.end());
3758 auto iter = mapped_buffer_range_map_.insert(std::make_pair(
3759 buffer,
3760 MappedBuffer(access, shm_id, mem, shm_offset, target, offset, size)));
3761 DCHECK(iter.second);
3762 } else {
3763 mapped_memory_->Free(mem);
3764 mem = nullptr;
3767 GPU_CLIENT_LOG(" returned " << mem);
3768 CheckGLError();
3769 return mem;
3772 GLboolean GLES2Implementation::UnmapBuffer(GLenum target) {
3773 GPU_CLIENT_SINGLE_THREAD_CHECK();
3774 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapBuffer("
3775 << GLES2Util::GetStringEnum(target) << ")");
3776 switch (target) {
3777 case GL_ARRAY_BUFFER:
3778 case GL_ELEMENT_ARRAY_BUFFER:
3779 case GL_COPY_READ_BUFFER:
3780 case GL_COPY_WRITE_BUFFER:
3781 case GL_PIXEL_PACK_BUFFER:
3782 case GL_PIXEL_UNPACK_BUFFER:
3783 case GL_TRANSFORM_FEEDBACK_BUFFER:
3784 case GL_UNIFORM_BUFFER:
3785 break;
3786 default:
3787 SetGLError(GL_INVALID_ENUM, "glUnmapBuffer", "invalid target");
3788 return GL_FALSE;
3790 GLuint buffer = GetBoundBufferHelper(target);
3791 if (buffer == 0) {
3792 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "no buffer bound");
3793 return GL_FALSE;
3795 auto iter = mapped_buffer_range_map_.find(buffer);
3796 if (iter == mapped_buffer_range_map_.end()) {
3797 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "buffer is unmapped");
3798 return GL_FALSE;
3801 helper_->UnmapBuffer(target);
3802 RemoveMappedBufferRangeById(buffer);
3803 // TODO(zmo): There is a rare situation that data might be corrupted and
3804 // GL_FALSE should be returned. We lose context on that sitatuon, so we
3805 // don't have to WaitForCmd().
3806 GPU_CLIENT_LOG(" returned " << GL_TRUE);
3807 CheckGLError();
3808 return GL_TRUE;
3811 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
3812 GLenum target,
3813 GLint level,
3814 GLint xoffset,
3815 GLint yoffset,
3816 GLsizei width,
3817 GLsizei height,
3818 GLenum format,
3819 GLenum type,
3820 GLenum access) {
3821 GPU_CLIENT_SINGLE_THREAD_CHECK();
3822 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
3823 << target << ", " << level << ", "
3824 << xoffset << ", " << yoffset << ", "
3825 << width << ", " << height << ", "
3826 << GLES2Util::GetStringTextureFormat(format) << ", "
3827 << GLES2Util::GetStringPixelType(type) << ", "
3828 << GLES2Util::GetStringEnum(access) << ")");
3829 if (access != GL_WRITE_ONLY) {
3830 SetGLErrorInvalidEnum(
3831 "glMapTexSubImage2DCHROMIUM", access, "access");
3832 return NULL;
3834 // NOTE: target is NOT checked because the service will check it
3835 // and we don't know what targets are valid.
3836 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
3837 SetGLError(
3838 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
3839 return NULL;
3841 uint32 size;
3842 if (!GLES2Util::ComputeImageDataSizes(
3843 width, height, 1, format, type, unpack_alignment_, &size, NULL, NULL)) {
3844 SetGLError(
3845 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
3846 return NULL;
3848 int32 shm_id;
3849 unsigned int shm_offset;
3850 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
3851 if (!mem) {
3852 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
3853 return NULL;
3856 std::pair<MappedTextureMap::iterator, bool> result =
3857 mapped_textures_.insert(std::make_pair(
3858 mem,
3859 MappedTexture(
3860 access, shm_id, mem, shm_offset,
3861 target, level, xoffset, yoffset, width, height, format, type)));
3862 DCHECK(result.second);
3863 GPU_CLIENT_LOG(" returned " << mem);
3864 return mem;
3867 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
3868 GPU_CLIENT_SINGLE_THREAD_CHECK();
3869 GPU_CLIENT_LOG(
3870 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
3871 MappedTextureMap::iterator it = mapped_textures_.find(mem);
3872 if (it == mapped_textures_.end()) {
3873 SetGLError(
3874 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
3875 return;
3877 const MappedTexture& mt = it->second;
3878 helper_->TexSubImage2D(
3879 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
3880 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
3881 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
3882 mapped_textures_.erase(it);
3883 CheckGLError();
3886 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
3887 float scale_factor) {
3888 GPU_CLIENT_SINGLE_THREAD_CHECK();
3889 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
3890 << width << ", " << height << ", " << scale_factor << ")");
3891 helper_->ResizeCHROMIUM(width, height, scale_factor);
3892 CheckGLError();
3895 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
3896 GPU_CLIENT_SINGLE_THREAD_CHECK();
3897 GPU_CLIENT_LOG("[" << GetLogPrefix()
3898 << "] glGetRequestableExtensionsCHROMIUM()");
3899 TRACE_EVENT0("gpu",
3900 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
3901 const char* result = NULL;
3902 // Clear the bucket so if the command fails nothing will be in it.
3903 helper_->SetBucketSize(kResultBucketId, 0);
3904 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
3905 std::string str;
3906 if (GetBucketAsString(kResultBucketId, &str)) {
3907 // The set of requestable extensions shrinks as we enable
3908 // them. Because we don't know when the client will stop referring
3909 // to a previous one it queries (see GetString) we need to cache
3910 // the unique results.
3911 std::set<std::string>::const_iterator sit =
3912 requestable_extensions_set_.find(str);
3913 if (sit != requestable_extensions_set_.end()) {
3914 result = sit->c_str();
3915 } else {
3916 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
3917 requestable_extensions_set_.insert(str);
3918 DCHECK(insert_result.second);
3919 result = insert_result.first->c_str();
3922 GPU_CLIENT_LOG(" returned " << result);
3923 return reinterpret_cast<const GLchar*>(result);
3926 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
3927 // with VirtualGL contexts.
3928 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
3929 GPU_CLIENT_SINGLE_THREAD_CHECK();
3930 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
3931 << extension << ")");
3932 SetBucketAsCString(kResultBucketId, extension);
3933 helper_->RequestExtensionCHROMIUM(kResultBucketId);
3934 helper_->SetBucketSize(kResultBucketId, 0);
3936 struct ExtensionCheck {
3937 const char* extension;
3938 ExtensionStatus* status;
3940 const ExtensionCheck checks[] = {
3942 "GL_ANGLE_pack_reverse_row_order",
3943 &angle_pack_reverse_row_order_status_,
3946 "GL_CHROMIUM_framebuffer_multisample",
3947 &chromium_framebuffer_multisample_,
3950 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
3951 for (size_t ii = 0; ii < kNumChecks; ++ii) {
3952 const ExtensionCheck& check = checks[ii];
3953 if (*check.status == kUnavailableExtensionStatus &&
3954 !strcmp(extension, check.extension)) {
3955 *check.status = kUnknownExtensionStatus;
3960 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
3961 GPU_CLIENT_SINGLE_THREAD_CHECK();
3962 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
3963 // Wait if this would add too many rate limit tokens.
3964 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
3965 helper_->WaitForToken(rate_limit_tokens_.front());
3966 rate_limit_tokens_.pop();
3968 rate_limit_tokens_.push(helper_->InsertToken());
3971 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3972 GLuint program, std::vector<int8>* result) {
3973 DCHECK(result);
3974 // Clear the bucket so if the command fails nothing will be in it.
3975 helper_->SetBucketSize(kResultBucketId, 0);
3976 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
3977 GetBucketContents(kResultBucketId, result);
3980 void GLES2Implementation::GetProgramInfoCHROMIUM(
3981 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3982 GPU_CLIENT_SINGLE_THREAD_CHECK();
3983 if (bufsize < 0) {
3984 SetGLError(
3985 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3986 return;
3988 if (size == NULL) {
3989 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
3990 return;
3992 // Make sure they've set size to 0 else the value will be undefined on
3993 // lost context.
3994 DCHECK_EQ(0, *size);
3995 std::vector<int8> result;
3996 GetProgramInfoCHROMIUMHelper(program, &result);
3997 if (result.empty()) {
3998 return;
4000 *size = result.size();
4001 if (!info) {
4002 return;
4004 if (static_cast<size_t>(bufsize) < result.size()) {
4005 SetGLError(GL_INVALID_OPERATION,
4006 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
4007 return;
4009 memcpy(info, &result[0], result.size());
4012 void GLES2Implementation::GetUniformBlocksCHROMIUMHelper(
4013 GLuint program, std::vector<int8>* result) {
4014 DCHECK(result);
4015 // Clear the bucket so if the command fails nothing will be in it.
4016 helper_->SetBucketSize(kResultBucketId, 0);
4017 helper_->GetUniformBlocksCHROMIUM(program, kResultBucketId);
4018 GetBucketContents(kResultBucketId, result);
4021 void GLES2Implementation::GetUniformBlocksCHROMIUM(
4022 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4023 GPU_CLIENT_SINGLE_THREAD_CHECK();
4024 if (bufsize < 0) {
4025 SetGLError(
4026 GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "bufsize less than 0.");
4027 return;
4029 if (size == NULL) {
4030 SetGLError(GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "size is null.");
4031 return;
4033 // Make sure they've set size to 0 else the value will be undefined on
4034 // lost context.
4035 DCHECK_EQ(0, *size);
4036 std::vector<int8> result;
4037 GetUniformBlocksCHROMIUMHelper(program, &result);
4038 if (result.empty()) {
4039 return;
4041 *size = result.size();
4042 if (!info) {
4043 return;
4045 if (static_cast<size_t>(bufsize) < result.size()) {
4046 SetGLError(GL_INVALID_OPERATION, "glGetUniformBlocksCHROMIUM",
4047 "bufsize is too small for result.");
4048 return;
4050 memcpy(info, &result[0], result.size());
4053 void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
4054 GLuint program, std::vector<int8>* result) {
4055 DCHECK(result);
4056 // Clear the bucket so if the command fails nothing will be in it.
4057 helper_->SetBucketSize(kResultBucketId, 0);
4058 helper_->GetUniformsES3CHROMIUM(program, kResultBucketId);
4059 GetBucketContents(kResultBucketId, result);
4062 void GLES2Implementation::GetUniformsES3CHROMIUM(
4063 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4064 GPU_CLIENT_SINGLE_THREAD_CHECK();
4065 if (bufsize < 0) {
4066 SetGLError(
4067 GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "bufsize less than 0.");
4068 return;
4070 if (size == NULL) {
4071 SetGLError(GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "size is null.");
4072 return;
4074 // Make sure they've set size to 0 else the value will be undefined on
4075 // lost context.
4076 DCHECK_EQ(0, *size);
4077 std::vector<int8> result;
4078 GetUniformsES3CHROMIUMHelper(program, &result);
4079 if (result.empty()) {
4080 return;
4082 *size = result.size();
4083 if (!info) {
4084 return;
4086 if (static_cast<size_t>(bufsize) < result.size()) {
4087 SetGLError(GL_INVALID_OPERATION,
4088 "glGetUniformsES3CHROMIUM", "bufsize is too small for result.");
4089 return;
4091 memcpy(info, &result[0], result.size());
4094 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
4095 GLuint program, std::vector<int8>* result) {
4096 DCHECK(result);
4097 // Clear the bucket so if the command fails nothing will be in it.
4098 helper_->SetBucketSize(kResultBucketId, 0);
4099 helper_->GetTransformFeedbackVaryingsCHROMIUM(program, kResultBucketId);
4100 GetBucketContents(kResultBucketId, result);
4103 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(
4104 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4105 GPU_CLIENT_SINGLE_THREAD_CHECK();
4106 if (bufsize < 0) {
4107 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4108 "bufsize less than 0.");
4109 return;
4111 if (size == NULL) {
4112 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4113 "size is null.");
4114 return;
4116 // Make sure they've set size to 0 else the value will be undefined on
4117 // lost context.
4118 DCHECK_EQ(0, *size);
4119 std::vector<int8> result;
4120 GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
4121 if (result.empty()) {
4122 return;
4124 *size = result.size();
4125 if (!info) {
4126 return;
4128 if (static_cast<size_t>(bufsize) < result.size()) {
4129 SetGLError(GL_INVALID_OPERATION, "glGetTransformFeedbackVaryingsCHROMIUM",
4130 "bufsize is too small for result.");
4131 return;
4133 memcpy(info, &result[0], result.size());
4136 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
4137 GPU_CLIENT_SINGLE_THREAD_CHECK();
4138 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
4139 << texture << ")");
4140 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
4141 helper_->CommandBufferHelper::Flush();
4142 return gpu_control_->CreateStreamTexture(texture);
4145 void GLES2Implementation::PostSubBufferCHROMIUM(
4146 GLint x, GLint y, GLint width, GLint height) {
4147 GPU_CLIENT_SINGLE_THREAD_CHECK();
4148 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
4149 << x << ", " << y << ", " << width << ", " << height << ")");
4150 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
4151 "width", width, "height", height);
4153 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
4154 swap_buffers_tokens_.push(helper_->InsertToken());
4155 helper_->PostSubBufferCHROMIUM(x, y, width, height);
4156 helper_->CommandBufferHelper::Flush();
4157 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
4158 helper_->WaitForToken(swap_buffers_tokens_.front());
4159 swap_buffers_tokens_.pop();
4163 void GLES2Implementation::DeleteQueriesEXTHelper(
4164 GLsizei n, const GLuint* queries) {
4165 for (GLsizei ii = 0; ii < n; ++ii) {
4166 query_tracker_->RemoveQuery(queries[ii]);
4167 query_id_allocator_->FreeID(queries[ii]);
4170 helper_->DeleteQueriesEXTImmediate(n, queries);
4173 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
4174 GPU_CLIENT_SINGLE_THREAD_CHECK();
4175 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
4177 // TODO(gman): To be spec compliant IDs from other contexts sharing
4178 // resources need to return true here even though you can't share
4179 // queries across contexts?
4180 return query_tracker_->GetQuery(id) != NULL;
4183 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
4184 GPU_CLIENT_SINGLE_THREAD_CHECK();
4185 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
4186 << GLES2Util::GetStringQueryTarget(target)
4187 << ", " << id << ")");
4189 // if any outstanding queries INV_OP
4190 QueryMap::iterator it = current_queries_.find(target);
4191 if (it != current_queries_.end()) {
4192 SetGLError(
4193 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
4194 return;
4197 // id = 0 INV_OP
4198 if (id == 0) {
4199 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
4200 return;
4203 // if not GENned INV_OPERATION
4204 if (!query_id_allocator_->InUse(id)) {
4205 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "invalid id");
4206 return;
4209 // if id does not have an object
4210 QueryTracker::Query* query = query_tracker_->GetQuery(id);
4211 if (!query) {
4212 query = query_tracker_->CreateQuery(id, target);
4213 if (!query) {
4214 SetGLError(GL_OUT_OF_MEMORY,
4215 "glBeginQueryEXT",
4216 "transfer buffer allocation failed");
4217 return;
4219 } else if (query->target() != target) {
4220 SetGLError(
4221 GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
4222 return;
4225 current_queries_[target] = query;
4227 query->Begin(this);
4228 CheckGLError();
4231 void GLES2Implementation::EndQueryEXT(GLenum target) {
4232 GPU_CLIENT_SINGLE_THREAD_CHECK();
4233 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
4234 << GLES2Util::GetStringQueryTarget(target) << ")");
4235 // Don't do anything if the context is lost.
4236 if (helper_->IsContextLost()) {
4237 return;
4240 QueryMap::iterator it = current_queries_.find(target);
4241 if (it == current_queries_.end()) {
4242 SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
4243 return;
4246 QueryTracker::Query* query = it->second;
4247 query->End(this);
4248 current_queries_.erase(it);
4249 CheckGLError();
4252 void GLES2Implementation::GetQueryivEXT(
4253 GLenum target, GLenum pname, GLint* params) {
4254 GPU_CLIENT_SINGLE_THREAD_CHECK();
4255 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
4256 << GLES2Util::GetStringQueryTarget(target) << ", "
4257 << GLES2Util::GetStringQueryParameter(pname) << ", "
4258 << static_cast<const void*>(params) << ")");
4260 if (pname != GL_CURRENT_QUERY_EXT) {
4261 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
4262 return;
4264 QueryMap::iterator it = current_queries_.find(target);
4265 if (it != current_queries_.end()) {
4266 QueryTracker::Query* query = it->second;
4267 *params = query->id();
4268 } else {
4269 *params = 0;
4271 GPU_CLIENT_LOG(" " << *params);
4272 CheckGLError();
4275 void GLES2Implementation::GetQueryObjectuivEXT(
4276 GLuint id, GLenum pname, GLuint* params) {
4277 GPU_CLIENT_SINGLE_THREAD_CHECK();
4278 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
4279 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
4280 << static_cast<const void*>(params) << ")");
4282 QueryTracker::Query* query = query_tracker_->GetQuery(id);
4283 if (!query) {
4284 SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
4285 return;
4288 QueryMap::iterator it = current_queries_.find(query->target());
4289 if (it != current_queries_.end()) {
4290 SetGLError(
4291 GL_INVALID_OPERATION,
4292 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
4293 return;
4296 if (query->NeverUsed()) {
4297 SetGLError(
4298 GL_INVALID_OPERATION,
4299 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
4300 return;
4303 switch (pname) {
4304 case GL_QUERY_RESULT_EXT:
4305 if (!query->CheckResultsAvailable(helper_)) {
4306 helper_->WaitForToken(query->token());
4307 if (!query->CheckResultsAvailable(helper_)) {
4308 FinishHelper();
4309 CHECK(query->CheckResultsAvailable(helper_));
4312 *params = query->GetResult();
4313 break;
4314 case GL_QUERY_RESULT_AVAILABLE_EXT:
4315 *params = query->CheckResultsAvailable(helper_);
4316 break;
4317 default:
4318 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
4319 break;
4321 GPU_CLIENT_LOG(" " << *params);
4322 CheckGLError();
4325 void GLES2Implementation::DrawArraysInstancedANGLE(
4326 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
4327 GPU_CLIENT_SINGLE_THREAD_CHECK();
4328 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
4329 << GLES2Util::GetStringDrawMode(mode) << ", "
4330 << first << ", " << count << ", " << primcount << ")");
4331 if (count < 0) {
4332 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
4333 return;
4335 if (primcount < 0) {
4336 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
4337 return;
4339 if (primcount == 0) {
4340 return;
4342 bool simulated = false;
4343 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
4344 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
4345 &simulated)) {
4346 return;
4348 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
4349 RestoreArrayBuffer(simulated);
4350 CheckGLError();
4353 void GLES2Implementation::DrawElementsInstancedANGLE(
4354 GLenum mode, GLsizei count, GLenum type, const void* indices,
4355 GLsizei primcount) {
4356 GPU_CLIENT_SINGLE_THREAD_CHECK();
4357 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
4358 << GLES2Util::GetStringDrawMode(mode) << ", "
4359 << count << ", "
4360 << GLES2Util::GetStringIndexType(type) << ", "
4361 << static_cast<const void*>(indices) << ", "
4362 << primcount << ")");
4363 if (count < 0) {
4364 SetGLError(GL_INVALID_VALUE,
4365 "glDrawElementsInstancedANGLE", "count less than 0.");
4366 return;
4368 if (count == 0) {
4369 return;
4371 if (primcount < 0) {
4372 SetGLError(GL_INVALID_VALUE,
4373 "glDrawElementsInstancedANGLE", "primcount < 0");
4374 return;
4376 if (primcount == 0) {
4377 return;
4379 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
4380 !ValidateOffset("glDrawElementsInstancedANGLE",
4381 reinterpret_cast<GLintptr>(indices))) {
4382 return;
4384 GLuint offset = 0;
4385 bool simulated = false;
4386 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
4387 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
4388 indices, &offset, &simulated)) {
4389 return;
4391 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
4392 RestoreElementAndArrayBuffers(simulated);
4393 CheckGLError();
4396 void GLES2Implementation::GenMailboxCHROMIUM(
4397 GLbyte* mailbox) {
4398 GPU_CLIENT_SINGLE_THREAD_CHECK();
4399 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
4400 << static_cast<const void*>(mailbox) << ")");
4401 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
4403 gpu::Mailbox result = gpu::Mailbox::Generate();
4404 memcpy(mailbox, result.name, sizeof(result.name));
4407 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target,
4408 const GLbyte* data) {
4409 GPU_CLIENT_SINGLE_THREAD_CHECK();
4410 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
4411 << static_cast<const void*>(data) << ")");
4412 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4413 DCHECK(mailbox.Verify()) << "ProduceTextureCHROMIUM was passed a "
4414 "mailbox that was not generated by "
4415 "GenMailboxCHROMIUM.";
4416 helper_->ProduceTextureCHROMIUMImmediate(target, data);
4417 CheckGLError();
4420 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
4421 GLuint texture, GLenum target, const GLbyte* data) {
4422 GPU_CLIENT_SINGLE_THREAD_CHECK();
4423 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
4424 << static_cast<const void*>(data) << ")");
4425 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4426 DCHECK(mailbox.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
4427 "mailbox that was not generated by "
4428 "GenMailboxCHROMIUM.";
4429 helper_->ProduceTextureDirectCHROMIUMImmediate(texture, target, data);
4430 CheckGLError();
4433 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target,
4434 const GLbyte* data) {
4435 GPU_CLIENT_SINGLE_THREAD_CHECK();
4436 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
4437 << static_cast<const void*>(data) << ")");
4438 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4439 DCHECK(mailbox.Verify()) << "ConsumeTextureCHROMIUM was passed a "
4440 "mailbox that was not generated by "
4441 "GenMailboxCHROMIUM.";
4442 helper_->ConsumeTextureCHROMIUMImmediate(target, data);
4443 CheckGLError();
4446 GLuint GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
4447 GLenum target, const GLbyte* data) {
4448 GPU_CLIENT_SINGLE_THREAD_CHECK();
4449 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
4450 << static_cast<const void*>(data) << ")");
4451 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
4452 DCHECK(mailbox.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
4453 "mailbox that was not generated by "
4454 "GenMailboxCHROMIUM.";
4455 GLuint client_id;
4456 GetIdHandler(id_namespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
4457 helper_->CreateAndConsumeTextureCHROMIUMImmediate(target,
4458 client_id, data);
4459 if (share_group_->bind_generates_resource())
4460 helper_->CommandBufferHelper::Flush();
4461 CheckGLError();
4462 return client_id;
4465 void GLES2Implementation::PushGroupMarkerEXT(
4466 GLsizei length, const GLchar* marker) {
4467 GPU_CLIENT_SINGLE_THREAD_CHECK();
4468 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
4469 << length << ", " << marker << ")");
4470 if (!marker) {
4471 marker = "";
4473 SetBucketAsString(
4474 kResultBucketId,
4475 (length ? std::string(marker, length) : std::string(marker)));
4476 helper_->PushGroupMarkerEXT(kResultBucketId);
4477 helper_->SetBucketSize(kResultBucketId, 0);
4478 debug_marker_manager_.PushGroup(
4479 length ? std::string(marker, length) : std::string(marker));
4482 void GLES2Implementation::InsertEventMarkerEXT(
4483 GLsizei length, const GLchar* marker) {
4484 GPU_CLIENT_SINGLE_THREAD_CHECK();
4485 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
4486 << length << ", " << marker << ")");
4487 if (!marker) {
4488 marker = "";
4490 SetBucketAsString(
4491 kResultBucketId,
4492 (length ? std::string(marker, length) : std::string(marker)));
4493 helper_->InsertEventMarkerEXT(kResultBucketId);
4494 helper_->SetBucketSize(kResultBucketId, 0);
4495 debug_marker_manager_.SetMarker(
4496 length ? std::string(marker, length) : std::string(marker));
4499 void GLES2Implementation::PopGroupMarkerEXT() {
4500 GPU_CLIENT_SINGLE_THREAD_CHECK();
4501 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
4502 helper_->PopGroupMarkerEXT();
4503 debug_marker_manager_.PopGroup();
4506 void GLES2Implementation::TraceBeginCHROMIUM(
4507 const char* category_name, const char* trace_name) {
4508 GPU_CLIENT_SINGLE_THREAD_CHECK();
4509 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
4510 << category_name << ", " << trace_name << ")");
4511 SetBucketAsCString(kResultBucketId, category_name);
4512 SetBucketAsCString(kResultBucketId + 1, trace_name);
4513 helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1);
4514 helper_->SetBucketSize(kResultBucketId, 0);
4515 helper_->SetBucketSize(kResultBucketId + 1, 0);
4516 current_trace_stack_++;
4519 void GLES2Implementation::TraceEndCHROMIUM() {
4520 GPU_CLIENT_SINGLE_THREAD_CHECK();
4521 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
4522 if (current_trace_stack_ == 0) {
4523 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
4524 "missing begin trace");
4525 return;
4527 helper_->TraceEndCHROMIUM();
4528 current_trace_stack_--;
4531 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
4532 GPU_CLIENT_SINGLE_THREAD_CHECK();
4533 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
4534 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
4535 switch (target) {
4536 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
4537 if (access != GL_READ_ONLY) {
4538 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
4539 return NULL;
4541 break;
4542 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
4543 if (access != GL_WRITE_ONLY) {
4544 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
4545 return NULL;
4547 break;
4548 default:
4549 SetGLError(
4550 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
4551 return NULL;
4553 GLuint buffer_id;
4554 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
4555 if (!buffer_id) {
4556 return NULL;
4558 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
4559 if (!buffer) {
4560 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
4561 return NULL;
4563 if (buffer->mapped()) {
4564 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
4565 return NULL;
4567 // Here we wait for previous transfer operations to be finished.
4568 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
4569 // with this method of synchronization. Until this is fixed,
4570 // MapBufferCHROMIUM will not block even if the transfer is not ready
4571 // for these calls.
4572 if (buffer->last_usage_token()) {
4573 helper_->WaitForToken(buffer->last_usage_token());
4574 buffer->set_last_usage_token(0);
4576 buffer->set_mapped(true);
4578 GPU_CLIENT_LOG(" returned " << buffer->address());
4579 CheckGLError();
4580 return buffer->address();
4583 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
4584 GPU_CLIENT_SINGLE_THREAD_CHECK();
4585 GPU_CLIENT_LOG(
4586 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
4587 GLuint buffer_id;
4588 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
4589 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
4591 if (!buffer_id) {
4592 return false;
4594 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
4595 if (!buffer) {
4596 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
4597 return false;
4599 if (!buffer->mapped()) {
4600 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
4601 return false;
4603 buffer->set_mapped(false);
4604 CheckGLError();
4605 return true;
4608 bool GLES2Implementation::EnsureAsyncUploadSync() {
4609 if (async_upload_sync_)
4610 return true;
4612 int32 shm_id;
4613 unsigned int shm_offset;
4614 void* mem = mapped_memory_->Alloc(sizeof(AsyncUploadSync),
4615 &shm_id,
4616 &shm_offset);
4617 if (!mem)
4618 return false;
4620 async_upload_sync_shm_id_ = shm_id;
4621 async_upload_sync_shm_offset_ = shm_offset;
4622 async_upload_sync_ = static_cast<AsyncUploadSync*>(mem);
4623 async_upload_sync_->Reset();
4625 return true;
4628 uint32 GLES2Implementation::NextAsyncUploadToken() {
4629 async_upload_token_++;
4630 if (async_upload_token_ == 0)
4631 async_upload_token_++;
4632 return async_upload_token_;
4635 void GLES2Implementation::PollAsyncUploads() {
4636 if (!async_upload_sync_)
4637 return;
4639 if (helper_->IsContextLost()) {
4640 DetachedAsyncUploadMemoryList::iterator it =
4641 detached_async_upload_memory_.begin();
4642 while (it != detached_async_upload_memory_.end()) {
4643 mapped_memory_->Free(it->first);
4644 it = detached_async_upload_memory_.erase(it);
4646 return;
4649 DetachedAsyncUploadMemoryList::iterator it =
4650 detached_async_upload_memory_.begin();
4651 while (it != detached_async_upload_memory_.end()) {
4652 if (HasAsyncUploadTokenPassed(it->second)) {
4653 mapped_memory_->Free(it->first);
4654 it = detached_async_upload_memory_.erase(it);
4655 } else {
4656 break;
4661 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
4662 // Free all completed unmanaged async uploads buffers.
4663 PollAsyncUploads();
4665 // Synchronously free rest of the unmanaged async upload buffers.
4666 if (!detached_async_upload_memory_.empty()) {
4667 WaitAllAsyncTexImage2DCHROMIUM();
4668 WaitForCmd();
4669 PollAsyncUploads();
4673 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
4674 GLenum target, GLint level, GLenum internalformat, GLsizei width,
4675 GLsizei height, GLint border, GLenum format, GLenum type,
4676 const void* pixels) {
4677 GPU_CLIENT_SINGLE_THREAD_CHECK();
4678 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
4679 << GLES2Util::GetStringTextureTarget(target) << ", "
4680 << level << ", "
4681 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
4682 << width << ", " << height << ", " << border << ", "
4683 << GLES2Util::GetStringTextureFormat(format) << ", "
4684 << GLES2Util::GetStringPixelType(type) << ", "
4685 << static_cast<const void*>(pixels) << ")");
4686 if (level < 0 || height < 0 || width < 0) {
4687 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
4688 return;
4690 if (border != 0) {
4691 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
4692 return;
4694 uint32 size;
4695 uint32 unpadded_row_size;
4696 uint32 padded_row_size;
4697 if (!GLES2Util::ComputeImageDataSizes(
4698 width, height, 1, format, type, unpack_alignment_, &size,
4699 &unpadded_row_size, &padded_row_size)) {
4700 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
4701 return;
4704 // If there's no data/buffer just issue the AsyncTexImage2D
4705 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
4706 helper_->AsyncTexImage2DCHROMIUM(
4707 target, level, internalformat, width, height, format, type,
4708 0, 0, 0, 0, 0);
4709 return;
4712 if (!EnsureAsyncUploadSync()) {
4713 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
4714 return;
4717 // Otherwise, async uploads require a transfer buffer to be bound.
4718 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
4719 // the buffer before the transfer is finished. (Currently such
4720 // synchronization has to be handled manually.)
4721 GLuint offset = ToGLuint(pixels);
4722 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
4723 bound_pixel_unpack_transfer_buffer_id_,
4724 "glAsyncTexImage2DCHROMIUM", offset, size);
4725 if (buffer && buffer->shm_id() != -1) {
4726 uint32 async_token = NextAsyncUploadToken();
4727 buffer->set_last_async_upload_token(async_token);
4728 helper_->AsyncTexImage2DCHROMIUM(
4729 target, level, internalformat, width, height, format, type,
4730 buffer->shm_id(), buffer->shm_offset() + offset,
4731 async_token,
4732 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
4736 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
4737 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
4738 GLsizei height, GLenum format, GLenum type, const void* pixels) {
4739 GPU_CLIENT_SINGLE_THREAD_CHECK();
4740 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
4741 << GLES2Util::GetStringTextureTarget(target) << ", "
4742 << level << ", "
4743 << xoffset << ", " << yoffset << ", "
4744 << width << ", " << height << ", "
4745 << GLES2Util::GetStringTextureFormat(format) << ", "
4746 << GLES2Util::GetStringPixelType(type) << ", "
4747 << static_cast<const void*>(pixels) << ")");
4748 if (level < 0 || height < 0 || width < 0) {
4749 SetGLError(
4750 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
4751 return;
4754 uint32 size;
4755 uint32 unpadded_row_size;
4756 uint32 padded_row_size;
4757 if (!GLES2Util::ComputeImageDataSizes(
4758 width, height, 1, format, type, unpack_alignment_, &size,
4759 &unpadded_row_size, &padded_row_size)) {
4760 SetGLError(
4761 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
4762 return;
4765 if (!EnsureAsyncUploadSync()) {
4766 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
4767 return;
4770 // Async uploads require a transfer buffer to be bound.
4771 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
4772 // the buffer before the transfer is finished. (Currently such
4773 // synchronization has to be handled manually.)
4774 GLuint offset = ToGLuint(pixels);
4775 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
4776 bound_pixel_unpack_transfer_buffer_id_,
4777 "glAsyncTexSubImage2DCHROMIUM", offset, size);
4778 if (buffer && buffer->shm_id() != -1) {
4779 uint32 async_token = NextAsyncUploadToken();
4780 buffer->set_last_async_upload_token(async_token);
4781 helper_->AsyncTexSubImage2DCHROMIUM(
4782 target, level, xoffset, yoffset, width, height, format, type,
4783 buffer->shm_id(), buffer->shm_offset() + offset,
4784 async_token,
4785 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
4789 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
4790 GPU_CLIENT_SINGLE_THREAD_CHECK();
4791 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
4792 << GLES2Util::GetStringTextureTarget(target) << ")");
4793 helper_->WaitAsyncTexImage2DCHROMIUM(target);
4794 CheckGLError();
4797 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
4798 GPU_CLIENT_SINGLE_THREAD_CHECK();
4799 GPU_CLIENT_LOG("[" << GetLogPrefix()
4800 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
4801 helper_->WaitAllAsyncTexImage2DCHROMIUM();
4802 CheckGLError();
4805 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
4806 GPU_CLIENT_SINGLE_THREAD_CHECK();
4807 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
4808 helper_->CommandBufferHelper::Flush();
4809 return gpu_control_->InsertSyncPoint();
4812 GLuint GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
4813 GPU_CLIENT_SINGLE_THREAD_CHECK();
4814 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
4815 DCHECK(capabilities_.future_sync_points);
4816 return gpu_control_->InsertFutureSyncPoint();
4819 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point) {
4820 GPU_CLIENT_SINGLE_THREAD_CHECK();
4821 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
4822 << sync_point << ")");
4823 DCHECK(capabilities_.future_sync_points);
4824 helper_->CommandBufferHelper::Flush();
4825 gpu_control_->RetireSyncPoint(sync_point);
4828 namespace {
4830 bool ValidImageFormat(GLenum internalformat) {
4831 switch (internalformat) {
4832 case GL_RGB:
4833 case GL_RGBA:
4834 case GL_BGRA_EXT:
4835 return true;
4836 default:
4837 return false;
4841 bool ValidImageUsage(GLenum usage) {
4842 switch (usage) {
4843 case GL_MAP_CHROMIUM:
4844 case GL_SCANOUT_CHROMIUM:
4845 return true;
4846 default:
4847 return false;
4851 } // namespace
4853 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer,
4854 GLsizei width,
4855 GLsizei height,
4856 GLenum internalformat) {
4857 if (width <= 0) {
4858 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
4859 return 0;
4862 if (height <= 0) {
4863 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
4864 return 0;
4867 if (!ValidImageFormat(internalformat)) {
4868 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "invalid format");
4869 return 0;
4872 int32_t image_id =
4873 gpu_control_->CreateImage(buffer, width, height, internalformat);
4874 if (image_id < 0) {
4875 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "image_id < 0");
4876 return 0;
4878 return image_id;
4881 GLuint GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer,
4882 GLsizei width,
4883 GLsizei height,
4884 GLenum internalformat) {
4885 GPU_CLIENT_SINGLE_THREAD_CHECK();
4886 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
4887 << ", " << height << ", "
4888 << GLES2Util::GetStringImageInternalFormat(internalformat)
4889 << ")");
4890 GLuint image_id =
4891 CreateImageCHROMIUMHelper(buffer, width, height, internalformat);
4892 CheckGLError();
4893 return image_id;
4896 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
4897 // Flush the command stream to make sure all pending commands
4898 // that may refer to the image_id are executed on the service side.
4899 helper_->CommandBufferHelper::Flush();
4900 gpu_control_->DestroyImage(image_id);
4903 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
4904 GPU_CLIENT_SINGLE_THREAD_CHECK();
4905 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
4906 << image_id << ")");
4907 DestroyImageCHROMIUMHelper(image_id);
4908 CheckGLError();
4911 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
4912 GLsizei width,
4913 GLsizei height,
4914 GLenum internalformat,
4915 GLenum usage) {
4916 if (width <= 0) {
4917 SetGLError(
4918 GL_INVALID_VALUE, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
4919 return 0;
4922 if (height <= 0) {
4923 SetGLError(GL_INVALID_VALUE,
4924 "glCreateGpuMemoryBufferImageCHROMIUM",
4925 "height <= 0");
4926 return 0;
4929 if (!ValidImageFormat(internalformat)) {
4930 SetGLError(GL_INVALID_VALUE,
4931 "glCreateGpuMemoryBufferImageCHROMIUM",
4932 "invalid format");
4933 return 0;
4936 if (!ValidImageUsage(usage)) {
4937 SetGLError(GL_INVALID_VALUE,
4938 "glCreateGpuMemoryBufferImageCHROMIUM",
4939 "invalid usage");
4940 return 0;
4943 // Flush the command stream to ensure ordering in case the newly
4944 // returned image_id has recently been in use with a different buffer.
4945 helper_->CommandBufferHelper::Flush();
4946 int32_t image_id = gpu_control_->CreateGpuMemoryBufferImage(
4947 width, height, internalformat, usage);
4948 if (image_id < 0) {
4949 SetGLError(GL_OUT_OF_MEMORY,
4950 "glCreateGpuMemoryBufferImageCHROMIUM",
4951 "image_id < 0");
4952 return 0;
4954 return image_id;
4957 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
4958 GLsizei width,
4959 GLsizei height,
4960 GLenum internalformat,
4961 GLenum usage) {
4962 GPU_CLIENT_SINGLE_THREAD_CHECK();
4963 GPU_CLIENT_LOG("[" << GetLogPrefix()
4964 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
4965 << ", " << height << ", "
4966 << GLES2Util::GetStringImageInternalFormat(internalformat)
4967 << ", " << GLES2Util::GetStringImageUsage(usage) << ")");
4968 GLuint image_id = CreateGpuMemoryBufferImageCHROMIUMHelper(
4969 width, height, internalformat, usage);
4970 CheckGLError();
4971 return image_id;
4974 bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
4975 if (size < 0) {
4976 SetGLError(GL_INVALID_VALUE, func, "size < 0");
4977 return false;
4979 if (!base::IsValueInRangeForNumericType<int32_t>(size)) {
4980 SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
4981 return false;
4983 return true;
4986 bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
4987 if (offset < 0) {
4988 SetGLError(GL_INVALID_VALUE, func, "offset < 0");
4989 return false;
4991 if (!base::IsValueInRangeForNumericType<int32_t>(offset)) {
4992 SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
4993 return false;
4995 return true;
4998 bool GLES2Implementation::GetSamplerParameterfvHelper(
4999 GLuint /* sampler */, GLenum /* pname */, GLfloat* /* params */) {
5000 // TODO(zmo): Implement client side caching.
5001 return false;
5004 bool GLES2Implementation::GetSamplerParameterivHelper(
5005 GLuint /* sampler */, GLenum /* pname */, GLint* /* params */) {
5006 // TODO(zmo): Implement client side caching.
5007 return false;
5010 bool GLES2Implementation::PackStringsToBucket(GLsizei count,
5011 const char* const* str,
5012 const GLint* length,
5013 const char* func_name) {
5014 DCHECK_LE(0, count);
5015 // Compute the total size.
5016 base::CheckedNumeric<size_t> total_size = count;
5017 total_size += 1;
5018 total_size *= sizeof(GLint);
5019 if (!total_size.IsValid()) {
5020 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5021 return false;
5023 size_t header_size = total_size.ValueOrDefault(0);
5024 std::vector<GLint> header(count + 1);
5025 header[0] = static_cast<GLint>(count);
5026 for (GLsizei ii = 0; ii < count; ++ii) {
5027 GLint len = 0;
5028 if (str[ii]) {
5029 len = (length && length[ii] >= 0)
5030 ? length[ii]
5031 : base::checked_cast<GLint>(strlen(str[ii]));
5033 total_size += len;
5034 total_size += 1; // NULL at the end of each char array.
5035 if (!total_size.IsValid()) {
5036 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5037 return false;
5039 header[ii + 1] = len;
5041 // Pack data into a bucket on the service.
5042 helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
5043 size_t offset = 0;
5044 for (GLsizei ii = 0; ii <= count; ++ii) {
5045 const char* src =
5046 (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
5047 base::CheckedNumeric<size_t> checked_size =
5048 (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
5049 if (ii > 0) {
5050 checked_size += 1; // NULL in the end.
5052 if (!checked_size.IsValid()) {
5053 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5054 return false;
5056 size_t size = checked_size.ValueOrDefault(0);
5057 while (size) {
5058 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
5059 if (!buffer.valid() || buffer.size() == 0) {
5060 SetGLError(GL_OUT_OF_MEMORY, func_name, "too large");
5061 return false;
5063 size_t copy_size = buffer.size();
5064 if (ii > 0 && buffer.size() == size)
5065 --copy_size;
5066 if (copy_size)
5067 memcpy(buffer.address(), src, copy_size);
5068 if (copy_size < buffer.size()) {
5069 // Append NULL in the end.
5070 DCHECK(copy_size + 1 == buffer.size());
5071 char* str = reinterpret_cast<char*>(buffer.address());
5072 str[copy_size] = 0;
5074 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
5075 buffer.shm_id(), buffer.offset());
5076 offset += buffer.size();
5077 src += buffer.size();
5078 size -= buffer.size();
5081 DCHECK_EQ(total_size.ValueOrDefault(0), offset);
5082 return true;
5085 void GLES2Implementation::UniformBlockBinding(GLuint program,
5086 GLuint index,
5087 GLuint binding) {
5088 GPU_CLIENT_SINGLE_THREAD_CHECK();
5089 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
5090 << ", " << index << ", " << binding << ")");
5091 share_group_->program_info_manager()->UniformBlockBinding(
5092 this, program, index, binding);
5093 helper_->UniformBlockBinding(program, index, binding);
5094 CheckGLError();
5097 GLenum GLES2Implementation::ClientWaitSync(
5098 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5099 GPU_CLIENT_SINGLE_THREAD_CHECK();
5100 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync
5101 << ", " << flags << ", " << timeout << ")");
5102 typedef cmds::ClientWaitSync::Result Result;
5103 Result* result = GetResultAs<Result*>();
5104 if (!result) {
5105 SetGLError(GL_OUT_OF_MEMORY, "ClientWaitSync", "");
5106 return GL_WAIT_FAILED;
5108 *result = GL_WAIT_FAILED;
5109 uint32_t v32_0 = 0, v32_1 = 0;
5110 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5111 helper_->ClientWaitSync(
5112 ToGLuint(sync), flags, v32_0, v32_1,
5113 GetResultShmId(), GetResultShmOffset());
5114 WaitForCmd();
5115 GPU_CLIENT_LOG("returned " << *result);
5116 CheckGLError();
5117 return *result;
5120 void GLES2Implementation::WaitSync(
5121 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5122 GPU_CLIENT_SINGLE_THREAD_CHECK();
5123 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync << ", "
5124 << flags << ", " << timeout << ")");
5125 uint32_t v32_0 = 0, v32_1 = 0;
5126 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5127 helper_->WaitSync(ToGLuint(sync), flags, v32_0, v32_1);
5128 CheckGLError();
5131 // Include the auto-generated part of this file. We split this because it means
5132 // we can easily edit the non-auto generated parts right here in this file
5133 // instead of having to edit some template or the code generator.
5134 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
5136 } // namespace gles2
5137 } // namespace gpu