Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blob2bf603b0ca78a32f160d643680af840caa50440a
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/gl2.h>
10 #include <GLES2/gl2ext.h>
11 #include <GLES2/gl2extchromium.h>
12 #include <GLES3/gl3.h>
13 #include <algorithm>
14 #include <map>
15 #include <set>
16 #include <sstream>
17 #include <string>
18 #include "base/compiler_specific.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/thread_task_runner_handle.h"
21 #include "base/trace_event/memory_allocator_dump.h"
22 #include "base/trace_event/memory_dump_manager.h"
23 #include "base/trace_event/process_memory_dump.h"
24 #include "gpu/command_buffer/client/buffer_tracker.h"
25 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
26 #include "gpu/command_buffer/client/gpu_control.h"
27 #include "gpu/command_buffer/client/program_info_manager.h"
28 #include "gpu/command_buffer/client/query_tracker.h"
29 #include "gpu/command_buffer/client/transfer_buffer.h"
30 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
31 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
32 #include "gpu/command_buffer/common/id_allocator.h"
33 #include "gpu/command_buffer/common/trace_event.h"
34 #include "ui/gfx/geometry/rect.h"
35 #include "ui/gfx/geometry/rect_f.h"
37 #if defined(GPU_CLIENT_DEBUG)
38 #include "base/command_line.h"
39 #include "gpu/command_buffer/client/gpu_switches.h"
40 #endif
42 namespace gpu {
43 namespace gles2 {
45 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
46 static GLuint ToGLuint(const void* ptr) {
47 return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
50 #if !defined(_MSC_VER)
51 const size_t GLES2Implementation::kMaxSizeOfSimpleResult;
52 const unsigned int GLES2Implementation::kStartingOffset;
53 #endif
55 GLES2Implementation::GLStaticState::GLStaticState() {
58 GLES2Implementation::GLStaticState::~GLStaticState() {
61 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
62 GLES2Implementation* gles2_implementation)
63 : gles2_implementation_(gles2_implementation) {
64 CHECK_EQ(0, gles2_implementation_->use_count_);
65 ++gles2_implementation_->use_count_;
68 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
69 --gles2_implementation_->use_count_;
70 CHECK_EQ(0, gles2_implementation_->use_count_);
73 GLES2Implementation::GLES2Implementation(
74 GLES2CmdHelper* helper,
75 ShareGroup* share_group,
76 TransferBufferInterface* transfer_buffer,
77 bool bind_generates_resource,
78 bool lose_context_when_out_of_memory,
79 bool support_client_side_arrays,
80 GpuControl* gpu_control)
81 : helper_(helper),
82 transfer_buffer_(transfer_buffer),
83 angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
84 chromium_framebuffer_multisample_(kUnknownExtensionStatus),
85 pack_alignment_(4),
86 unpack_alignment_(4),
87 unpack_row_length_(0),
88 unpack_image_height_(0),
89 unpack_skip_rows_(0),
90 unpack_skip_pixels_(0),
91 unpack_skip_images_(0),
92 pack_reverse_row_order_(false),
93 active_texture_unit_(0),
94 bound_framebuffer_(0),
95 bound_read_framebuffer_(0),
96 bound_renderbuffer_(0),
97 bound_valuebuffer_(0),
98 current_program_(0),
99 bound_array_buffer_(0),
100 bound_copy_read_buffer_(0),
101 bound_copy_write_buffer_(0),
102 bound_pixel_pack_buffer_(0),
103 bound_pixel_unpack_buffer_(0),
104 bound_transform_feedback_buffer_(0),
105 bound_uniform_buffer_(0),
106 bound_pixel_pack_transfer_buffer_id_(0),
107 bound_pixel_unpack_transfer_buffer_id_(0),
108 error_bits_(0),
109 debug_(false),
110 lose_context_when_out_of_memory_(lose_context_when_out_of_memory),
111 support_client_side_arrays_(support_client_side_arrays),
112 use_count_(0),
113 error_message_callback_(NULL),
114 current_trace_stack_(0),
115 gpu_control_(gpu_control),
116 capabilities_(gpu_control->GetCapabilities()),
117 aggressively_free_resources_(false),
118 weak_ptr_factory_(this) {
119 DCHECK(helper);
120 DCHECK(transfer_buffer);
121 DCHECK(gpu_control);
123 std::stringstream ss;
124 ss << std::hex << this;
125 this_in_hex_ = ss.str();
127 GPU_CLIENT_LOG_CODE_BLOCK({
128 debug_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
129 switches::kEnableGPUClientLogging);
132 share_group_ =
133 (share_group ? share_group
134 : new ShareGroup(bind_generates_resource,
135 gpu_control_->GetCommandBufferID()));
136 DCHECK(share_group_->bind_generates_resource() == bind_generates_resource);
138 memset(&reserved_ids_, 0, sizeof(reserved_ids_));
141 bool GLES2Implementation::Initialize(
142 unsigned int starting_transfer_buffer_size,
143 unsigned int min_transfer_buffer_size,
144 unsigned int max_transfer_buffer_size,
145 unsigned int mapped_memory_limit) {
146 TRACE_EVENT0("gpu", "GLES2Implementation::Initialize");
147 DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
148 DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
149 DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
151 if (!transfer_buffer_->Initialize(
152 starting_transfer_buffer_size,
153 kStartingOffset,
154 min_transfer_buffer_size,
155 max_transfer_buffer_size,
156 kAlignment,
157 kSizeToFlush)) {
158 return false;
161 mapped_memory_.reset(new MappedMemoryManager(helper_, mapped_memory_limit));
163 unsigned chunk_size = 2 * 1024 * 1024;
164 if (mapped_memory_limit != kNoLimit) {
165 // Use smaller chunks if the client is very memory conscientious.
166 chunk_size = std::min(mapped_memory_limit / 4, chunk_size);
168 mapped_memory_->set_chunk_size_multiple(chunk_size);
170 GLStaticState::ShaderPrecisionMap* shader_precisions =
171 &static_state_.shader_precisions;
172 capabilities_.VisitPrecisions([shader_precisions](
173 GLenum shader, GLenum type, Capabilities::ShaderPrecision* result) {
174 const GLStaticState::ShaderPrecisionKey key(shader, type);
175 cmds::GetShaderPrecisionFormat::Result cached_result = {
176 true, result->min_range, result->max_range, result->precision};
177 shader_precisions->insert(std::make_pair(key, cached_result));
180 util_.set_num_compressed_texture_formats(
181 capabilities_.num_compressed_texture_formats);
182 util_.set_num_shader_binary_formats(capabilities_.num_shader_binary_formats);
184 texture_units_.reset(
185 new TextureUnit[capabilities_.max_combined_texture_image_units]);
187 query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
188 buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
190 query_id_allocator_.reset(new IdAllocator());
191 if (support_client_side_arrays_) {
192 GetIdHandler(id_namespaces::kBuffers)->MakeIds(
193 this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
196 vertex_array_object_manager_.reset(new VertexArrayObjectManager(
197 capabilities_.max_vertex_attribs, reserved_ids_[0], reserved_ids_[1],
198 support_client_side_arrays_));
200 // GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
201 // on Client & Service.
202 if (capabilities_.bind_generates_resource_chromium !=
203 (share_group_->bind_generates_resource() ? 1 : 0)) {
204 SetGLError(GL_INVALID_OPERATION,
205 "Initialize",
206 "Service bind_generates_resource mismatch.");
207 return false;
210 // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
211 // Don't register a dump provider in these cases.
212 // TODO(ericrk): Get this working in Android Webview. crbug.com/517156
213 if (base::ThreadTaskRunnerHandle::IsSet()) {
214 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
215 this, base::ThreadTaskRunnerHandle::Get());
218 return true;
221 GLES2Implementation::~GLES2Implementation() {
222 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
223 this);
225 // Make sure the queries are finished otherwise we'll delete the
226 // shared memory (mapped_memory_) which will free the memory used
227 // by the queries. The GPU process when validating that memory is still
228 // shared will fail and abort (ie, it will stop running).
229 WaitForCmd();
230 query_tracker_.reset();
232 // GLES2Implementation::Initialize() could fail before allocating
233 // reserved_ids_, so we need delete them carefully.
234 if (support_client_side_arrays_ && reserved_ids_[0]) {
235 DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
238 // Release remaining BufferRange mem; This is when a MapBufferRange() is
239 // called but not the UnmapBuffer() pair.
240 ClearMappedBufferRangeMap();
242 // Release any per-context data in share group.
243 share_group_->FreeContext(this);
245 buffer_tracker_.reset();
247 // Make sure the commands make it the service.
248 WaitForCmd();
251 GLES2CmdHelper* GLES2Implementation::helper() const {
252 return helper_;
255 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
256 return share_group_->GetIdHandler(namespace_id);
259 RangeIdHandlerInterface* GLES2Implementation::GetRangeIdHandler(
260 int namespace_id) const {
261 return share_group_->GetRangeIdHandler(namespace_id);
264 IdAllocator* GLES2Implementation::GetIdAllocator(int namespace_id) const {
265 if (namespace_id == id_namespaces::kQueries)
266 return query_id_allocator_.get();
267 NOTREACHED();
268 return NULL;
271 void* GLES2Implementation::GetResultBuffer() {
272 return transfer_buffer_->GetResultBuffer();
275 int32 GLES2Implementation::GetResultShmId() {
276 return transfer_buffer_->GetShmId();
279 uint32 GLES2Implementation::GetResultShmOffset() {
280 return transfer_buffer_->GetResultOffset();
283 void GLES2Implementation::FreeUnusedSharedMemory() {
284 mapped_memory_->FreeUnused();
287 void GLES2Implementation::FreeEverything() {
288 WaitForCmd();
289 query_tracker_->Shrink();
290 FreeUnusedSharedMemory();
291 transfer_buffer_->Free();
292 helper_->FreeRingBuffer();
295 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
296 if (!helper_->IsContextLost())
297 callback.Run();
300 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
301 const base::Closure& callback) {
302 gpu_control_->SignalSyncPoint(
303 sync_point,
304 base::Bind(&GLES2Implementation::RunIfContextNotLost,
305 weak_ptr_factory_.GetWeakPtr(),
306 callback));
309 void GLES2Implementation::SignalQuery(uint32 query,
310 const base::Closure& callback) {
311 // Flush previously entered commands to ensure ordering with any
312 // glBeginQueryEXT() calls that may have been put into the context.
313 ShallowFlushCHROMIUM();
314 gpu_control_->SignalQuery(
315 query,
316 base::Bind(&GLES2Implementation::RunIfContextNotLost,
317 weak_ptr_factory_.GetWeakPtr(),
318 callback));
321 void GLES2Implementation::SetSurfaceVisible(bool visible) {
322 TRACE_EVENT1(
323 "gpu", "GLES2Implementation::SetSurfaceVisible", "visible", visible);
324 ShallowFlushCHROMIUM();
325 gpu_control_->SetSurfaceVisible(visible);
328 void GLES2Implementation::SetAggressivelyFreeResources(
329 bool aggressively_free_resources) {
330 TRACE_EVENT1("gpu", "GLES2Implementation::SetAggressivelyFreeResources",
331 "aggressively_free_resources", aggressively_free_resources);
332 aggressively_free_resources_ = aggressively_free_resources;
334 if (aggressively_free_resources_ && helper_->HaveRingBuffer()) {
335 // Ensure that we clean up as much cache memory as possible and fully flush.
336 FlushDriverCachesCHROMIUM();
338 // Flush will delete transfer buffer resources if
339 // |aggressively_free_resources_| is true.
340 Flush();
341 } else {
342 ShallowFlushCHROMIUM();
346 bool GLES2Implementation::OnMemoryDump(
347 const base::trace_event::MemoryDumpArgs& args,
348 base::trace_event::ProcessMemoryDump* pmd) {
349 if (!transfer_buffer_->HaveBuffer())
350 return true;
352 const uint64 tracing_process_id =
353 base::trace_event::MemoryDumpManager::GetInstance()
354 ->GetTracingProcessId();
356 base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
357 base::StringPrintf("gpu/transfer_buffer_memory/buffer_%d",
358 transfer_buffer_->GetShmId()));
359 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
360 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
361 transfer_buffer_->GetSize());
362 dump->AddScalar("free_size",
363 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
364 transfer_buffer_->GetFreeSize());
365 auto guid =
366 GetBufferGUIDForTracing(tracing_process_id, transfer_buffer_->GetShmId());
367 const int kImportance = 2;
368 pmd->CreateSharedGlobalAllocatorDump(guid);
369 pmd->AddOwnershipEdge(dump->guid(), guid, kImportance);
371 return true;
374 void GLES2Implementation::WaitForCmd() {
375 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
376 helper_->CommandBufferHelper::Finish();
379 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
380 const char* extensions =
381 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
382 if (!extensions)
383 return false;
385 int length = strlen(ext);
386 while (true) {
387 int n = strcspn(extensions, " ");
388 if (n == length && 0 == strncmp(ext, extensions, length)) {
389 return true;
391 if ('\0' == extensions[n]) {
392 return false;
394 extensions += n + 1;
398 bool GLES2Implementation::IsExtensionAvailableHelper(
399 const char* extension, ExtensionStatus* status) {
400 switch (*status) {
401 case kAvailableExtensionStatus:
402 return true;
403 case kUnavailableExtensionStatus:
404 return false;
405 default: {
406 bool available = IsExtensionAvailable(extension);
407 *status = available ? kAvailableExtensionStatus :
408 kUnavailableExtensionStatus;
409 return available;
414 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
415 return IsExtensionAvailableHelper(
416 "GL_ANGLE_pack_reverse_row_order",
417 &angle_pack_reverse_row_order_status_);
420 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
421 return IsExtensionAvailableHelper(
422 "GL_CHROMIUM_framebuffer_multisample",
423 &chromium_framebuffer_multisample_);
426 const std::string& GLES2Implementation::GetLogPrefix() const {
427 const std::string& prefix(debug_marker_manager_.GetMarker());
428 return prefix.empty() ? this_in_hex_ : prefix;
431 GLenum GLES2Implementation::GetError() {
432 GPU_CLIENT_SINGLE_THREAD_CHECK();
433 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
434 GLenum err = GetGLError();
435 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
436 return err;
439 GLenum GLES2Implementation::GetClientSideGLError() {
440 if (error_bits_ == 0) {
441 return GL_NO_ERROR;
444 GLenum error = GL_NO_ERROR;
445 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
446 if ((error_bits_ & mask) != 0) {
447 error = GLES2Util::GLErrorBitToGLError(mask);
448 break;
451 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
452 return error;
455 GLenum GLES2Implementation::GetGLError() {
456 TRACE_EVENT0("gpu", "GLES2::GetGLError");
457 // Check the GL error first, then our wrapped error.
458 typedef cmds::GetError::Result Result;
459 Result* result = GetResultAs<Result*>();
460 // If we couldn't allocate a result the context is lost.
461 if (!result) {
462 return GL_NO_ERROR;
464 *result = GL_NO_ERROR;
465 helper_->GetError(GetResultShmId(), GetResultShmOffset());
466 WaitForCmd();
467 GLenum error = *result;
468 if (error == GL_NO_ERROR) {
469 error = GetClientSideGLError();
470 } else {
471 // There was an error, clear the corresponding wrapped error.
472 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
474 return error;
477 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
478 void GLES2Implementation::FailGLError(GLenum error) {
479 if (error != GL_NO_ERROR) {
480 NOTREACHED() << "Error";
483 // NOTE: Calling GetGLError overwrites data in the result buffer.
484 void GLES2Implementation::CheckGLError() {
485 FailGLError(GetGLError());
487 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
489 void GLES2Implementation::SetGLError(
490 GLenum error, const char* function_name, const char* msg) {
491 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
492 << GLES2Util::GetStringError(error) << ": "
493 << function_name << ": " << msg);
494 FailGLError(error);
495 if (msg) {
496 last_error_ = msg;
498 if (error_message_callback_) {
499 std::string temp(GLES2Util::GetStringError(error) + " : " +
500 function_name + ": " + (msg ? msg : ""));
501 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
503 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
505 if (error == GL_OUT_OF_MEMORY && lose_context_when_out_of_memory_) {
506 helper_->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
507 GL_UNKNOWN_CONTEXT_RESET_ARB);
511 void GLES2Implementation::SetGLErrorInvalidEnum(
512 const char* function_name, GLenum value, const char* label) {
513 SetGLError(GL_INVALID_ENUM, function_name,
514 (std::string(label) + " was " +
515 GLES2Util::GetStringEnum(value)).c_str());
518 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
519 std::vector<int8>* data) {
520 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
521 DCHECK(data);
522 const uint32 kStartSize = 32 * 1024;
523 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
524 if (!buffer.valid()) {
525 return false;
527 typedef cmd::GetBucketStart::Result Result;
528 Result* result = GetResultAs<Result*>();
529 if (!result) {
530 return false;
532 *result = 0;
533 helper_->GetBucketStart(
534 bucket_id, GetResultShmId(), GetResultShmOffset(),
535 buffer.size(), buffer.shm_id(), buffer.offset());
536 WaitForCmd();
537 uint32 size = *result;
538 data->resize(size);
539 if (size > 0u) {
540 uint32 offset = 0;
541 while (size) {
542 if (!buffer.valid()) {
543 buffer.Reset(size);
544 if (!buffer.valid()) {
545 return false;
547 helper_->GetBucketData(
548 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
549 WaitForCmd();
551 uint32 size_to_copy = std::min(size, buffer.size());
552 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
553 offset += size_to_copy;
554 size -= size_to_copy;
555 buffer.Release();
557 // Free the bucket. This is not required but it does free up the memory.
558 // and we don't have to wait for the result so from the client's perspective
559 // it's cheap.
560 helper_->SetBucketSize(bucket_id, 0);
562 return true;
565 void GLES2Implementation::SetBucketContents(
566 uint32 bucket_id, const void* data, size_t size) {
567 DCHECK(data);
568 helper_->SetBucketSize(bucket_id, size);
569 if (size > 0u) {
570 uint32 offset = 0;
571 while (size) {
572 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
573 if (!buffer.valid()) {
574 return;
576 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
577 buffer.size());
578 helper_->SetBucketData(
579 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
580 offset += buffer.size();
581 size -= buffer.size();
586 void GLES2Implementation::SetBucketAsCString(
587 uint32 bucket_id, const char* str) {
588 // NOTE: strings are passed NULL terminated. That means the empty
589 // string will have a size of 1 and no-string will have a size of 0
590 if (str) {
591 SetBucketContents(bucket_id, str, strlen(str) + 1);
592 } else {
593 helper_->SetBucketSize(bucket_id, 0);
597 bool GLES2Implementation::GetBucketAsString(
598 uint32 bucket_id, std::string* str) {
599 DCHECK(str);
600 std::vector<int8> data;
601 // NOTE: strings are passed NULL terminated. That means the empty
602 // string will have a size of 1 and no-string will have a size of 0
603 if (!GetBucketContents(bucket_id, &data)) {
604 return false;
606 if (data.empty()) {
607 return false;
609 str->assign(&data[0], &data[0] + data.size() - 1);
610 return true;
613 void GLES2Implementation::SetBucketAsString(
614 uint32 bucket_id, const std::string& str) {
615 // NOTE: strings are passed NULL terminated. That means the empty
616 // string will have a size of 1 and no-string will have a size of 0
617 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
620 void GLES2Implementation::Disable(GLenum cap) {
621 GPU_CLIENT_SINGLE_THREAD_CHECK();
622 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
623 << GLES2Util::GetStringCapability(cap) << ")");
624 bool changed = false;
625 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
626 helper_->Disable(cap);
628 CheckGLError();
631 void GLES2Implementation::Enable(GLenum cap) {
632 GPU_CLIENT_SINGLE_THREAD_CHECK();
633 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
634 << GLES2Util::GetStringCapability(cap) << ")");
635 bool changed = false;
636 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
637 helper_->Enable(cap);
639 CheckGLError();
642 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
643 GPU_CLIENT_SINGLE_THREAD_CHECK();
644 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
645 << GLES2Util::GetStringCapability(cap) << ")");
646 bool state = false;
647 if (!state_.GetEnabled(cap, &state)) {
648 typedef cmds::IsEnabled::Result Result;
649 Result* result = GetResultAs<Result*>();
650 if (!result) {
651 return GL_FALSE;
653 *result = 0;
654 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
655 WaitForCmd();
656 state = (*result) != 0;
659 GPU_CLIENT_LOG("returned " << state);
660 CheckGLError();
661 return state;
664 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
665 // TODO(zmo): For all the BINDING points, there is a possibility where
666 // resources are shared among multiple contexts, that the cached points
667 // are invalid. It is not a problem for now, but once we allow resource
668 // sharing in WebGL, we need to implement a mechanism to allow correct
669 // client side binding points tracking. crbug.com/465562.
671 // ES2 parameters.
672 switch (pname) {
673 case GL_ACTIVE_TEXTURE:
674 *params = active_texture_unit_ + GL_TEXTURE0;
675 return true;
676 case GL_ARRAY_BUFFER_BINDING:
677 *params = bound_array_buffer_;
678 return true;
679 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
680 *params =
681 vertex_array_object_manager_->bound_element_array_buffer();
682 return true;
683 case GL_FRAMEBUFFER_BINDING:
684 *params = bound_framebuffer_;
685 return true;
686 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
687 *params = capabilities_.max_combined_texture_image_units;
688 return true;
689 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
690 *params = capabilities_.max_cube_map_texture_size;
691 return true;
692 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
693 *params = capabilities_.max_fragment_uniform_vectors;
694 return true;
695 case GL_MAX_RENDERBUFFER_SIZE:
696 *params = capabilities_.max_renderbuffer_size;
697 return true;
698 case GL_MAX_TEXTURE_IMAGE_UNITS:
699 *params = capabilities_.max_texture_image_units;
700 return true;
701 case GL_MAX_TEXTURE_SIZE:
702 *params = capabilities_.max_texture_size;
703 return true;
704 case GL_MAX_VARYING_VECTORS:
705 *params = capabilities_.max_varying_vectors;
706 return true;
707 case GL_MAX_VERTEX_ATTRIBS:
708 *params = capabilities_.max_vertex_attribs;
709 return true;
710 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
711 *params = capabilities_.max_vertex_texture_image_units;
712 return true;
713 case GL_MAX_VERTEX_UNIFORM_VECTORS:
714 *params = capabilities_.max_vertex_uniform_vectors;
715 return true;
716 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
717 *params = capabilities_.num_compressed_texture_formats;
718 return true;
719 case GL_NUM_SHADER_BINARY_FORMATS:
720 *params = capabilities_.num_shader_binary_formats;
721 return true;
722 case GL_RENDERBUFFER_BINDING:
723 *params = bound_renderbuffer_;
724 return true;
725 case GL_TEXTURE_BINDING_2D:
726 *params = texture_units_[active_texture_unit_].bound_texture_2d;
727 return true;
728 case GL_TEXTURE_BINDING_CUBE_MAP:
729 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
730 return true;
732 // Non-standard parameters.
733 case GL_TEXTURE_BINDING_EXTERNAL_OES:
734 *params =
735 texture_units_[active_texture_unit_].bound_texture_external_oes;
736 return true;
737 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
738 *params = bound_pixel_pack_transfer_buffer_id_;
739 return true;
740 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
741 *params = bound_pixel_unpack_transfer_buffer_id_;
742 return true;
743 case GL_READ_FRAMEBUFFER_BINDING:
744 if (IsChromiumFramebufferMultisampleAvailable()) {
745 *params = bound_read_framebuffer_;
746 return true;
748 break;
749 case GL_TIMESTAMP_EXT:
750 // We convert all GPU timestamps to CPU time.
751 *params = base::saturated_cast<GLint>(
752 (base::TraceTicks::Now() - base::TraceTicks()).InMicroseconds()
753 * base::Time::kNanosecondsPerMicrosecond);
754 return true;
755 case GL_GPU_DISJOINT_EXT:
756 *params = static_cast<GLint>(query_tracker_->CheckAndResetDisjoint());
757 return true;
759 // Non-cached parameters.
760 case GL_ALIASED_LINE_WIDTH_RANGE:
761 case GL_ALIASED_POINT_SIZE_RANGE:
762 case GL_ALPHA_BITS:
763 case GL_BLEND:
764 case GL_BLEND_COLOR:
765 case GL_BLEND_DST_ALPHA:
766 case GL_BLEND_DST_RGB:
767 case GL_BLEND_EQUATION_ALPHA:
768 case GL_BLEND_EQUATION_RGB:
769 case GL_BLEND_SRC_ALPHA:
770 case GL_BLEND_SRC_RGB:
771 case GL_BLUE_BITS:
772 case GL_COLOR_CLEAR_VALUE:
773 case GL_COLOR_WRITEMASK:
774 case GL_COMPRESSED_TEXTURE_FORMATS:
775 case GL_CULL_FACE:
776 case GL_CULL_FACE_MODE:
777 case GL_CURRENT_PROGRAM:
778 case GL_DEPTH_BITS:
779 case GL_DEPTH_CLEAR_VALUE:
780 case GL_DEPTH_FUNC:
781 case GL_DEPTH_RANGE:
782 case GL_DEPTH_TEST:
783 case GL_DEPTH_WRITEMASK:
784 case GL_DITHER:
785 case GL_FRONT_FACE:
786 case GL_GENERATE_MIPMAP_HINT:
787 case GL_GREEN_BITS:
788 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
789 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
790 case GL_LINE_WIDTH:
791 case GL_MAX_VIEWPORT_DIMS:
792 case GL_PACK_ALIGNMENT:
793 case GL_POLYGON_OFFSET_FACTOR:
794 case GL_POLYGON_OFFSET_FILL:
795 case GL_POLYGON_OFFSET_UNITS:
796 case GL_RED_BITS:
797 case GL_SAMPLE_ALPHA_TO_COVERAGE:
798 case GL_SAMPLE_BUFFERS:
799 case GL_SAMPLE_COVERAGE:
800 case GL_SAMPLE_COVERAGE_INVERT:
801 case GL_SAMPLE_COVERAGE_VALUE:
802 case GL_SAMPLES:
803 case GL_SCISSOR_BOX:
804 case GL_SCISSOR_TEST:
805 case GL_SHADER_BINARY_FORMATS:
806 case GL_SHADER_COMPILER:
807 case GL_STENCIL_BACK_FAIL:
808 case GL_STENCIL_BACK_FUNC:
809 case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
810 case GL_STENCIL_BACK_PASS_DEPTH_PASS:
811 case GL_STENCIL_BACK_REF:
812 case GL_STENCIL_BACK_VALUE_MASK:
813 case GL_STENCIL_BACK_WRITEMASK:
814 case GL_STENCIL_BITS:
815 case GL_STENCIL_CLEAR_VALUE:
816 case GL_STENCIL_FAIL:
817 case GL_STENCIL_FUNC:
818 case GL_STENCIL_PASS_DEPTH_FAIL:
819 case GL_STENCIL_PASS_DEPTH_PASS:
820 case GL_STENCIL_REF:
821 case GL_STENCIL_TEST:
822 case GL_STENCIL_VALUE_MASK:
823 case GL_STENCIL_WRITEMASK:
824 case GL_SUBPIXEL_BITS:
825 case GL_UNPACK_ALIGNMENT:
826 case GL_VIEWPORT:
827 return false;
828 default:
829 break;
832 if (capabilities_.major_version < 3) {
833 return false;
836 // ES3 parameters.
837 switch (pname) {
838 case GL_COPY_READ_BUFFER_BINDING:
839 *params = bound_copy_read_buffer_;
840 return true;
841 case GL_COPY_WRITE_BUFFER_BINDING:
842 *params = bound_copy_write_buffer_;
843 return true;
844 case GL_MAJOR_VERSION:
845 *params = capabilities_.major_version;
846 return true;
847 case GL_MAX_3D_TEXTURE_SIZE:
848 *params = capabilities_.max_3d_texture_size;
849 return true;
850 case GL_MAX_ARRAY_TEXTURE_LAYERS:
851 *params = capabilities_.max_array_texture_layers;
852 return true;
853 case GL_MAX_COLOR_ATTACHMENTS:
854 *params = capabilities_.max_color_attachments;
855 return true;
856 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
857 *params = static_cast<GLint>(
858 capabilities_.max_combined_fragment_uniform_components);
859 return true;
860 case GL_MAX_COMBINED_UNIFORM_BLOCKS:
861 *params = capabilities_.max_combined_uniform_blocks;
862 return true;
863 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
864 *params = static_cast<GLint>(
865 capabilities_.max_combined_vertex_uniform_components);
866 return true;
867 case GL_MAX_DRAW_BUFFERS:
868 *params = capabilities_.max_draw_buffers;
869 return true;
870 case GL_MAX_ELEMENT_INDEX:
871 *params = static_cast<GLint>(capabilities_.max_element_index);
872 return true;
873 case GL_MAX_ELEMENTS_INDICES:
874 *params = capabilities_.max_elements_indices;
875 return true;
876 case GL_MAX_ELEMENTS_VERTICES:
877 *params = capabilities_.max_elements_vertices;
878 return true;
879 case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
880 *params = capabilities_.max_fragment_input_components;
881 return true;
882 case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
883 *params = capabilities_.max_fragment_uniform_blocks;
884 return true;
885 case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
886 *params = capabilities_.max_fragment_uniform_components;
887 return true;
888 case GL_MAX_PROGRAM_TEXEL_OFFSET:
889 *params = capabilities_.max_program_texel_offset;
890 return true;
891 case GL_MAX_SAMPLES:
892 *params = capabilities_.max_samples;
893 return true;
894 case GL_MAX_SERVER_WAIT_TIMEOUT:
895 *params = static_cast<GLint>(capabilities_.max_server_wait_timeout);
896 return true;
897 case GL_MAX_TEXTURE_LOD_BIAS:
898 *params = static_cast<GLint>(capabilities_.max_texture_lod_bias);
899 return true;
900 case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
901 *params = capabilities_.max_transform_feedback_interleaved_components;
902 return true;
903 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
904 *params = capabilities_.max_transform_feedback_separate_attribs;
905 return true;
906 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
907 *params = capabilities_.max_transform_feedback_separate_components;
908 return true;
909 case GL_MAX_UNIFORM_BLOCK_SIZE:
910 *params = static_cast<GLint>(capabilities_.max_uniform_block_size);
911 return true;
912 case GL_MAX_UNIFORM_BUFFER_BINDINGS:
913 *params = capabilities_.max_uniform_buffer_bindings;
914 return true;
915 case GL_MAX_VARYING_COMPONENTS:
916 *params = capabilities_.max_varying_components;
917 return true;
918 case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
919 *params = capabilities_.max_vertex_output_components;
920 return true;
921 case GL_MAX_VERTEX_UNIFORM_BLOCKS:
922 *params = capabilities_.max_vertex_uniform_blocks;
923 return true;
924 case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
925 *params = capabilities_.max_vertex_uniform_components;
926 return true;
927 case GL_MIN_PROGRAM_TEXEL_OFFSET:
928 *params = capabilities_.min_program_texel_offset;
929 return true;
930 case GL_MINOR_VERSION:
931 *params = capabilities_.minor_version;
932 return true;
933 case GL_NUM_EXTENSIONS:
934 *params = capabilities_.num_extensions;
935 return true;
936 case GL_NUM_PROGRAM_BINARY_FORMATS:
937 *params = capabilities_.num_program_binary_formats;
938 return true;
939 case GL_PIXEL_PACK_BUFFER_BINDING:
940 *params = bound_pixel_pack_buffer_;
941 return true;
942 case GL_PIXEL_UNPACK_BUFFER_BINDING:
943 *params = bound_pixel_unpack_buffer_;
944 return true;
945 case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
946 *params = bound_transform_feedback_buffer_;
947 return true;
948 case GL_UNIFORM_BUFFER_BINDING:
949 *params = bound_uniform_buffer_;
950 return true;
951 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
952 *params = capabilities_.uniform_buffer_offset_alignment;
953 return true;
955 // Non-cached ES3 parameters.
956 case GL_DRAW_BUFFER0:
957 case GL_DRAW_BUFFER1:
958 case GL_DRAW_BUFFER2:
959 case GL_DRAW_BUFFER3:
960 case GL_DRAW_BUFFER4:
961 case GL_DRAW_BUFFER5:
962 case GL_DRAW_BUFFER6:
963 case GL_DRAW_BUFFER7:
964 case GL_DRAW_BUFFER8:
965 case GL_DRAW_BUFFER9:
966 case GL_DRAW_BUFFER10:
967 case GL_DRAW_BUFFER11:
968 case GL_DRAW_BUFFER12:
969 case GL_DRAW_BUFFER13:
970 case GL_DRAW_BUFFER14:
971 case GL_DRAW_BUFFER15:
972 case GL_DRAW_FRAMEBUFFER_BINDING:
973 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
974 case GL_PACK_ROW_LENGTH:
975 case GL_PACK_SKIP_PIXELS:
976 case GL_PACK_SKIP_ROWS:
977 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
978 case GL_PROGRAM_BINARY_FORMATS:
979 case GL_RASTERIZER_DISCARD:
980 case GL_READ_BUFFER:
981 case GL_READ_FRAMEBUFFER_BINDING:
982 case GL_SAMPLER_BINDING:
983 case GL_TEXTURE_BINDING_2D_ARRAY:
984 case GL_TEXTURE_BINDING_3D:
985 case GL_TRANSFORM_FEEDBACK_BINDING:
986 case GL_TRANSFORM_FEEDBACK_ACTIVE:
987 case GL_TRANSFORM_FEEDBACK_PAUSED:
988 case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
989 case GL_TRANSFORM_FEEDBACK_BUFFER_START:
990 case GL_UNIFORM_BUFFER_SIZE:
991 case GL_UNIFORM_BUFFER_START:
992 case GL_UNPACK_IMAGE_HEIGHT:
993 case GL_UNPACK_ROW_LENGTH:
994 case GL_UNPACK_SKIP_IMAGES:
995 case GL_UNPACK_SKIP_PIXELS:
996 case GL_UNPACK_SKIP_ROWS:
997 case GL_VERTEX_ARRAY_BINDING:
998 return false;
999 default:
1000 return false;
1004 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
1005 // TODO(gman): Make this handle pnames that return more than 1 value.
1006 GLint value;
1007 if (!GetHelper(pname, &value)) {
1008 return false;
1010 *params = static_cast<GLboolean>(value);
1011 return true;
1014 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
1015 // TODO(gman): Make this handle pnames that return more than 1 value.
1016 switch (pname) {
1017 case GL_MAX_TEXTURE_LOD_BIAS:
1018 *params = capabilities_.max_texture_lod_bias;
1019 return true;
1020 default:
1021 break;
1023 GLint value;
1024 if (!GetHelper(pname, &value)) {
1025 return false;
1027 *params = static_cast<GLfloat>(value);
1028 return true;
1031 bool GLES2Implementation::GetInteger64vHelper(GLenum pname, GLint64* params) {
1032 switch (pname) {
1033 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
1034 *params = capabilities_.max_combined_fragment_uniform_components;
1035 return true;
1036 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
1037 *params = capabilities_.max_combined_vertex_uniform_components;
1038 return true;
1039 case GL_MAX_ELEMENT_INDEX:
1040 *params = capabilities_.max_element_index;
1041 return true;
1042 case GL_MAX_SERVER_WAIT_TIMEOUT:
1043 *params = capabilities_.max_server_wait_timeout;
1044 return true;
1045 case GL_MAX_UNIFORM_BLOCK_SIZE:
1046 *params = capabilities_.max_uniform_block_size;
1047 return true;
1048 case GL_TIMESTAMP_EXT:
1049 // We convert all GPU timestamps to CPU time.
1050 *params = (base::TraceTicks::Now() - base::TraceTicks()).InMicroseconds()
1051 * base::Time::kNanosecondsPerMicrosecond;
1052 return true;
1053 default:
1054 break;
1056 GLint value;
1057 if (!GetHelper(pname, &value)) {
1058 return false;
1060 *params = static_cast<GLint64>(value);
1061 return true;
1064 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
1065 return GetHelper(pname, params);
1068 bool GLES2Implementation::GetIntegeri_vHelper(
1069 GLenum pname, GLuint index, GLint* data) {
1070 // TODO(zmo): Implement client side caching.
1071 return false;
1074 bool GLES2Implementation::GetInteger64i_vHelper(
1075 GLenum pname, GLuint index, GLint64* data) {
1076 // TODO(zmo): Implement client side caching.
1077 return false;
1080 bool GLES2Implementation::GetInternalformativHelper(
1081 GLenum target, GLenum format, GLenum pname, GLsizei bufSize,
1082 GLint* params) {
1083 // TODO(zmo): Implement the client side caching.
1084 return false;
1087 bool GLES2Implementation::GetSyncivHelper(
1088 GLsync sync, GLenum pname, GLsizei bufsize, GLsizei* length,
1089 GLint* values) {
1090 GLint value = 0;
1091 switch (pname) {
1092 case GL_OBJECT_TYPE:
1093 value = GL_SYNC_FENCE;
1094 break;
1095 case GL_SYNC_CONDITION:
1096 value = GL_SYNC_GPU_COMMANDS_COMPLETE;
1097 break;
1098 case GL_SYNC_FLAGS:
1099 value = 0;
1100 break;
1101 default:
1102 return false;
1104 if (bufsize > 0) {
1105 DCHECK(values);
1106 *values = value;
1108 if (length) {
1109 *length = 1;
1111 return true;
1114 bool GLES2Implementation::GetQueryObjectValueHelper(
1115 const char* function_name, GLuint id, GLenum pname, GLuint64* params) {
1116 GPU_CLIENT_SINGLE_THREAD_CHECK();
1117 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryObjectValueHelper("
1118 << id << ", "
1119 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
1120 << static_cast<const void*>(params) << ")");
1122 QueryTracker::Query* query = query_tracker_->GetQuery(id);
1123 if (!query) {
1124 SetGLError(GL_INVALID_OPERATION,
1125 function_name, "unknown query id");
1126 return false;
1129 if (query->Active()) {
1130 SetGLError(
1131 GL_INVALID_OPERATION,
1132 function_name,
1133 "query active. Did you call glEndQueryEXT?");
1134 return false;
1137 if (query->NeverUsed()) {
1138 SetGLError(
1139 GL_INVALID_OPERATION,
1140 function_name, "Never used. Did you call glBeginQueryEXT?");
1141 return false;
1144 bool valid_value = false;
1145 switch (pname) {
1146 case GL_QUERY_RESULT_EXT:
1147 if (!query->CheckResultsAvailable(helper_)) {
1148 helper_->WaitForToken(query->token());
1149 if (!query->CheckResultsAvailable(helper_)) {
1150 FinishHelper();
1151 CHECK(query->CheckResultsAvailable(helper_));
1154 *params = query->GetResult();
1155 valid_value = true;
1156 break;
1157 case GL_QUERY_RESULT_AVAILABLE_EXT:
1158 *params = query->CheckResultsAvailable(helper_);
1159 valid_value = true;
1160 break;
1161 default:
1162 SetGLErrorInvalidEnum(function_name, pname, "pname");
1163 break;
1165 GPU_CLIENT_LOG(" " << *params);
1166 CheckGLError();
1167 return valid_value;
1170 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
1171 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1172 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
1173 Result* result = GetResultAs<Result*>();
1174 if (!result) {
1175 return 0;
1177 *result = 0;
1178 helper_->GetMaxValueInBufferCHROMIUM(
1179 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
1180 WaitForCmd();
1181 return *result;
1184 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
1185 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1186 GPU_CLIENT_SINGLE_THREAD_CHECK();
1187 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
1188 << buffer_id << ", " << count << ", "
1189 << GLES2Util::GetStringGetMaxIndexType(type)
1190 << ", " << offset << ")");
1191 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
1192 buffer_id, count, type, offset);
1193 GPU_CLIENT_LOG("returned " << result);
1194 CheckGLError();
1195 return result;
1198 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
1199 if (restore) {
1200 RestoreArrayBuffer(restore);
1201 // Restore the element array binding.
1202 // We only need to restore it if it wasn't a client side array.
1203 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
1204 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1209 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
1210 if (restore) {
1211 // Restore the user's current binding.
1212 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_);
1216 void GLES2Implementation::DrawElements(
1217 GLenum mode, GLsizei count, GLenum type, const void* indices) {
1218 GPU_CLIENT_SINGLE_THREAD_CHECK();
1219 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
1220 << GLES2Util::GetStringDrawMode(mode) << ", "
1221 << count << ", "
1222 << GLES2Util::GetStringIndexType(type) << ", "
1223 << static_cast<const void*>(indices) << ")");
1224 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1227 void GLES2Implementation::DrawRangeElements(
1228 GLenum mode, GLuint start, GLuint end,
1229 GLsizei count, GLenum type, const void* indices) {
1230 GPU_CLIENT_SINGLE_THREAD_CHECK();
1231 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawRangeElements("
1232 << GLES2Util::GetStringDrawMode(mode) << ", "
1233 << start << ", " << end << ", " << count << ", "
1234 << GLES2Util::GetStringIndexType(type) << ", "
1235 << static_cast<const void*>(indices) << ")");
1236 if (end < start) {
1237 SetGLError(GL_INVALID_VALUE, "glDrawRangeElements", "end < start");
1238 return;
1240 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1243 void GLES2Implementation::DrawElementsImpl(
1244 GLenum mode, GLsizei count, GLenum type, const void* indices,
1245 const char* func_name) {
1246 if (count < 0) {
1247 SetGLError(GL_INVALID_VALUE, func_name, "count < 0");
1248 return;
1250 bool simulated = false;
1251 GLuint offset = ToGLuint(indices);
1252 if (count > 0) {
1253 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
1254 !ValidateOffset(func_name, reinterpret_cast<GLintptr>(indices))) {
1255 return;
1257 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
1258 func_name, this, helper_, count, type, 0, indices,
1259 &offset, &simulated)) {
1260 return;
1263 helper_->DrawElements(mode, count, type, offset);
1264 RestoreElementAndArrayBuffers(simulated);
1265 CheckGLError();
1268 void GLES2Implementation::Flush() {
1269 GPU_CLIENT_SINGLE_THREAD_CHECK();
1270 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
1271 // Insert the cmd to call glFlush
1272 helper_->Flush();
1273 FlushHelper();
1276 void GLES2Implementation::ShallowFlushCHROMIUM() {
1277 GPU_CLIENT_SINGLE_THREAD_CHECK();
1278 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
1279 FlushHelper();
1282 void GLES2Implementation::FlushHelper() {
1283 // Flush our command buffer
1284 // (tell the service to execute up to the flush cmd.)
1285 helper_->CommandBufferHelper::Flush();
1287 if (aggressively_free_resources_)
1288 FreeEverything();
1291 void GLES2Implementation::OrderingBarrierCHROMIUM() {
1292 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOrderingBarrierCHROMIUM");
1293 // Flush command buffer at the GPU channel level. May be implemented as
1294 // Flush().
1295 helper_->CommandBufferHelper::OrderingBarrier();
1298 void GLES2Implementation::Finish() {
1299 GPU_CLIENT_SINGLE_THREAD_CHECK();
1300 FinishHelper();
1303 void GLES2Implementation::ShallowFinishCHROMIUM() {
1304 GPU_CLIENT_SINGLE_THREAD_CHECK();
1305 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
1306 // Flush our command buffer (tell the service to execute up to the flush cmd
1307 // and don't return until it completes).
1308 helper_->CommandBufferHelper::Finish();
1310 if (aggressively_free_resources_)
1311 FreeEverything();
1314 void GLES2Implementation::FinishHelper() {
1315 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
1316 TRACE_EVENT0("gpu", "GLES2::Finish");
1317 // Insert the cmd to call glFinish
1318 helper_->Finish();
1319 // Finish our command buffer
1320 // (tell the service to execute up to the Finish cmd and wait for it to
1321 // execute.)
1322 helper_->CommandBufferHelper::Finish();
1324 if (aggressively_free_resources_)
1325 FreeEverything();
1328 void GLES2Implementation::SwapBuffers() {
1329 GPU_CLIENT_SINGLE_THREAD_CHECK();
1330 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
1331 // TODO(piman): Strictly speaking we'd want to insert the token after the
1332 // swap, but the state update with the updated token might not have happened
1333 // by the time the SwapBuffer callback gets called, forcing us to synchronize
1334 // with the GPU process more than needed. So instead, make it happen before.
1335 // All it means is that we could be slightly looser on the kMaxSwapBuffers
1336 // semantics if the client doesn't use the callback mechanism, and by chance
1337 // the scheduler yields between the InsertToken and the SwapBuffers.
1338 swap_buffers_tokens_.push(helper_->InsertToken());
1339 helper_->SwapBuffers();
1340 helper_->CommandBufferHelper::Flush();
1341 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
1342 // compensate for TODO above.
1343 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
1344 helper_->WaitForToken(swap_buffers_tokens_.front());
1345 swap_buffers_tokens_.pop();
1349 void GLES2Implementation::SwapInterval(int interval) {
1350 GPU_CLIENT_SINGLE_THREAD_CHECK();
1351 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapInterval("
1352 << interval << ")");
1353 helper_->SwapInterval(interval);
1356 void GLES2Implementation::BindAttribLocation(
1357 GLuint program, GLuint index, const char* name) {
1358 GPU_CLIENT_SINGLE_THREAD_CHECK();
1359 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
1360 << program << ", " << index << ", " << name << ")");
1361 SetBucketAsString(kResultBucketId, name);
1362 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
1363 helper_->SetBucketSize(kResultBucketId, 0);
1364 CheckGLError();
1367 void GLES2Implementation::BindUniformLocationCHROMIUM(
1368 GLuint program, GLint location, const char* name) {
1369 GPU_CLIENT_SINGLE_THREAD_CHECK();
1370 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1371 << program << ", " << location << ", " << name << ")");
1372 SetBucketAsString(kResultBucketId, name);
1373 helper_->BindUniformLocationCHROMIUMBucket(
1374 program, location, kResultBucketId);
1375 helper_->SetBucketSize(kResultBucketId, 0);
1376 CheckGLError();
1379 void GLES2Implementation::GetVertexAttribPointerv(
1380 GLuint index, GLenum pname, void** ptr) {
1381 GPU_CLIENT_SINGLE_THREAD_CHECK();
1382 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1383 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1384 << static_cast<void*>(ptr) << ")");
1385 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
1386 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1387 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1388 typedef cmds::GetVertexAttribPointerv::Result Result;
1389 Result* result = GetResultAs<Result*>();
1390 if (!result) {
1391 return;
1393 result->SetNumResults(0);
1394 helper_->GetVertexAttribPointerv(
1395 index, pname, GetResultShmId(), GetResultShmOffset());
1396 WaitForCmd();
1397 result->CopyResult(ptr);
1398 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1400 GPU_CLIENT_LOG_CODE_BLOCK({
1401 for (int32 i = 0; i < num_results; ++i) {
1402 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
1405 CheckGLError();
1408 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1409 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1410 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
1411 SetGLError(
1412 GL_INVALID_VALUE,
1413 "glDeleteProgram", "id not created by this context.");
1414 return false;
1416 if (program == current_program_) {
1417 current_program_ = 0;
1419 return true;
1422 void GLES2Implementation::DeleteProgramStub(
1423 GLsizei n, const GLuint* programs) {
1424 DCHECK_EQ(1, n);
1425 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1426 helper_->DeleteProgram(programs[0]);
1429 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1430 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1431 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1432 SetGLError(
1433 GL_INVALID_VALUE,
1434 "glDeleteShader", "id not created by this context.");
1435 return false;
1437 return true;
1440 void GLES2Implementation::DeleteShaderStub(
1441 GLsizei n, const GLuint* shaders) {
1442 DCHECK_EQ(1, n);
1443 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1444 helper_->DeleteShader(shaders[0]);
1447 void GLES2Implementation::DeleteSyncHelper(GLsync sync) {
1448 GLuint sync_uint = ToGLuint(sync);
1449 if (!GetIdHandler(id_namespaces::kSyncs)->FreeIds(
1450 this, 1, &sync_uint, &GLES2Implementation::DeleteSyncStub)) {
1451 SetGLError(
1452 GL_INVALID_VALUE,
1453 "glDeleteSync", "id not created by this context.");
1457 void GLES2Implementation::DeleteSyncStub(GLsizei n, const GLuint* syncs) {
1458 DCHECK_EQ(1, n);
1459 helper_->DeleteSync(syncs[0]);
1462 GLint GLES2Implementation::GetAttribLocationHelper(
1463 GLuint program, const char* name) {
1464 typedef cmds::GetAttribLocation::Result Result;
1465 Result* result = GetResultAs<Result*>();
1466 if (!result) {
1467 return -1;
1469 *result = -1;
1470 SetBucketAsCString(kResultBucketId, name);
1471 helper_->GetAttribLocation(
1472 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1473 WaitForCmd();
1474 helper_->SetBucketSize(kResultBucketId, 0);
1475 return *result;
1478 GLint GLES2Implementation::GetAttribLocation(
1479 GLuint program, const char* name) {
1480 GPU_CLIENT_SINGLE_THREAD_CHECK();
1481 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1482 << ", " << name << ")");
1483 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1484 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1485 this, program, name);
1486 GPU_CLIENT_LOG("returned " << loc);
1487 CheckGLError();
1488 return loc;
1491 GLint GLES2Implementation::GetUniformLocationHelper(
1492 GLuint program, const char* name) {
1493 typedef cmds::GetUniformLocation::Result Result;
1494 Result* result = GetResultAs<Result*>();
1495 if (!result) {
1496 return -1;
1498 *result = -1;
1499 SetBucketAsCString(kResultBucketId, name);
1500 helper_->GetUniformLocation(program, kResultBucketId,
1501 GetResultShmId(), GetResultShmOffset());
1502 WaitForCmd();
1503 helper_->SetBucketSize(kResultBucketId, 0);
1504 return *result;
1507 GLint GLES2Implementation::GetUniformLocation(
1508 GLuint program, const char* name) {
1509 GPU_CLIENT_SINGLE_THREAD_CHECK();
1510 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1511 << ", " << name << ")");
1512 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1513 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1514 this, program, name);
1515 GPU_CLIENT_LOG("returned " << loc);
1516 CheckGLError();
1517 return loc;
1520 bool GLES2Implementation::GetUniformIndicesHelper(
1521 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1522 typedef cmds::GetUniformIndices::Result Result;
1523 Result* result = GetResultAs<Result*>();
1524 if (!result) {
1525 return false;
1527 result->SetNumResults(0);
1528 if (!PackStringsToBucket(count, names, NULL, "glGetUniformIndices")) {
1529 return false;
1531 helper_->GetUniformIndices(program, kResultBucketId,
1532 GetResultShmId(), GetResultShmOffset());
1533 WaitForCmd();
1534 if (result->GetNumResults() != count) {
1535 return false;
1537 result->CopyResult(indices);
1538 return true;
1541 void GLES2Implementation::GetUniformIndices(
1542 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1543 GPU_CLIENT_SINGLE_THREAD_CHECK();
1544 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
1545 << ", " << count << ", " << names << ", " << indices << ")");
1546 TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
1547 if (count < 0) {
1548 SetGLError(GL_INVALID_VALUE, "glGetUniformIndices", "count < 0");
1549 return;
1551 if (count == 0) {
1552 return;
1554 bool success = share_group_->program_info_manager()->GetUniformIndices(
1555 this, program, count, names, indices);
1556 if (success) {
1557 GPU_CLIENT_LOG_CODE_BLOCK({
1558 for (GLsizei ii = 0; ii < count; ++ii) {
1559 GPU_CLIENT_LOG(" " << ii << ": " << indices[ii]);
1563 CheckGLError();
1566 bool GLES2Implementation::GetProgramivHelper(
1567 GLuint program, GLenum pname, GLint* params) {
1568 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1569 this, program, pname, params);
1570 GPU_CLIENT_LOG_CODE_BLOCK({
1571 if (got_value) {
1572 GPU_CLIENT_LOG(" 0: " << *params);
1575 return got_value;
1578 GLint GLES2Implementation::GetFragDataLocationHelper(
1579 GLuint program, const char* name) {
1580 typedef cmds::GetFragDataLocation::Result Result;
1581 Result* result = GetResultAs<Result*>();
1582 if (!result) {
1583 return -1;
1585 *result = -1;
1586 SetBucketAsCString(kResultBucketId, name);
1587 helper_->GetFragDataLocation(
1588 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1589 WaitForCmd();
1590 helper_->SetBucketSize(kResultBucketId, 0);
1591 return *result;
1594 GLint GLES2Implementation::GetFragDataLocation(
1595 GLuint program, const char* name) {
1596 GPU_CLIENT_SINGLE_THREAD_CHECK();
1597 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataLocation("
1598 << program << ", " << name << ")");
1599 TRACE_EVENT0("gpu", "GLES2::GetFragDataLocation");
1600 GLint loc = share_group_->program_info_manager()->GetFragDataLocation(
1601 this, program, name);
1602 GPU_CLIENT_LOG("returned " << loc);
1603 CheckGLError();
1604 return loc;
1607 GLuint GLES2Implementation::GetUniformBlockIndexHelper(
1608 GLuint program, const char* name) {
1609 typedef cmds::GetUniformBlockIndex::Result Result;
1610 Result* result = GetResultAs<Result*>();
1611 if (!result) {
1612 return GL_INVALID_INDEX;
1614 *result = GL_INVALID_INDEX;
1615 SetBucketAsCString(kResultBucketId, name);
1616 helper_->GetUniformBlockIndex(
1617 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1618 WaitForCmd();
1619 helper_->SetBucketSize(kResultBucketId, 0);
1620 return *result;
1623 GLuint GLES2Implementation::GetUniformBlockIndex(
1624 GLuint program, const char* name) {
1625 GPU_CLIENT_SINGLE_THREAD_CHECK();
1626 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformBlockIndex("
1627 << program << ", " << name << ")");
1628 TRACE_EVENT0("gpu", "GLES2::GetUniformBlockIndex");
1629 GLuint index = share_group_->program_info_manager()->GetUniformBlockIndex(
1630 this, program, name);
1631 GPU_CLIENT_LOG("returned " << index);
1632 CheckGLError();
1633 return index;
1636 void GLES2Implementation::LinkProgram(GLuint program) {
1637 GPU_CLIENT_SINGLE_THREAD_CHECK();
1638 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1639 helper_->LinkProgram(program);
1640 share_group_->program_info_manager()->CreateInfo(program);
1641 CheckGLError();
1644 void GLES2Implementation::ShaderBinary(
1645 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1646 GLsizei length) {
1647 GPU_CLIENT_SINGLE_THREAD_CHECK();
1648 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1649 << static_cast<const void*>(shaders) << ", "
1650 << GLES2Util::GetStringEnum(binaryformat) << ", "
1651 << static_cast<const void*>(binary) << ", "
1652 << length << ")");
1653 if (n < 0) {
1654 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1655 return;
1657 if (length < 0) {
1658 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1659 return;
1661 // TODO(gman): ShaderBinary should use buckets.
1662 unsigned int shader_id_size = n * sizeof(*shaders);
1663 ScopedTransferBufferArray<GLint> buffer(
1664 shader_id_size + length, helper_, transfer_buffer_);
1665 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1666 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1667 return;
1669 void* shader_ids = buffer.elements();
1670 void* shader_data = buffer.elements() + shader_id_size;
1671 memcpy(shader_ids, shaders, shader_id_size);
1672 memcpy(shader_data, binary, length);
1673 helper_->ShaderBinary(
1675 buffer.shm_id(),
1676 buffer.offset(),
1677 binaryformat,
1678 buffer.shm_id(),
1679 buffer.offset() + shader_id_size,
1680 length);
1681 CheckGLError();
1684 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1685 GPU_CLIENT_SINGLE_THREAD_CHECK();
1686 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1687 << GLES2Util::GetStringPixelStore(pname) << ", "
1688 << param << ")");
1689 switch (pname) {
1690 case GL_PACK_ALIGNMENT:
1691 pack_alignment_ = param;
1692 break;
1693 case GL_UNPACK_ALIGNMENT:
1694 unpack_alignment_ = param;
1695 break;
1696 case GL_UNPACK_ROW_LENGTH_EXT:
1697 unpack_row_length_ = param;
1698 return;
1699 case GL_UNPACK_IMAGE_HEIGHT:
1700 unpack_image_height_ = param;
1701 return;
1702 case GL_UNPACK_SKIP_ROWS_EXT:
1703 unpack_skip_rows_ = param;
1704 return;
1705 case GL_UNPACK_SKIP_PIXELS_EXT:
1706 unpack_skip_pixels_ = param;
1707 return;
1708 case GL_UNPACK_SKIP_IMAGES:
1709 unpack_skip_images_ = param;
1710 return;
1711 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1712 pack_reverse_row_order_ =
1713 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1714 break;
1715 default:
1716 break;
1718 helper_->PixelStorei(pname, param);
1719 CheckGLError();
1722 void GLES2Implementation::VertexAttribIPointer(
1723 GLuint index, GLint size, GLenum type, GLsizei stride, const void* ptr) {
1724 GPU_CLIENT_SINGLE_THREAD_CHECK();
1725 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribIPointer("
1726 << index << ", "
1727 << size << ", "
1728 << GLES2Util::GetStringVertexAttribIType(type) << ", "
1729 << stride << ", "
1730 << ptr << ")");
1731 // Record the info on the client side.
1732 if (!vertex_array_object_manager_->SetAttribPointer(bound_array_buffer_,
1733 index,
1734 size,
1735 type,
1736 GL_FALSE,
1737 stride,
1738 ptr,
1739 GL_TRUE)) {
1740 SetGLError(GL_INVALID_OPERATION, "glVertexAttribIPointer",
1741 "client side arrays are not allowed in vertex array objects.");
1742 return;
1744 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
1745 // Only report NON client side buffers to the service.
1746 if (!ValidateOffset("glVertexAttribIPointer",
1747 reinterpret_cast<GLintptr>(ptr))) {
1748 return;
1750 helper_->VertexAttribIPointer(index, size, type, stride, ToGLuint(ptr));
1752 CheckGLError();
1755 void GLES2Implementation::VertexAttribPointer(
1756 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1757 const void* ptr) {
1758 GPU_CLIENT_SINGLE_THREAD_CHECK();
1759 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1760 << index << ", "
1761 << size << ", "
1762 << GLES2Util::GetStringVertexAttribType(type) << ", "
1763 << GLES2Util::GetStringBool(normalized) << ", "
1764 << stride << ", "
1765 << ptr << ")");
1766 // Record the info on the client side.
1767 if (!vertex_array_object_manager_->SetAttribPointer(bound_array_buffer_,
1768 index,
1769 size,
1770 type,
1771 normalized,
1772 stride,
1773 ptr,
1774 GL_FALSE)) {
1775 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1776 "client side arrays are not allowed in vertex array objects.");
1777 return;
1779 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
1780 // Only report NON client side buffers to the service.
1781 if (!ValidateOffset("glVertexAttribPointer",
1782 reinterpret_cast<GLintptr>(ptr))) {
1783 return;
1785 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1786 ToGLuint(ptr));
1788 CheckGLError();
1791 void GLES2Implementation::VertexAttribDivisorANGLE(
1792 GLuint index, GLuint divisor) {
1793 GPU_CLIENT_SINGLE_THREAD_CHECK();
1794 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1795 << index << ", "
1796 << divisor << ") ");
1797 // Record the info on the client side.
1798 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1799 helper_->VertexAttribDivisorANGLE(index, divisor);
1800 CheckGLError();
1803 void GLES2Implementation::BufferDataHelper(
1804 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1805 if (!ValidateSize("glBufferData", size))
1806 return;
1808 #if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
1809 // Do not upload uninitialized data. Even if it's not a bug, it can cause a
1810 // bogus MSan report during a readback later. This is because MSan doesn't
1811 // understand shared memory and would assume we were reading back the same
1812 // unintialized data.
1813 if (data) __msan_check_mem_is_initialized(data, size);
1814 #endif
1816 GLuint buffer_id;
1817 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1818 if (!buffer_id) {
1819 return;
1822 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1823 if (buffer)
1824 RemoveTransferBuffer(buffer);
1826 // Create new buffer.
1827 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1828 DCHECK(buffer);
1829 if (buffer->address() && data)
1830 memcpy(buffer->address(), data, size);
1831 return;
1834 RemoveMappedBufferRangeByTarget(target);
1836 // If there is no data just send BufferData
1837 if (size == 0 || !data) {
1838 helper_->BufferData(target, size, 0, 0, usage);
1839 return;
1842 // See if we can send all at once.
1843 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1844 if (!buffer.valid()) {
1845 return;
1848 if (buffer.size() >= static_cast<unsigned int>(size)) {
1849 memcpy(buffer.address(), data, size);
1850 helper_->BufferData(
1851 target,
1852 size,
1853 buffer.shm_id(),
1854 buffer.offset(),
1855 usage);
1856 return;
1859 // Make the buffer with BufferData then send via BufferSubData
1860 helper_->BufferData(target, size, 0, 0, usage);
1861 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1862 CheckGLError();
1865 void GLES2Implementation::BufferData(
1866 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1867 GPU_CLIENT_SINGLE_THREAD_CHECK();
1868 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1869 << GLES2Util::GetStringBufferTarget(target) << ", "
1870 << size << ", "
1871 << static_cast<const void*>(data) << ", "
1872 << GLES2Util::GetStringBufferUsage(usage) << ")");
1873 BufferDataHelper(target, size, data, usage);
1874 CheckGLError();
1877 void GLES2Implementation::BufferSubDataHelper(
1878 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1879 if (size == 0) {
1880 return;
1883 if (!ValidateSize("glBufferSubData", size) ||
1884 !ValidateOffset("glBufferSubData", offset)) {
1885 return;
1888 GLuint buffer_id;
1889 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1890 if (!buffer_id) {
1891 return;
1893 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1894 if (!buffer) {
1895 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1896 return;
1899 int32 end = 0;
1900 int32 buffer_size = buffer->size();
1901 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1902 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1903 return;
1906 if (buffer->address() && data)
1907 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1908 return;
1911 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1912 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1915 void GLES2Implementation::BufferSubDataHelperImpl(
1916 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1917 ScopedTransferBufferPtr* buffer) {
1918 DCHECK(buffer);
1919 DCHECK_GT(size, 0);
1921 const int8* source = static_cast<const int8*>(data);
1922 while (size) {
1923 if (!buffer->valid() || buffer->size() == 0) {
1924 buffer->Reset(size);
1925 if (!buffer->valid()) {
1926 return;
1929 memcpy(buffer->address(), source, buffer->size());
1930 helper_->BufferSubData(
1931 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1932 offset += buffer->size();
1933 source += buffer->size();
1934 size -= buffer->size();
1935 buffer->Release();
1939 void GLES2Implementation::BufferSubData(
1940 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1941 GPU_CLIENT_SINGLE_THREAD_CHECK();
1942 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1943 << GLES2Util::GetStringBufferTarget(target) << ", "
1944 << offset << ", " << size << ", "
1945 << static_cast<const void*>(data) << ")");
1946 BufferSubDataHelper(target, offset, size, data);
1947 CheckGLError();
1950 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
1951 int32 token = buffer->last_usage_token();
1953 if (token) {
1954 if (helper_->HasTokenPassed(token))
1955 buffer_tracker_->Free(buffer);
1956 else
1957 buffer_tracker_->FreePendingToken(buffer, token);
1958 } else {
1959 buffer_tracker_->Free(buffer);
1962 buffer_tracker_->RemoveBuffer(buffer->id());
1965 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1966 GLenum target,
1967 const char* function_name,
1968 GLuint* buffer_id) {
1969 *buffer_id = 0;
1971 switch (target) {
1972 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1973 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1974 break;
1975 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1976 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1977 break;
1978 default:
1979 // Unknown target
1980 return false;
1982 if (!*buffer_id) {
1983 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1985 return true;
1988 BufferTracker::Buffer*
1989 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1990 GLuint buffer_id,
1991 const char* function_name,
1992 GLuint offset, GLsizei size) {
1993 DCHECK(buffer_id);
1994 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1995 if (!buffer) {
1996 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1997 return NULL;
1999 if (buffer->mapped()) {
2000 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
2001 return NULL;
2003 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
2004 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
2005 return NULL;
2007 return buffer;
2010 void GLES2Implementation::CompressedTexImage2D(
2011 GLenum target, GLint level, GLenum internalformat, GLsizei width,
2012 GLsizei height, GLint border, GLsizei image_size, const void* data) {
2013 GPU_CLIENT_SINGLE_THREAD_CHECK();
2014 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
2015 << GLES2Util::GetStringTextureTarget(target) << ", "
2016 << level << ", "
2017 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
2018 << width << ", " << height << ", " << border << ", "
2019 << image_size << ", "
2020 << static_cast<const void*>(data) << ")");
2021 if (width < 0 || height < 0 || level < 0) {
2022 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
2023 return;
2025 if (border != 0) {
2026 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "border != 0");
2027 return;
2029 if (height == 0 || width == 0) {
2030 return;
2032 // If there's a pixel unpack buffer bound use it when issuing
2033 // CompressedTexImage2D.
2034 if (bound_pixel_unpack_transfer_buffer_id_) {
2035 GLuint offset = ToGLuint(data);
2036 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2037 bound_pixel_unpack_transfer_buffer_id_,
2038 "glCompressedTexImage2D", offset, image_size);
2039 if (buffer && buffer->shm_id() != -1) {
2040 helper_->CompressedTexImage2D(
2041 target, level, internalformat, width, height, image_size,
2042 buffer->shm_id(), buffer->shm_offset() + offset);
2043 buffer->set_last_usage_token(helper_->InsertToken());
2045 return;
2047 SetBucketContents(kResultBucketId, data, image_size);
2048 helper_->CompressedTexImage2DBucket(
2049 target, level, internalformat, width, height, kResultBucketId);
2050 // Free the bucket. This is not required but it does free up the memory.
2051 // and we don't have to wait for the result so from the client's perspective
2052 // it's cheap.
2053 helper_->SetBucketSize(kResultBucketId, 0);
2054 CheckGLError();
2057 void GLES2Implementation::CompressedTexSubImage2D(
2058 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2059 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
2060 GPU_CLIENT_SINGLE_THREAD_CHECK();
2061 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
2062 << GLES2Util::GetStringTextureTarget(target) << ", "
2063 << level << ", "
2064 << xoffset << ", " << yoffset << ", "
2065 << width << ", " << height << ", "
2066 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
2067 << image_size << ", "
2068 << static_cast<const void*>(data) << ")");
2069 if (width < 0 || height < 0 || level < 0) {
2070 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
2071 return;
2073 // If there's a pixel unpack buffer bound use it when issuing
2074 // CompressedTexSubImage2D.
2075 if (bound_pixel_unpack_transfer_buffer_id_) {
2076 GLuint offset = ToGLuint(data);
2077 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2078 bound_pixel_unpack_transfer_buffer_id_,
2079 "glCompressedTexSubImage2D", offset, image_size);
2080 if (buffer && buffer->shm_id() != -1) {
2081 helper_->CompressedTexSubImage2D(
2082 target, level, xoffset, yoffset, width, height, format, image_size,
2083 buffer->shm_id(), buffer->shm_offset() + offset);
2084 buffer->set_last_usage_token(helper_->InsertToken());
2085 CheckGLError();
2087 return;
2089 SetBucketContents(kResultBucketId, data, image_size);
2090 helper_->CompressedTexSubImage2DBucket(
2091 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
2092 // Free the bucket. This is not required but it does free up the memory.
2093 // and we don't have to wait for the result so from the client's perspective
2094 // it's cheap.
2095 helper_->SetBucketSize(kResultBucketId, 0);
2096 CheckGLError();
2099 void GLES2Implementation::CompressedTexImage3D(
2100 GLenum target, GLint level, GLenum internalformat, GLsizei width,
2101 GLsizei height, GLsizei depth, GLint border, GLsizei image_size,
2102 const void* data) {
2103 GPU_CLIENT_SINGLE_THREAD_CHECK();
2104 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage3D("
2105 << GLES2Util::GetStringTexture3DTarget(target) << ", " << level << ", "
2106 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
2107 << width << ", " << height << ", " << depth << ", " << border << ", "
2108 << image_size << ", " << static_cast<const void*>(data) << ")");
2109 if (width < 0 || height < 0 || depth < 0 || level < 0) {
2110 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "dimension < 0");
2111 return;
2113 if (border != 0) {
2114 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "border != 0");
2115 return;
2117 if (height == 0 || width == 0 || depth == 0) {
2118 return;
2120 // If there's a pixel unpack buffer bound use it when issuing
2121 // CompressedTexImage3D.
2122 if (bound_pixel_unpack_transfer_buffer_id_) {
2123 GLuint offset = ToGLuint(data);
2124 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2125 bound_pixel_unpack_transfer_buffer_id_,
2126 "glCompressedTexImage3D", offset, image_size);
2127 if (buffer && buffer->shm_id() != -1) {
2128 helper_->CompressedTexImage3D(
2129 target, level, internalformat, width, height, depth, image_size,
2130 buffer->shm_id(), buffer->shm_offset() + offset);
2131 buffer->set_last_usage_token(helper_->InsertToken());
2133 return;
2135 SetBucketContents(kResultBucketId, data, image_size);
2136 helper_->CompressedTexImage3DBucket(
2137 target, level, internalformat, width, height, depth, kResultBucketId);
2138 // Free the bucket. This is not required but it does free up the memory.
2139 // and we don't have to wait for the result so from the client's perspective
2140 // it's cheap.
2141 helper_->SetBucketSize(kResultBucketId, 0);
2142 CheckGLError();
2145 void GLES2Implementation::CompressedTexSubImage3D(
2146 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2147 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2148 GLsizei image_size, const void* data) {
2149 GPU_CLIENT_SINGLE_THREAD_CHECK();
2150 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage3D("
2151 << GLES2Util::GetStringTextureTarget(target) << ", "
2152 << level << ", "
2153 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2154 << width << ", " << height << ", " << depth << ", "
2155 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
2156 << image_size << ", "
2157 << static_cast<const void*>(data) << ")");
2158 if (width < 0 || height < 0 || depth < 0 || level < 0) {
2159 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage3D", "dimension < 0");
2160 return;
2162 // If there's a pixel unpack buffer bound use it when issuing
2163 // CompressedTexSubImage3D.
2164 if (bound_pixel_unpack_transfer_buffer_id_) {
2165 GLuint offset = ToGLuint(data);
2166 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2167 bound_pixel_unpack_transfer_buffer_id_,
2168 "glCompressedTexSubImage3D", offset, image_size);
2169 if (buffer && buffer->shm_id() != -1) {
2170 helper_->CompressedTexSubImage3D(
2171 target, level, xoffset, yoffset, zoffset,
2172 width, height, depth, format, image_size,
2173 buffer->shm_id(), buffer->shm_offset() + offset);
2174 buffer->set_last_usage_token(helper_->InsertToken());
2175 CheckGLError();
2177 return;
2179 SetBucketContents(kResultBucketId, data, image_size);
2180 helper_->CompressedTexSubImage3DBucket(
2181 target, level, xoffset, yoffset, zoffset, width, height, depth, format,
2182 kResultBucketId);
2183 // Free the bucket. This is not required but it does free up the memory.
2184 // and we don't have to wait for the result so from the client's perspective
2185 // it's cheap.
2186 helper_->SetBucketSize(kResultBucketId, 0);
2187 CheckGLError();
2190 namespace {
2192 void CopyRectToBuffer(
2193 const void* pixels,
2194 uint32 height,
2195 uint32 unpadded_row_size,
2196 uint32 pixels_padded_row_size,
2197 void* buffer,
2198 uint32 buffer_padded_row_size) {
2199 const int8* source = static_cast<const int8*>(pixels);
2200 int8* dest = static_cast<int8*>(buffer);
2201 if (pixels_padded_row_size != buffer_padded_row_size) {
2202 // the last row is copied unpadded at the end
2203 for (; height > 1; --height) {
2204 memcpy(dest, source, buffer_padded_row_size);
2205 dest += buffer_padded_row_size;
2206 source += pixels_padded_row_size;
2208 memcpy(dest, source, unpadded_row_size);
2209 } else {
2210 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
2211 memcpy(dest, source, size);
2215 } // anonymous namespace
2217 void GLES2Implementation::TexImage2D(
2218 GLenum target, GLint level, GLint internalformat, GLsizei width,
2219 GLsizei height, GLint border, GLenum format, GLenum type,
2220 const void* pixels) {
2221 GPU_CLIENT_SINGLE_THREAD_CHECK();
2222 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
2223 << GLES2Util::GetStringTextureTarget(target) << ", "
2224 << level << ", "
2225 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2226 << width << ", " << height << ", " << border << ", "
2227 << GLES2Util::GetStringTextureFormat(format) << ", "
2228 << GLES2Util::GetStringPixelType(type) << ", "
2229 << static_cast<const void*>(pixels) << ")");
2230 if (level < 0 || height < 0 || width < 0) {
2231 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
2232 return;
2234 if (border != 0) {
2235 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
2236 return;
2238 uint32 size;
2239 uint32 unpadded_row_size;
2240 uint32 padded_row_size;
2241 if (!GLES2Util::ComputeImageDataSizes(
2242 width, height, 1, format, type, unpack_alignment_, &size,
2243 &unpadded_row_size, &padded_row_size)) {
2244 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
2245 return;
2248 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
2249 if (bound_pixel_unpack_transfer_buffer_id_) {
2250 GLuint offset = ToGLuint(pixels);
2251 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2252 bound_pixel_unpack_transfer_buffer_id_,
2253 "glTexImage2D", offset, size);
2254 if (buffer && buffer->shm_id() != -1) {
2255 helper_->TexImage2D(
2256 target, level, internalformat, width, height, format, type,
2257 buffer->shm_id(), buffer->shm_offset() + offset);
2258 buffer->set_last_usage_token(helper_->InsertToken());
2259 CheckGLError();
2261 return;
2264 // If there's no data just issue TexImage2D
2265 if (!pixels) {
2266 helper_->TexImage2D(
2267 target, level, internalformat, width, height, format, type,
2268 0, 0);
2269 CheckGLError();
2270 return;
2273 // compute the advance bytes per row for the src pixels
2274 uint32 src_padded_row_size;
2275 if (unpack_row_length_ > 0) {
2276 if (!GLES2Util::ComputeImagePaddedRowSize(
2277 unpack_row_length_, format, type, unpack_alignment_,
2278 &src_padded_row_size)) {
2279 SetGLError(
2280 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2281 return;
2283 } else {
2284 src_padded_row_size = padded_row_size;
2287 // advance pixels pointer past the skip rows and skip pixels
2288 pixels = reinterpret_cast<const int8*>(pixels) +
2289 unpack_skip_rows_ * src_padded_row_size;
2290 if (unpack_skip_pixels_) {
2291 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2292 pixels = reinterpret_cast<const int8*>(pixels) +
2293 unpack_skip_pixels_ * group_size;
2296 // Check if we can send it all at once.
2297 int32_t shm_id = 0;
2298 uint32_t shm_offset = 0;
2299 void* buffer_pointer = nullptr;
2301 ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
2302 ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
2304 if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
2305 shm_id = transfer_alloc.shm_id();
2306 shm_offset = transfer_alloc.offset();
2307 buffer_pointer = transfer_alloc.address();
2308 } else {
2309 mapped_alloc.Reset(size);
2310 if (mapped_alloc.valid()) {
2311 transfer_alloc.Discard();
2313 mapped_alloc.SetFlushAfterRelease(true);
2314 shm_id = mapped_alloc.shm_id();
2315 shm_offset = mapped_alloc.offset();
2316 buffer_pointer = mapped_alloc.address();
2320 if (buffer_pointer) {
2321 CopyRectToBuffer(
2322 pixels, height, unpadded_row_size, src_padded_row_size,
2323 buffer_pointer, padded_row_size);
2324 helper_->TexImage2D(
2325 target, level, internalformat, width, height, format, type,
2326 shm_id, shm_offset);
2327 CheckGLError();
2328 return;
2331 // No, so send it using TexSubImage2D.
2332 helper_->TexImage2D(
2333 target, level, internalformat, width, height, format, type,
2334 0, 0);
2335 TexSubImage2DImpl(
2336 target, level, 0, 0, width, height, format, type, unpadded_row_size,
2337 pixels, src_padded_row_size, GL_TRUE, &transfer_alloc, padded_row_size);
2338 CheckGLError();
2341 void GLES2Implementation::TexImage3D(
2342 GLenum target, GLint level, GLint internalformat, GLsizei width,
2343 GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type,
2344 const void* pixels) {
2345 GPU_CLIENT_SINGLE_THREAD_CHECK();
2346 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D("
2347 << GLES2Util::GetStringTextureTarget(target) << ", "
2348 << level << ", "
2349 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2350 << width << ", " << height << ", " << depth << ", " << border << ", "
2351 << GLES2Util::GetStringTextureFormat(format) << ", "
2352 << GLES2Util::GetStringPixelType(type) << ", "
2353 << static_cast<const void*>(pixels) << ")");
2354 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2355 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "dimension < 0");
2356 return;
2358 if (border != 0) {
2359 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "border != 0");
2360 return;
2362 uint32 size;
2363 uint32 unpadded_row_size;
2364 uint32 padded_row_size;
2365 if (!GLES2Util::ComputeImageDataSizes(
2366 width, height, depth, format, type, unpack_alignment_, &size,
2367 &unpadded_row_size, &padded_row_size)) {
2368 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large");
2369 return;
2372 // If there's a pixel unpack buffer bound use it when issuing TexImage3D.
2373 if (bound_pixel_unpack_transfer_buffer_id_) {
2374 GLuint offset = ToGLuint(pixels);
2375 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2376 bound_pixel_unpack_transfer_buffer_id_,
2377 "glTexImage3D", offset, size);
2378 if (buffer && buffer->shm_id() != -1) {
2379 helper_->TexImage3D(
2380 target, level, internalformat, width, height, depth, format, type,
2381 buffer->shm_id(), buffer->shm_offset() + offset);
2382 buffer->set_last_usage_token(helper_->InsertToken());
2383 CheckGLError();
2385 return;
2388 // If there's no data just issue TexImage3D
2389 if (!pixels) {
2390 helper_->TexImage3D(
2391 target, level, internalformat, width, height, depth, format, type,
2392 0, 0);
2393 CheckGLError();
2394 return;
2397 // compute the advance bytes per row for the src pixels
2398 uint32 src_padded_row_size;
2399 if (unpack_row_length_ > 0) {
2400 if (!GLES2Util::ComputeImagePaddedRowSize(
2401 unpack_row_length_, format, type, unpack_alignment_,
2402 &src_padded_row_size)) {
2403 SetGLError(
2404 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2405 return;
2407 } else {
2408 src_padded_row_size = padded_row_size;
2410 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2412 // advance pixels pointer past the skip images/rows/pixels
2413 pixels = reinterpret_cast<const int8*>(pixels) +
2414 unpack_skip_images_ * src_padded_row_size * src_height +
2415 unpack_skip_rows_ * src_padded_row_size;
2416 if (unpack_skip_pixels_) {
2417 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2418 pixels = reinterpret_cast<const int8*>(pixels) +
2419 unpack_skip_pixels_ * group_size;
2422 // Check if we can send it all at once.
2423 int32_t shm_id = 0;
2424 uint32_t shm_offset = 0;
2425 void* buffer_pointer = nullptr;
2427 ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
2428 ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
2430 if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
2431 shm_id = transfer_alloc.shm_id();
2432 shm_offset = transfer_alloc.offset();
2433 buffer_pointer = transfer_alloc.address();
2434 } else {
2435 mapped_alloc.Reset(size);
2436 if (mapped_alloc.valid()) {
2437 transfer_alloc.Discard();
2439 mapped_alloc.SetFlushAfterRelease(true);
2440 shm_id = mapped_alloc.shm_id();
2441 shm_offset = mapped_alloc.offset();
2442 buffer_pointer = mapped_alloc.address();
2446 if (buffer_pointer) {
2447 for (GLsizei z = 0; z < depth; ++z) {
2448 // Only the last row of the last image is unpadded.
2449 uint32 src_unpadded_row_size =
2450 (z == depth - 1) ? unpadded_row_size : src_padded_row_size;
2451 CopyRectToBuffer(
2452 pixels, height, src_unpadded_row_size, src_padded_row_size,
2453 buffer_pointer, padded_row_size);
2454 pixels = reinterpret_cast<const int8*>(pixels) +
2455 src_padded_row_size * src_height;
2456 buffer_pointer = reinterpret_cast<int8*>(buffer_pointer) +
2457 padded_row_size * height;
2459 helper_->TexImage3D(
2460 target, level, internalformat, width, height, depth, format, type,
2461 shm_id, shm_offset);
2462 CheckGLError();
2463 return;
2466 // No, so send it using TexSubImage3D.
2467 helper_->TexImage3D(
2468 target, level, internalformat, width, height, depth, format, type,
2469 0, 0);
2470 TexSubImage3DImpl(
2471 target, level, 0, 0, 0, width, height, depth, format, type,
2472 unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &transfer_alloc,
2473 padded_row_size);
2474 CheckGLError();
2477 void GLES2Implementation::TexSubImage2D(
2478 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2479 GLsizei height, GLenum format, GLenum type, const void* pixels) {
2480 GPU_CLIENT_SINGLE_THREAD_CHECK();
2481 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
2482 << GLES2Util::GetStringTextureTarget(target) << ", "
2483 << level << ", "
2484 << xoffset << ", " << yoffset << ", "
2485 << width << ", " << height << ", "
2486 << GLES2Util::GetStringTextureFormat(format) << ", "
2487 << GLES2Util::GetStringPixelType(type) << ", "
2488 << static_cast<const void*>(pixels) << ")");
2490 if (level < 0 || height < 0 || width < 0) {
2491 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
2492 return;
2494 if (height == 0 || width == 0) {
2495 return;
2498 uint32 temp_size;
2499 uint32 unpadded_row_size;
2500 uint32 padded_row_size;
2501 if (!GLES2Util::ComputeImageDataSizes(
2502 width, height, 1, format, type, unpack_alignment_, &temp_size,
2503 &unpadded_row_size, &padded_row_size)) {
2504 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
2505 return;
2508 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2509 if (bound_pixel_unpack_transfer_buffer_id_) {
2510 GLuint offset = ToGLuint(pixels);
2511 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2512 bound_pixel_unpack_transfer_buffer_id_,
2513 "glTexSubImage2D", offset, temp_size);
2514 if (buffer && buffer->shm_id() != -1) {
2515 helper_->TexSubImage2D(
2516 target, level, xoffset, yoffset, width, height, format, type,
2517 buffer->shm_id(), buffer->shm_offset() + offset, false);
2518 buffer->set_last_usage_token(helper_->InsertToken());
2519 CheckGLError();
2521 return;
2524 // compute the advance bytes per row for the src pixels
2525 uint32 src_padded_row_size;
2526 if (unpack_row_length_ > 0) {
2527 if (!GLES2Util::ComputeImagePaddedRowSize(
2528 unpack_row_length_, format, type, unpack_alignment_,
2529 &src_padded_row_size)) {
2530 SetGLError(
2531 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2532 return;
2534 } else {
2535 src_padded_row_size = padded_row_size;
2538 // advance pixels pointer past the skip rows and skip pixels
2539 pixels = reinterpret_cast<const int8*>(pixels) +
2540 unpack_skip_rows_ * src_padded_row_size;
2541 if (unpack_skip_pixels_) {
2542 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2543 pixels = reinterpret_cast<const int8*>(pixels) +
2544 unpack_skip_pixels_ * group_size;
2547 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2548 TexSubImage2DImpl(
2549 target, level, xoffset, yoffset, width, height, format, type,
2550 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
2551 padded_row_size);
2552 CheckGLError();
2555 void GLES2Implementation::TexSubImage3D(
2556 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2557 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2558 const void* pixels) {
2559 GPU_CLIENT_SINGLE_THREAD_CHECK();
2560 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D("
2561 << GLES2Util::GetStringTextureTarget(target) << ", "
2562 << level << ", "
2563 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2564 << width << ", " << height << ", " << depth << ", "
2565 << GLES2Util::GetStringTextureFormat(format) << ", "
2566 << GLES2Util::GetStringPixelType(type) << ", "
2567 << static_cast<const void*>(pixels) << ")");
2569 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2570 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "dimension < 0");
2571 return;
2573 if (height == 0 || width == 0 || depth == 0) {
2574 return;
2577 uint32 temp_size;
2578 uint32 unpadded_row_size;
2579 uint32 padded_row_size;
2580 if (!GLES2Util::ComputeImageDataSizes(
2581 width, height, depth, format, type, unpack_alignment_, &temp_size,
2582 &unpadded_row_size, &padded_row_size)) {
2583 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "size to large");
2584 return;
2587 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2588 if (bound_pixel_unpack_transfer_buffer_id_) {
2589 GLuint offset = ToGLuint(pixels);
2590 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2591 bound_pixel_unpack_transfer_buffer_id_,
2592 "glTexSubImage3D", offset, temp_size);
2593 if (buffer && buffer->shm_id() != -1) {
2594 helper_->TexSubImage3D(
2595 target, level, xoffset, yoffset, zoffset, width, height, depth,
2596 format, type, buffer->shm_id(), buffer->shm_offset() + offset, false);
2597 buffer->set_last_usage_token(helper_->InsertToken());
2598 CheckGLError();
2600 return;
2603 // compute the advance bytes per row for the src pixels
2604 uint32 src_padded_row_size;
2605 if (unpack_row_length_ > 0) {
2606 if (!GLES2Util::ComputeImagePaddedRowSize(
2607 unpack_row_length_, format, type, unpack_alignment_,
2608 &src_padded_row_size)) {
2609 SetGLError(
2610 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2611 return;
2613 } else {
2614 src_padded_row_size = padded_row_size;
2616 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2618 // advance pixels pointer past the skip images/rows/pixels
2619 pixels = reinterpret_cast<const int8*>(pixels) +
2620 unpack_skip_images_ * src_padded_row_size * src_height +
2621 unpack_skip_rows_ * src_padded_row_size;
2622 if (unpack_skip_pixels_) {
2623 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2624 pixels = reinterpret_cast<const int8*>(pixels) +
2625 unpack_skip_pixels_ * group_size;
2628 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2629 TexSubImage3DImpl(
2630 target, level, xoffset, yoffset, zoffset, width, height, depth,
2631 format, type, unpadded_row_size, pixels, src_padded_row_size, GL_FALSE,
2632 &buffer, padded_row_size);
2633 CheckGLError();
2636 static GLint ComputeNumRowsThatFitInBuffer(
2637 uint32 padded_row_size, uint32 unpadded_row_size,
2638 unsigned int size, GLsizei remaining_rows) {
2639 DCHECK_GE(unpadded_row_size, 0u);
2640 if (padded_row_size == 0) {
2641 return 1;
2643 GLint num_rows = size / padded_row_size;
2644 if (num_rows + 1 == remaining_rows &&
2645 size - num_rows * padded_row_size >= unpadded_row_size) {
2646 num_rows++;
2648 return num_rows;
2651 void GLES2Implementation::TexSubImage2DImpl(
2652 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2653 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
2654 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
2655 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
2656 DCHECK(buffer);
2657 DCHECK_GE(level, 0);
2658 DCHECK_GT(height, 0);
2659 DCHECK_GT(width, 0);
2661 const int8* source = reinterpret_cast<const int8*>(pixels);
2662 // Transfer by rows.
2663 while (height) {
2664 unsigned int desired_size =
2665 buffer_padded_row_size * (height - 1) + unpadded_row_size;
2666 if (!buffer->valid() || buffer->size() == 0) {
2667 buffer->Reset(desired_size);
2668 if (!buffer->valid()) {
2669 return;
2673 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2674 buffer_padded_row_size, unpadded_row_size, buffer->size(), height);
2675 num_rows = std::min(num_rows, height);
2676 CopyRectToBuffer(
2677 source, num_rows, unpadded_row_size, pixels_padded_row_size,
2678 buffer->address(), buffer_padded_row_size);
2679 helper_->TexSubImage2D(
2680 target, level, xoffset, yoffset, width, num_rows, format, type,
2681 buffer->shm_id(), buffer->offset(), internal);
2682 buffer->Release();
2683 yoffset += num_rows;
2684 source += num_rows * pixels_padded_row_size;
2685 height -= num_rows;
2689 void GLES2Implementation::TexSubImage3DImpl(
2690 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei zoffset,
2691 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2692 uint32 unpadded_row_size, const void* pixels, uint32 pixels_padded_row_size,
2693 GLboolean internal, ScopedTransferBufferPtr* buffer,
2694 uint32 buffer_padded_row_size) {
2695 DCHECK(buffer);
2696 DCHECK_GE(level, 0);
2697 DCHECK_GT(height, 0);
2698 DCHECK_GT(width, 0);
2699 DCHECK_GT(depth, 0);
2700 const int8* source = reinterpret_cast<const int8*>(pixels);
2701 GLsizei total_rows = height * depth;
2702 GLint row_index = 0, depth_index = 0;
2703 while (total_rows) {
2704 // Each time, we either copy one or more images, or copy one or more rows
2705 // within a single image, depending on the buffer size limit.
2706 GLsizei max_rows;
2707 unsigned int desired_size;
2708 if (row_index > 0) {
2709 // We are in the middle of an image. Send the remaining of the image.
2710 max_rows = height - row_index;
2711 if (total_rows <= height) {
2712 // Last image, so last row is unpadded.
2713 desired_size = buffer_padded_row_size * (max_rows - 1) +
2714 unpadded_row_size;
2715 } else {
2716 desired_size = buffer_padded_row_size * max_rows;
2718 } else {
2719 // Send all the remaining data if possible.
2720 max_rows = total_rows;
2721 desired_size =
2722 buffer_padded_row_size * (max_rows - 1) + unpadded_row_size;
2724 if (!buffer->valid() || buffer->size() == 0) {
2725 buffer->Reset(desired_size);
2726 if (!buffer->valid()) {
2727 return;
2730 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2731 buffer_padded_row_size, unpadded_row_size, buffer->size(), total_rows);
2732 num_rows = std::min(num_rows, max_rows);
2733 GLint num_images = num_rows / height;
2734 GLsizei my_height, my_depth;
2735 if (num_images > 0) {
2736 num_rows = num_images * height;
2737 my_height = height;
2738 my_depth = num_images;
2739 } else {
2740 my_height = num_rows;
2741 my_depth = 1;
2744 if (num_images > 0) {
2745 int8* buffer_pointer = reinterpret_cast<int8*>(buffer->address());
2746 uint32 src_height =
2747 unpack_image_height_ > 0 ? unpack_image_height_ : height;
2748 uint32 image_size_dst = buffer_padded_row_size * height;
2749 uint32 image_size_src = pixels_padded_row_size * src_height;
2750 for (GLint ii = 0; ii < num_images; ++ii) {
2751 uint32 my_unpadded_row_size;
2752 if (total_rows == num_rows && ii + 1 == num_images)
2753 my_unpadded_row_size = unpadded_row_size;
2754 else
2755 my_unpadded_row_size = pixels_padded_row_size;
2756 CopyRectToBuffer(
2757 source + ii * image_size_src, my_height, my_unpadded_row_size,
2758 pixels_padded_row_size, buffer_pointer + ii * image_size_dst,
2759 buffer_padded_row_size);
2761 } else {
2762 uint32 my_unpadded_row_size;
2763 if (total_rows == num_rows)
2764 my_unpadded_row_size = unpadded_row_size;
2765 else
2766 my_unpadded_row_size = pixels_padded_row_size;
2767 CopyRectToBuffer(
2768 source, my_height, my_unpadded_row_size, pixels_padded_row_size,
2769 buffer->address(), buffer_padded_row_size);
2771 helper_->TexSubImage3D(
2772 target, level, xoffset, yoffset + row_index, zoffset + depth_index,
2773 width, my_height, my_depth,
2774 format, type, buffer->shm_id(), buffer->offset(), internal);
2775 buffer->Release();
2777 total_rows -= num_rows;
2778 if (total_rows > 0) {
2779 GLint num_image_paddings;
2780 if (num_images > 0) {
2781 DCHECK_EQ(row_index, 0);
2782 depth_index += num_images;
2783 num_image_paddings = num_images;
2784 } else {
2785 row_index = (row_index + my_height) % height;
2786 num_image_paddings = 0;
2787 if (my_height > 0 && row_index == 0) {
2788 depth_index++;
2789 num_image_paddings++;
2792 source += num_rows * pixels_padded_row_size;
2793 if (unpack_image_height_ > height && num_image_paddings > 0) {
2794 source += num_image_paddings * (unpack_image_height_ - height) *
2795 pixels_padded_row_size;
2801 bool GLES2Implementation::GetActiveAttribHelper(
2802 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2803 GLenum* type, char* name) {
2804 // Clear the bucket so if the command fails nothing will be in it.
2805 helper_->SetBucketSize(kResultBucketId, 0);
2806 typedef cmds::GetActiveAttrib::Result Result;
2807 Result* result = GetResultAs<Result*>();
2808 if (!result) {
2809 return false;
2811 // Set as failed so if the command fails we'll recover.
2812 result->success = false;
2813 helper_->GetActiveAttrib(program, index, kResultBucketId,
2814 GetResultShmId(), GetResultShmOffset());
2815 WaitForCmd();
2816 if (result->success) {
2817 if (size) {
2818 *size = result->size;
2820 if (type) {
2821 *type = result->type;
2823 if (length || name) {
2824 std::vector<int8> str;
2825 GetBucketContents(kResultBucketId, &str);
2826 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2827 std::max(static_cast<size_t>(0),
2828 str.size() - 1));
2829 if (length) {
2830 *length = max_size;
2832 if (name && bufsize > 0) {
2833 memcpy(name, &str[0], max_size);
2834 name[max_size] = '\0';
2838 return result->success != 0;
2841 void GLES2Implementation::GetActiveAttrib(
2842 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2843 GLenum* type, char* name) {
2844 GPU_CLIENT_SINGLE_THREAD_CHECK();
2845 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2846 << program << ", " << index << ", " << bufsize << ", "
2847 << static_cast<const void*>(length) << ", "
2848 << static_cast<const void*>(size) << ", "
2849 << static_cast<const void*>(type) << ", "
2850 << static_cast<const void*>(name) << ", ");
2851 if (bufsize < 0) {
2852 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
2853 return;
2855 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2856 bool success = share_group_->program_info_manager()->GetActiveAttrib(
2857 this, program, index, bufsize, length, size, type, name);
2858 if (success) {
2859 if (size) {
2860 GPU_CLIENT_LOG(" size: " << *size);
2862 if (type) {
2863 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2865 if (name) {
2866 GPU_CLIENT_LOG(" name: " << name);
2869 CheckGLError();
2872 bool GLES2Implementation::GetActiveUniformHelper(
2873 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2874 GLenum* type, char* name) {
2875 // Clear the bucket so if the command fails nothing will be in it.
2876 helper_->SetBucketSize(kResultBucketId, 0);
2877 typedef cmds::GetActiveUniform::Result Result;
2878 Result* result = GetResultAs<Result*>();
2879 if (!result) {
2880 return false;
2882 // Set as failed so if the command fails we'll recover.
2883 result->success = false;
2884 helper_->GetActiveUniform(program, index, kResultBucketId,
2885 GetResultShmId(), GetResultShmOffset());
2886 WaitForCmd();
2887 if (result->success) {
2888 if (size) {
2889 *size = result->size;
2891 if (type) {
2892 *type = result->type;
2894 if (length || name) {
2895 std::vector<int8> str;
2896 GetBucketContents(kResultBucketId, &str);
2897 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2898 std::max(static_cast<size_t>(0),
2899 str.size() - 1));
2900 if (length) {
2901 *length = max_size;
2903 if (name && bufsize > 0) {
2904 memcpy(name, &str[0], max_size);
2905 name[max_size] = '\0';
2909 return result->success != 0;
2912 void GLES2Implementation::GetActiveUniform(
2913 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2914 GLenum* type, char* name) {
2915 GPU_CLIENT_SINGLE_THREAD_CHECK();
2916 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2917 << program << ", " << index << ", " << bufsize << ", "
2918 << static_cast<const void*>(length) << ", "
2919 << static_cast<const void*>(size) << ", "
2920 << static_cast<const void*>(type) << ", "
2921 << static_cast<const void*>(name) << ", ");
2922 if (bufsize < 0) {
2923 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2924 return;
2926 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2927 bool success = share_group_->program_info_manager()->GetActiveUniform(
2928 this, program, index, bufsize, length, size, type, name);
2929 if (success) {
2930 if (size) {
2931 GPU_CLIENT_LOG(" size: " << *size);
2933 if (type) {
2934 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2936 if (name) {
2937 GPU_CLIENT_LOG(" name: " << name);
2940 CheckGLError();
2943 bool GLES2Implementation::GetActiveUniformBlockNameHelper(
2944 GLuint program, GLuint index, GLsizei bufsize,
2945 GLsizei* length, char* name) {
2946 DCHECK_LE(0, bufsize);
2947 // Clear the bucket so if the command fails nothing will be in it.
2948 helper_->SetBucketSize(kResultBucketId, 0);
2949 typedef cmds::GetActiveUniformBlockName::Result Result;
2950 Result* result = GetResultAs<Result*>();
2951 if (!result) {
2952 return false;
2954 // Set as failed so if the command fails we'll recover.
2955 *result = 0;
2956 helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
2957 GetResultShmId(), GetResultShmOffset());
2958 WaitForCmd();
2959 if (*result) {
2960 if (bufsize == 0) {
2961 if (length) {
2962 *length = 0;
2964 } else if (length || name) {
2965 std::vector<int8> str;
2966 GetBucketContents(kResultBucketId, &str);
2967 DCHECK_GT(str.size(), 0u);
2968 GLsizei max_size =
2969 std::min(bufsize, static_cast<GLsizei>(str.size())) - 1;
2970 if (length) {
2971 *length = max_size;
2973 if (name) {
2974 memcpy(name, &str[0], max_size);
2975 name[max_size] = '\0';
2979 return *result != 0;
2982 void GLES2Implementation::GetActiveUniformBlockName(
2983 GLuint program, GLuint index, GLsizei bufsize,
2984 GLsizei* length, char* name) {
2985 GPU_CLIENT_SINGLE_THREAD_CHECK();
2986 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
2987 << program << ", " << index << ", " << bufsize << ", "
2988 << static_cast<const void*>(length) << ", "
2989 << static_cast<const void*>(name) << ")");
2990 if (bufsize < 0) {
2991 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformBlockName", "bufsize < 0");
2992 return;
2994 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockName");
2995 bool success =
2996 share_group_->program_info_manager()->GetActiveUniformBlockName(
2997 this, program, index, bufsize, length, name);
2998 if (success) {
2999 if (name) {
3000 GPU_CLIENT_LOG(" name: " << name);
3003 CheckGLError();
3006 bool GLES2Implementation::GetActiveUniformBlockivHelper(
3007 GLuint program, GLuint index, GLenum pname, GLint* params) {
3008 typedef cmds::GetActiveUniformBlockiv::Result Result;
3009 Result* result = GetResultAs<Result*>();
3010 if (!result) {
3011 return false;
3013 result->SetNumResults(0);
3014 helper_->GetActiveUniformBlockiv(
3015 program, index, pname, GetResultShmId(), GetResultShmOffset());
3016 WaitForCmd();
3017 if (result->GetNumResults() > 0) {
3018 if (params) {
3019 result->CopyResult(params);
3021 GPU_CLIENT_LOG_CODE_BLOCK({
3022 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
3023 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3026 return true;
3028 return false;
3031 void GLES2Implementation::GetActiveUniformBlockiv(
3032 GLuint program, GLuint index, GLenum pname, GLint* params) {
3033 GPU_CLIENT_SINGLE_THREAD_CHECK();
3034 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
3035 << program << ", " << index << ", "
3036 << GLES2Util::GetStringUniformBlockParameter(pname) << ", "
3037 << static_cast<const void*>(params) << ")");
3038 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
3039 bool success =
3040 share_group_->program_info_manager()->GetActiveUniformBlockiv(
3041 this, program, index, pname, params);
3042 if (success) {
3043 if (params) {
3044 // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
3045 // be more than one value returned in params.
3046 GPU_CLIENT_LOG(" params: " << params[0]);
3049 CheckGLError();
3052 bool GLES2Implementation::GetActiveUniformsivHelper(
3053 GLuint program, GLsizei count, const GLuint* indices,
3054 GLenum pname, GLint* params) {
3055 typedef cmds::GetActiveUniformsiv::Result Result;
3056 Result* result = GetResultAs<Result*>();
3057 if (!result) {
3058 return false;
3060 result->SetNumResults(0);
3061 base::CheckedNumeric<size_t> bytes = static_cast<size_t>(count);
3062 bytes *= sizeof(GLuint);
3063 if (!bytes.IsValid()) {
3064 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count overflow");
3065 return false;
3067 SetBucketContents(kResultBucketId, indices, bytes.ValueOrDefault(0));
3068 helper_->GetActiveUniformsiv(
3069 program, kResultBucketId, pname, GetResultShmId(), GetResultShmOffset());
3070 WaitForCmd();
3071 bool success = result->GetNumResults() == count;
3072 if (success) {
3073 if (params) {
3074 result->CopyResult(params);
3076 GPU_CLIENT_LOG_CODE_BLOCK({
3077 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
3078 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3082 helper_->SetBucketSize(kResultBucketId, 0);
3083 return success;
3086 void GLES2Implementation::GetActiveUniformsiv(
3087 GLuint program, GLsizei count, const GLuint* indices,
3088 GLenum pname, GLint* params) {
3089 GPU_CLIENT_SINGLE_THREAD_CHECK();
3090 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv("
3091 << program << ", " << count << ", "
3092 << static_cast<const void*>(indices) << ", "
3093 << GLES2Util::GetStringUniformParameter(pname) << ", "
3094 << static_cast<const void*>(params) << ")");
3095 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
3096 if (count < 0) {
3097 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count < 0");
3098 return;
3100 bool success = share_group_->program_info_manager()->GetActiveUniformsiv(
3101 this, program, count, indices, pname, params);
3102 if (success) {
3103 if (params) {
3104 GPU_CLIENT_LOG_CODE_BLOCK({
3105 for (GLsizei ii = 0; ii < count; ++ii) {
3106 GPU_CLIENT_LOG(" " << ii << ": " << params[ii]);
3111 CheckGLError();
3114 void GLES2Implementation::GetAttachedShaders(
3115 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
3116 GPU_CLIENT_SINGLE_THREAD_CHECK();
3117 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
3118 << program << ", " << maxcount << ", "
3119 << static_cast<const void*>(count) << ", "
3120 << static_cast<const void*>(shaders) << ", ");
3121 if (maxcount < 0) {
3122 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
3123 return;
3125 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
3126 typedef cmds::GetAttachedShaders::Result Result;
3127 uint32 size = Result::ComputeSize(maxcount);
3128 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
3129 if (!result) {
3130 return;
3132 result->SetNumResults(0);
3133 helper_->GetAttachedShaders(
3134 program,
3135 transfer_buffer_->GetShmId(),
3136 transfer_buffer_->GetOffset(result),
3137 size);
3138 int32 token = helper_->InsertToken();
3139 WaitForCmd();
3140 if (count) {
3141 *count = result->GetNumResults();
3143 result->CopyResult(shaders);
3144 GPU_CLIENT_LOG_CODE_BLOCK({
3145 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3146 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3149 transfer_buffer_->FreePendingToken(result, token);
3150 CheckGLError();
3153 void GLES2Implementation::GetShaderPrecisionFormat(
3154 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
3155 GPU_CLIENT_SINGLE_THREAD_CHECK();
3156 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
3157 << GLES2Util::GetStringShaderType(shadertype) << ", "
3158 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
3159 << static_cast<const void*>(range) << ", "
3160 << static_cast<const void*>(precision) << ", ");
3161 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
3162 typedef cmds::GetShaderPrecisionFormat::Result Result;
3163 Result* result = GetResultAs<Result*>();
3164 if (!result) {
3165 return;
3168 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
3169 GLStaticState::ShaderPrecisionMap::iterator i =
3170 static_state_.shader_precisions.find(key);
3171 if (i != static_state_.shader_precisions.end()) {
3172 *result = i->second;
3173 } else {
3174 result->success = false;
3175 helper_->GetShaderPrecisionFormat(
3176 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
3177 WaitForCmd();
3178 if (result->success)
3179 static_state_.shader_precisions[key] = *result;
3182 if (result->success) {
3183 if (range) {
3184 range[0] = result->min_range;
3185 range[1] = result->max_range;
3186 GPU_CLIENT_LOG(" min_range: " << range[0]);
3187 GPU_CLIENT_LOG(" min_range: " << range[1]);
3189 if (precision) {
3190 precision[0] = result->precision;
3191 GPU_CLIENT_LOG(" min_range: " << precision[0]);
3194 CheckGLError();
3197 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
3198 const char* result = NULL;
3199 // Clears the bucket so if the command fails nothing will be in it.
3200 helper_->SetBucketSize(kResultBucketId, 0);
3201 helper_->GetString(name, kResultBucketId);
3202 std::string str;
3203 if (GetBucketAsString(kResultBucketId, &str)) {
3204 // Adds extensions implemented on client side only.
3205 switch (name) {
3206 case GL_EXTENSIONS:
3207 str += std::string(str.empty() ? "" : " ") +
3208 "GL_EXT_unpack_subimage "
3209 "GL_CHROMIUM_map_sub";
3210 if (capabilities_.image)
3211 str += " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
3212 if (capabilities_.future_sync_points)
3213 str += " GL_CHROMIUM_future_sync_point";
3214 break;
3215 default:
3216 break;
3219 // Because of WebGL the extensions can change. We have to cache each unique
3220 // result since we don't know when the client will stop referring to a
3221 // previous one it queries.
3222 GLStringMap::iterator it = gl_strings_.find(name);
3223 if (it == gl_strings_.end()) {
3224 std::set<std::string> strings;
3225 std::pair<GLStringMap::iterator, bool> insert_result =
3226 gl_strings_.insert(std::make_pair(name, strings));
3227 DCHECK(insert_result.second);
3228 it = insert_result.first;
3230 std::set<std::string>& string_set = it->second;
3231 std::set<std::string>::const_iterator sit = string_set.find(str);
3232 if (sit != string_set.end()) {
3233 result = sit->c_str();
3234 } else {
3235 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
3236 string_set.insert(str);
3237 DCHECK(insert_result.second);
3238 result = insert_result.first->c_str();
3241 return reinterpret_cast<const GLubyte*>(result);
3244 const GLubyte* GLES2Implementation::GetString(GLenum name) {
3245 GPU_CLIENT_SINGLE_THREAD_CHECK();
3246 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
3247 << GLES2Util::GetStringStringType(name) << ")");
3248 TRACE_EVENT0("gpu", "GLES2::GetString");
3249 const GLubyte* result = GetStringHelper(name);
3250 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
3251 CheckGLError();
3252 return result;
3255 bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
3256 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3257 GLenum* type, char* name) {
3258 // Clear the bucket so if the command fails nothing will be in it.
3259 helper_->SetBucketSize(kResultBucketId, 0);
3260 typedef cmds::GetTransformFeedbackVarying::Result Result;
3261 Result* result = GetResultAs<Result*>();
3262 if (!result) {
3263 return false;
3265 // Set as failed so if the command fails we'll recover.
3266 result->success = false;
3267 helper_->GetTransformFeedbackVarying(
3268 program, index, kResultBucketId, GetResultShmId(), GetResultShmOffset());
3269 WaitForCmd();
3270 if (result->success) {
3271 if (size) {
3272 *size = result->size;
3274 if (type) {
3275 *type = result->type;
3277 if (length || name) {
3278 std::vector<int8> str;
3279 GetBucketContents(kResultBucketId, &str);
3280 GLsizei max_size = std::min(bufsize, static_cast<GLsizei>(str.size()));
3281 if (max_size > 0) {
3282 --max_size;
3284 if (length) {
3285 *length = max_size;
3287 if (name) {
3288 if (max_size > 0) {
3289 memcpy(name, &str[0], max_size);
3290 name[max_size] = '\0';
3291 } else if (bufsize > 0) {
3292 name[0] = '\0';
3297 return result->success != 0;
3300 void GLES2Implementation::GetTransformFeedbackVarying(
3301 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3302 GLenum* type, char* name) {
3303 GPU_CLIENT_SINGLE_THREAD_CHECK();
3304 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
3305 << program << ", " << index << ", " << bufsize << ", "
3306 << static_cast<const void*>(length) << ", "
3307 << static_cast<const void*>(size) << ", "
3308 << static_cast<const void*>(type) << ", "
3309 << static_cast<const void*>(name) << ", ");
3310 if (bufsize < 0) {
3311 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVarying",
3312 "bufsize < 0");
3313 return;
3315 TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
3316 bool success =
3317 share_group_->program_info_manager()->GetTransformFeedbackVarying(
3318 this, program, index, bufsize, length, size, type, name);
3319 if (success) {
3320 if (size) {
3321 GPU_CLIENT_LOG(" size: " << *size);
3323 if (type) {
3324 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
3326 if (name) {
3327 GPU_CLIENT_LOG(" name: " << name);
3330 CheckGLError();
3333 void GLES2Implementation::GetUniformfv(
3334 GLuint program, GLint location, GLfloat* params) {
3335 GPU_CLIENT_SINGLE_THREAD_CHECK();
3336 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
3337 << program << ", " << location << ", "
3338 << static_cast<const void*>(params) << ")");
3339 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
3340 typedef cmds::GetUniformfv::Result Result;
3341 Result* result = GetResultAs<Result*>();
3342 if (!result) {
3343 return;
3345 result->SetNumResults(0);
3346 helper_->GetUniformfv(
3347 program, location, GetResultShmId(), GetResultShmOffset());
3348 WaitForCmd();
3349 result->CopyResult(params);
3350 GPU_CLIENT_LOG_CODE_BLOCK({
3351 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3352 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3355 CheckGLError();
3358 void GLES2Implementation::GetUniformiv(
3359 GLuint program, GLint location, GLint* params) {
3360 GPU_CLIENT_SINGLE_THREAD_CHECK();
3361 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
3362 << program << ", " << location << ", "
3363 << static_cast<const void*>(params) << ")");
3364 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
3365 typedef cmds::GetUniformiv::Result Result;
3366 Result* result = GetResultAs<Result*>();
3367 if (!result) {
3368 return;
3370 result->SetNumResults(0);
3371 helper_->GetUniformiv(
3372 program, location, GetResultShmId(), GetResultShmOffset());
3373 WaitForCmd();
3374 GetResultAs<cmds::GetUniformiv::Result*>()->CopyResult(params);
3375 GPU_CLIENT_LOG_CODE_BLOCK({
3376 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3377 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3380 CheckGLError();
3383 void GLES2Implementation::GetUniformuiv(
3384 GLuint program, GLint location, GLuint* params) {
3385 GPU_CLIENT_SINGLE_THREAD_CHECK();
3386 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformuiv("
3387 << program << ", " << location << ", "
3388 << static_cast<const void*>(params) << ")");
3389 TRACE_EVENT0("gpu", "GLES2::GetUniformuiv");
3390 typedef cmds::GetUniformuiv::Result Result;
3391 Result* result = GetResultAs<Result*>();
3392 if (!result) {
3393 return;
3395 result->SetNumResults(0);
3396 helper_->GetUniformuiv(
3397 program, location, GetResultShmId(), GetResultShmOffset());
3398 WaitForCmd();
3399 GetResultAs<cmds::GetUniformuiv::Result*>()->CopyResult(params);
3400 GPU_CLIENT_LOG_CODE_BLOCK({
3401 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3402 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3405 CheckGLError();
3408 void GLES2Implementation::ReadPixels(
3409 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
3410 GLenum type, void* pixels) {
3411 GPU_CLIENT_SINGLE_THREAD_CHECK();
3412 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
3413 << xoffset << ", " << yoffset << ", "
3414 << width << ", " << height << ", "
3415 << GLES2Util::GetStringReadPixelFormat(format) << ", "
3416 << GLES2Util::GetStringPixelType(type) << ", "
3417 << static_cast<const void*>(pixels) << ")");
3418 if (width < 0 || height < 0) {
3419 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
3420 return;
3422 if (width == 0 || height == 0) {
3423 return;
3426 // glReadPixel pads the size of each row of pixels by an amount specified by
3427 // glPixelStorei. So, we have to take that into account both in the fact that
3428 // the pixels returned from the ReadPixel command will include that padding
3429 // and that when we copy the results to the user's buffer we need to not
3430 // write those padding bytes but leave them as they are.
3432 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
3433 typedef cmds::ReadPixels::Result Result;
3435 int8* dest = reinterpret_cast<int8*>(pixels);
3436 uint32 temp_size;
3437 uint32 unpadded_row_size;
3438 uint32 padded_row_size;
3439 if (!GLES2Util::ComputeImageDataSizes(
3440 width, 2, 1, format, type, pack_alignment_, &temp_size,
3441 &unpadded_row_size, &padded_row_size)) {
3442 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
3443 return;
3446 if (bound_pixel_pack_transfer_buffer_id_) {
3447 GLuint offset = ToGLuint(pixels);
3448 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3449 bound_pixel_pack_transfer_buffer_id_,
3450 "glReadPixels", offset, padded_row_size * height);
3451 if (buffer && buffer->shm_id() != -1) {
3452 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
3453 buffer->shm_id(), buffer->shm_offset(),
3454 0, 0, true);
3455 CheckGLError();
3457 return;
3460 if (!pixels) {
3461 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
3462 return;
3465 // Transfer by rows.
3466 // The max rows we can transfer.
3467 while (height) {
3468 GLsizei desired_size = padded_row_size * (height - 1) + unpadded_row_size;
3469 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
3470 if (!buffer.valid()) {
3471 return;
3473 GLint num_rows = ComputeNumRowsThatFitInBuffer(
3474 padded_row_size, unpadded_row_size, buffer.size(), height);
3475 num_rows = std::min(num_rows, height);
3476 // NOTE: We must look up the address of the result area AFTER allocation
3477 // of the transfer buffer since the transfer buffer may be reallocated.
3478 Result* result = GetResultAs<Result*>();
3479 if (!result) {
3480 return;
3482 *result = 0; // mark as failed.
3483 helper_->ReadPixels(
3484 xoffset, yoffset, width, num_rows, format, type,
3485 buffer.shm_id(), buffer.offset(),
3486 GetResultShmId(), GetResultShmOffset(),
3487 false);
3488 WaitForCmd();
3489 if (*result != 0) {
3490 // when doing a y-flip we have to iterate through top-to-bottom chunks
3491 // of the dst. The service side handles reversing the rows within a
3492 // chunk.
3493 int8* rows_dst;
3494 if (pack_reverse_row_order_) {
3495 rows_dst = dest + (height - num_rows) * padded_row_size;
3496 } else {
3497 rows_dst = dest;
3499 // We have to copy 1 row at a time to avoid writing pad bytes.
3500 const int8* src = static_cast<const int8*>(buffer.address());
3501 for (GLint yy = 0; yy < num_rows; ++yy) {
3502 memcpy(rows_dst, src, unpadded_row_size);
3503 rows_dst += padded_row_size;
3504 src += padded_row_size;
3506 if (!pack_reverse_row_order_) {
3507 dest = rows_dst;
3510 // If it was not marked as successful exit.
3511 if (*result == 0) {
3512 return;
3514 yoffset += num_rows;
3515 height -= num_rows;
3517 CheckGLError();
3520 void GLES2Implementation::ActiveTexture(GLenum texture) {
3521 GPU_CLIENT_SINGLE_THREAD_CHECK();
3522 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
3523 << GLES2Util::GetStringEnum(texture) << ")");
3524 GLuint texture_index = texture - GL_TEXTURE0;
3525 if (texture_index >=
3526 static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
3527 SetGLErrorInvalidEnum(
3528 "glActiveTexture", texture, "texture");
3529 return;
3532 active_texture_unit_ = texture_index;
3533 helper_->ActiveTexture(texture);
3534 CheckGLError();
3537 void GLES2Implementation::GenBuffersHelper(
3538 GLsizei /* n */, const GLuint* /* buffers */) {
3541 void GLES2Implementation::GenFramebuffersHelper(
3542 GLsizei /* n */, const GLuint* /* framebuffers */) {
3545 void GLES2Implementation::GenRenderbuffersHelper(
3546 GLsizei /* n */, const GLuint* /* renderbuffers */) {
3549 void GLES2Implementation::GenTexturesHelper(
3550 GLsizei /* n */, const GLuint* /* textures */) {
3553 void GLES2Implementation::GenVertexArraysOESHelper(
3554 GLsizei n, const GLuint* arrays) {
3555 vertex_array_object_manager_->GenVertexArrays(n, arrays);
3558 void GLES2Implementation::GenQueriesEXTHelper(
3559 GLsizei /* n */, const GLuint* /* queries */) {
3562 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
3563 GLsizei /* n */,
3564 const GLuint* /* valuebuffers */) {
3567 void GLES2Implementation::GenSamplersHelper(
3568 GLsizei /* n */, const GLuint* /* samplers */) {
3571 void GLES2Implementation::GenTransformFeedbacksHelper(
3572 GLsizei /* n */, const GLuint* /* transformfeedbacks */) {
3575 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
3576 // generates a new resource. On newer versions of OpenGL they don't. The code
3577 // related to binding below will need to change if we switch to the new OpenGL
3578 // model. Specifically it assumes a bind will succeed which is always true in
3579 // the old model but possibly not true in the new model if another context has
3580 // deleted the resource.
3582 // NOTE #2: There is a bug in some BindXXXHelpers, that IDs might be marked as
3583 // used even when Bind has failed. However, the bug is minor compared to the
3584 // overhead & duplicated checking in client side.
3586 void GLES2Implementation::BindBufferHelper(
3587 GLenum target, GLuint buffer_id) {
3588 // TODO(gman): See note #1 above.
3589 bool changed = false;
3590 switch (target) {
3591 case GL_ARRAY_BUFFER:
3592 if (bound_array_buffer_ != buffer_id) {
3593 bound_array_buffer_ = buffer_id;
3594 changed = true;
3596 break;
3597 case GL_COPY_READ_BUFFER:
3598 if (bound_copy_read_buffer_ != buffer_id) {
3599 bound_copy_read_buffer_ = buffer_id;
3600 changed = true;
3602 break;
3603 case GL_COPY_WRITE_BUFFER:
3604 if (bound_copy_write_buffer_ != buffer_id) {
3605 bound_copy_write_buffer_ = buffer_id;
3606 changed = true;
3608 break;
3609 case GL_ELEMENT_ARRAY_BUFFER:
3610 changed = vertex_array_object_manager_->BindElementArray(buffer_id);
3611 break;
3612 case GL_PIXEL_PACK_BUFFER:
3613 if (bound_pixel_pack_buffer_ != buffer_id) {
3614 bound_pixel_pack_buffer_ = buffer_id;
3615 changed = true;
3617 break;
3618 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3619 bound_pixel_pack_transfer_buffer_id_ = buffer_id;
3620 break;
3621 case GL_PIXEL_UNPACK_BUFFER:
3622 if (bound_pixel_unpack_buffer_ != buffer_id) {
3623 bound_pixel_unpack_buffer_ = buffer_id;
3624 changed = true;
3626 break;
3627 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3628 bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
3629 break;
3630 case GL_TRANSFORM_FEEDBACK_BUFFER:
3631 if (bound_transform_feedback_buffer_ != buffer_id) {
3632 bound_transform_feedback_buffer_ = buffer_id;
3633 changed = true;
3635 break;
3636 case GL_UNIFORM_BUFFER:
3637 if (bound_uniform_buffer_ != buffer_id) {
3638 bound_uniform_buffer_ = buffer_id;
3639 changed = true;
3641 break;
3642 default:
3643 changed = true;
3644 break;
3646 // TODO(gman): See note #2 above.
3647 if (changed) {
3648 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3649 this, target, buffer_id, &GLES2Implementation::BindBufferStub);
3653 void GLES2Implementation::BindBufferStub(GLenum target, GLuint buffer) {
3654 helper_->BindBuffer(target, buffer);
3655 if (share_group_->bind_generates_resource())
3656 helper_->CommandBufferHelper::OrderingBarrier();
3659 void GLES2Implementation::BindBufferBaseHelper(
3660 GLenum target, GLuint index, GLuint buffer_id) {
3661 // TODO(zmo): See note #1 above.
3662 // TODO(zmo): See note #2 above.
3663 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3664 this, target, index, buffer_id, &GLES2Implementation::BindBufferBaseStub);
3667 void GLES2Implementation::BindBufferBaseStub(
3668 GLenum target, GLuint index, GLuint buffer) {
3669 helper_->BindBufferBase(target, index, buffer);
3670 if (share_group_->bind_generates_resource())
3671 helper_->CommandBufferHelper::Flush();
3674 void GLES2Implementation::BindBufferRangeHelper(
3675 GLenum target, GLuint index, GLuint buffer_id,
3676 GLintptr offset, GLsizeiptr size) {
3677 // TODO(zmo): See note #1 above.
3678 // TODO(zmo): See note #2 above.
3679 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3680 this, target, index, buffer_id, offset, size,
3681 &GLES2Implementation::BindBufferRangeStub);
3684 void GLES2Implementation::BindBufferRangeStub(
3685 GLenum target, GLuint index, GLuint buffer,
3686 GLintptr offset, GLsizeiptr size) {
3687 helper_->BindBufferRange(target, index, buffer, offset, size);
3688 if (share_group_->bind_generates_resource())
3689 helper_->CommandBufferHelper::Flush();
3692 void GLES2Implementation::BindFramebufferHelper(
3693 GLenum target, GLuint framebuffer) {
3694 // TODO(gman): See note #1 above.
3695 bool changed = false;
3696 switch (target) {
3697 case GL_FRAMEBUFFER:
3698 if (bound_framebuffer_ != framebuffer ||
3699 bound_read_framebuffer_ != framebuffer) {
3700 bound_framebuffer_ = framebuffer;
3701 bound_read_framebuffer_ = framebuffer;
3702 changed = true;
3704 break;
3705 case GL_READ_FRAMEBUFFER:
3706 if (!IsChromiumFramebufferMultisampleAvailable()) {
3707 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3708 return;
3710 if (bound_read_framebuffer_ != framebuffer) {
3711 bound_read_framebuffer_ = framebuffer;
3712 changed = true;
3714 break;
3715 case GL_DRAW_FRAMEBUFFER:
3716 if (!IsChromiumFramebufferMultisampleAvailable()) {
3717 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3718 return;
3720 if (bound_framebuffer_ != framebuffer) {
3721 bound_framebuffer_ = framebuffer;
3722 changed = true;
3724 break;
3725 default:
3726 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3727 return;
3730 if (changed) {
3731 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(
3732 this, target, framebuffer, &GLES2Implementation::BindFramebufferStub);
3736 void GLES2Implementation::BindFramebufferStub(GLenum target,
3737 GLuint framebuffer) {
3738 helper_->BindFramebuffer(target, framebuffer);
3739 if (share_group_->bind_generates_resource())
3740 helper_->CommandBufferHelper::OrderingBarrier();
3743 void GLES2Implementation::BindRenderbufferHelper(
3744 GLenum target, GLuint renderbuffer) {
3745 // TODO(gman): See note #1 above.
3746 bool changed = false;
3747 switch (target) {
3748 case GL_RENDERBUFFER:
3749 if (bound_renderbuffer_ != renderbuffer) {
3750 bound_renderbuffer_ = renderbuffer;
3751 changed = true;
3753 break;
3754 default:
3755 changed = true;
3756 break;
3758 // TODO(zmo): See note #2 above.
3759 if (changed) {
3760 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(
3761 this, target, renderbuffer,
3762 &GLES2Implementation::BindRenderbufferStub);
3766 void GLES2Implementation::BindRenderbufferStub(GLenum target,
3767 GLuint renderbuffer) {
3768 helper_->BindRenderbuffer(target, renderbuffer);
3769 if (share_group_->bind_generates_resource())
3770 helper_->CommandBufferHelper::OrderingBarrier();
3773 void GLES2Implementation::BindSamplerHelper(GLuint unit,
3774 GLuint sampler) {
3775 helper_->BindSampler(unit, sampler);
3778 void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
3779 // TODO(gman): See note #1 above.
3780 // TODO(gman): Change this to false once we figure out why it's failing
3781 // on daisy.
3782 bool changed = true;
3783 TextureUnit& unit = texture_units_[active_texture_unit_];
3784 switch (target) {
3785 case GL_TEXTURE_2D:
3786 if (unit.bound_texture_2d != texture) {
3787 unit.bound_texture_2d = texture;
3788 changed = true;
3790 break;
3791 case GL_TEXTURE_CUBE_MAP:
3792 if (unit.bound_texture_cube_map != texture) {
3793 unit.bound_texture_cube_map = texture;
3794 changed = true;
3796 break;
3797 case GL_TEXTURE_EXTERNAL_OES:
3798 if (unit.bound_texture_external_oes != texture) {
3799 unit.bound_texture_external_oes = texture;
3800 changed = true;
3802 break;
3803 default:
3804 changed = true;
3805 break;
3807 // TODO(gman): See note #2 above.
3808 if (changed) {
3809 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(
3810 this, target, texture, &GLES2Implementation::BindTextureStub);
3814 void GLES2Implementation::BindTextureStub(GLenum target, GLuint texture) {
3815 helper_->BindTexture(target, texture);
3816 if (share_group_->bind_generates_resource())
3817 helper_->CommandBufferHelper::OrderingBarrier();
3820 void GLES2Implementation::BindTransformFeedbackHelper(
3821 GLenum target, GLuint transformfeedback) {
3822 helper_->BindTransformFeedback(target, transformfeedback);
3825 void GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
3826 bool changed = false;
3827 if (vertex_array_object_manager_->BindVertexArray(array, &changed)) {
3828 if (changed) {
3829 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
3830 // because unlike other resources VertexArrayObject ids must
3831 // be generated by GenVertexArrays. A random id to Bind will not
3832 // generate a new object.
3833 helper_->BindVertexArrayOES(array);
3835 } else {
3836 SetGLError(
3837 GL_INVALID_OPERATION, "glBindVertexArrayOES",
3838 "id was not generated with glGenVertexArrayOES");
3842 void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
3843 GLuint valuebuffer) {
3844 bool changed = false;
3845 switch (target) {
3846 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
3847 if (bound_valuebuffer_ != valuebuffer) {
3848 bound_valuebuffer_ = valuebuffer;
3849 changed = true;
3851 break;
3852 default:
3853 changed = true;
3854 break;
3856 // TODO(gman): See note #2 above.
3857 if (changed) {
3858 GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(
3859 this, target, valuebuffer,
3860 &GLES2Implementation::BindValuebufferCHROMIUMStub);
3864 void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target,
3865 GLuint valuebuffer) {
3866 helper_->BindValuebufferCHROMIUM(target, valuebuffer);
3867 if (share_group_->bind_generates_resource())
3868 helper_->CommandBufferHelper::OrderingBarrier();
3871 void GLES2Implementation::UseProgramHelper(GLuint program) {
3872 if (current_program_ != program) {
3873 current_program_ = program;
3874 helper_->UseProgram(program);
3878 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
3879 return vertex_array_object_manager_->IsReservedId(id);
3882 void GLES2Implementation::DeleteBuffersHelper(
3883 GLsizei n, const GLuint* buffers) {
3884 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
3885 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
3886 SetGLError(
3887 GL_INVALID_VALUE,
3888 "glDeleteBuffers", "id not created by this context.");
3889 return;
3891 for (GLsizei ii = 0; ii < n; ++ii) {
3892 if (buffers[ii] == bound_array_buffer_) {
3893 bound_array_buffer_ = 0;
3895 if (buffers[ii] == bound_copy_read_buffer_) {
3896 bound_copy_read_buffer_ = 0;
3898 if (buffers[ii] == bound_copy_write_buffer_) {
3899 bound_copy_write_buffer_ = 0;
3901 if (buffers[ii] == bound_pixel_pack_buffer_) {
3902 bound_pixel_pack_buffer_ = 0;
3904 if (buffers[ii] == bound_pixel_unpack_buffer_) {
3905 bound_pixel_unpack_buffer_ = 0;
3907 if (buffers[ii] == bound_transform_feedback_buffer_) {
3908 bound_transform_feedback_buffer_ = 0;
3910 if (buffers[ii] == bound_uniform_buffer_) {
3911 bound_uniform_buffer_ = 0;
3913 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
3915 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
3916 if (buffer)
3917 RemoveTransferBuffer(buffer);
3919 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
3920 bound_pixel_unpack_transfer_buffer_id_ = 0;
3923 RemoveMappedBufferRangeById(buffers[ii]);
3927 void GLES2Implementation::DeleteBuffersStub(
3928 GLsizei n, const GLuint* buffers) {
3929 helper_->DeleteBuffersImmediate(n, buffers);
3933 void GLES2Implementation::DeleteFramebuffersHelper(
3934 GLsizei n, const GLuint* framebuffers) {
3935 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
3936 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
3937 SetGLError(
3938 GL_INVALID_VALUE,
3939 "glDeleteFramebuffers", "id not created by this context.");
3940 return;
3942 for (GLsizei ii = 0; ii < n; ++ii) {
3943 if (framebuffers[ii] == bound_framebuffer_) {
3944 bound_framebuffer_ = 0;
3946 if (framebuffers[ii] == bound_read_framebuffer_) {
3947 bound_read_framebuffer_ = 0;
3952 void GLES2Implementation::DeleteFramebuffersStub(
3953 GLsizei n, const GLuint* framebuffers) {
3954 helper_->DeleteFramebuffersImmediate(n, framebuffers);
3957 void GLES2Implementation::DeleteRenderbuffersHelper(
3958 GLsizei n, const GLuint* renderbuffers) {
3959 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
3960 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
3961 SetGLError(
3962 GL_INVALID_VALUE,
3963 "glDeleteRenderbuffers", "id not created by this context.");
3964 return;
3966 for (GLsizei ii = 0; ii < n; ++ii) {
3967 if (renderbuffers[ii] == bound_renderbuffer_) {
3968 bound_renderbuffer_ = 0;
3973 void GLES2Implementation::DeleteRenderbuffersStub(
3974 GLsizei n, const GLuint* renderbuffers) {
3975 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
3978 void GLES2Implementation::DeleteTexturesHelper(
3979 GLsizei n, const GLuint* textures) {
3980 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
3981 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
3982 SetGLError(
3983 GL_INVALID_VALUE,
3984 "glDeleteTextures", "id not created by this context.");
3985 return;
3987 for (GLsizei ii = 0; ii < n; ++ii) {
3988 for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
3989 ++tt) {
3990 TextureUnit& unit = texture_units_[tt];
3991 if (textures[ii] == unit.bound_texture_2d) {
3992 unit.bound_texture_2d = 0;
3994 if (textures[ii] == unit.bound_texture_cube_map) {
3995 unit.bound_texture_cube_map = 0;
3997 if (textures[ii] == unit.bound_texture_external_oes) {
3998 unit.bound_texture_external_oes = 0;
4004 void GLES2Implementation::DeleteTexturesStub(GLsizei n,
4005 const GLuint* textures) {
4006 helper_->DeleteTexturesImmediate(n, textures);
4009 void GLES2Implementation::DeleteVertexArraysOESHelper(
4010 GLsizei n, const GLuint* arrays) {
4011 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
4012 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
4013 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
4014 SetGLError(
4015 GL_INVALID_VALUE,
4016 "glDeleteVertexArraysOES", "id not created by this context.");
4017 return;
4021 void GLES2Implementation::DeleteVertexArraysOESStub(
4022 GLsizei n, const GLuint* arrays) {
4023 helper_->DeleteVertexArraysOESImmediate(n, arrays);
4026 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
4027 GLsizei n,
4028 const GLuint* valuebuffers) {
4029 if (!GetIdHandler(id_namespaces::kValuebuffers)
4030 ->FreeIds(this, n, valuebuffers,
4031 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
4032 SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
4033 "id not created by this context.");
4034 return;
4036 for (GLsizei ii = 0; ii < n; ++ii) {
4037 if (valuebuffers[ii] == bound_valuebuffer_) {
4038 bound_valuebuffer_ = 0;
4043 void GLES2Implementation::DeleteSamplersStub(
4044 GLsizei n, const GLuint* samplers) {
4045 helper_->DeleteSamplersImmediate(n, samplers);
4048 void GLES2Implementation::DeleteSamplersHelper(
4049 GLsizei n, const GLuint* samplers) {
4050 if (!GetIdHandler(id_namespaces::kSamplers)->FreeIds(
4051 this, n, samplers, &GLES2Implementation::DeleteSamplersStub)) {
4052 SetGLError(
4053 GL_INVALID_VALUE,
4054 "glDeleteSamplers", "id not created by this context.");
4055 return;
4059 void GLES2Implementation::DeleteTransformFeedbacksStub(
4060 GLsizei n, const GLuint* transformfeedbacks) {
4061 helper_->DeleteTransformFeedbacksImmediate(n, transformfeedbacks);
4064 void GLES2Implementation::DeleteTransformFeedbacksHelper(
4065 GLsizei n, const GLuint* transformfeedbacks) {
4066 if (!GetIdHandler(id_namespaces::kTransformFeedbacks)->FreeIds(
4067 this, n, transformfeedbacks,
4068 &GLES2Implementation::DeleteTransformFeedbacksStub)) {
4069 SetGLError(
4070 GL_INVALID_VALUE,
4071 "glDeleteTransformFeedbacks", "id not created by this context.");
4072 return;
4076 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
4077 GLsizei n,
4078 const GLuint* valuebuffers) {
4079 helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
4082 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
4083 GPU_CLIENT_SINGLE_THREAD_CHECK();
4084 GPU_CLIENT_LOG(
4085 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
4086 vertex_array_object_manager_->SetAttribEnable(index, false);
4087 helper_->DisableVertexAttribArray(index);
4088 CheckGLError();
4091 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
4092 GPU_CLIENT_SINGLE_THREAD_CHECK();
4093 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
4094 << index << ")");
4095 vertex_array_object_manager_->SetAttribEnable(index, true);
4096 helper_->EnableVertexAttribArray(index);
4097 CheckGLError();
4100 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
4101 GPU_CLIENT_SINGLE_THREAD_CHECK();
4102 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
4103 << GLES2Util::GetStringDrawMode(mode) << ", "
4104 << first << ", " << count << ")");
4105 if (count < 0) {
4106 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
4107 return;
4109 bool simulated = false;
4110 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
4111 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
4112 return;
4114 helper_->DrawArrays(mode, first, count);
4115 RestoreArrayBuffer(simulated);
4116 CheckGLError();
4119 void GLES2Implementation::GetVertexAttribfv(
4120 GLuint index, GLenum pname, GLfloat* params) {
4121 GPU_CLIENT_SINGLE_THREAD_CHECK();
4122 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
4123 << index << ", "
4124 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4125 << static_cast<const void*>(params) << ")");
4126 uint32 value = 0;
4127 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4128 *params = static_cast<GLfloat>(value);
4129 return;
4131 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
4132 typedef cmds::GetVertexAttribfv::Result Result;
4133 Result* result = GetResultAs<Result*>();
4134 if (!result) {
4135 return;
4137 result->SetNumResults(0);
4138 helper_->GetVertexAttribfv(
4139 index, pname, GetResultShmId(), GetResultShmOffset());
4140 WaitForCmd();
4141 result->CopyResult(params);
4142 GPU_CLIENT_LOG_CODE_BLOCK({
4143 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4144 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4147 CheckGLError();
4150 void GLES2Implementation::GetVertexAttribiv(
4151 GLuint index, GLenum pname, GLint* params) {
4152 GPU_CLIENT_SINGLE_THREAD_CHECK();
4153 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
4154 << index << ", "
4155 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4156 << static_cast<const void*>(params) << ")");
4157 uint32 value = 0;
4158 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4159 *params = static_cast<GLint>(value);
4160 return;
4162 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
4163 typedef cmds::GetVertexAttribiv::Result Result;
4164 Result* result = GetResultAs<Result*>();
4165 if (!result) {
4166 return;
4168 result->SetNumResults(0);
4169 helper_->GetVertexAttribiv(
4170 index, pname, GetResultShmId(), GetResultShmOffset());
4171 WaitForCmd();
4172 result->CopyResult(params);
4173 GPU_CLIENT_LOG_CODE_BLOCK({
4174 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4175 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4178 CheckGLError();
4181 void GLES2Implementation::GetVertexAttribIiv(
4182 GLuint index, GLenum pname, GLint* params) {
4183 GPU_CLIENT_SINGLE_THREAD_CHECK();
4184 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIiv("
4185 << index << ", "
4186 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4187 << static_cast<const void*>(params) << ")");
4188 uint32 value = 0;
4189 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4190 *params = static_cast<GLint>(value);
4191 return;
4193 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIiv");
4194 typedef cmds::GetVertexAttribiv::Result Result;
4195 Result* result = GetResultAs<Result*>();
4196 if (!result) {
4197 return;
4199 result->SetNumResults(0);
4200 helper_->GetVertexAttribIiv(
4201 index, pname, GetResultShmId(), GetResultShmOffset());
4202 WaitForCmd();
4203 result->CopyResult(params);
4204 GPU_CLIENT_LOG_CODE_BLOCK({
4205 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4206 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4209 CheckGLError();
4212 void GLES2Implementation::GetVertexAttribIuiv(
4213 GLuint index, GLenum pname, GLuint* params) {
4214 GPU_CLIENT_SINGLE_THREAD_CHECK();
4215 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIuiv("
4216 << index << ", "
4217 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4218 << static_cast<const void*>(params) << ")");
4219 uint32 value = 0;
4220 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4221 *params = static_cast<GLuint>(value);
4222 return;
4224 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIuiv");
4225 typedef cmds::GetVertexAttribiv::Result Result;
4226 Result* result = GetResultAs<Result*>();
4227 if (!result) {
4228 return;
4230 result->SetNumResults(0);
4231 helper_->GetVertexAttribIuiv(
4232 index, pname, GetResultShmId(), GetResultShmOffset());
4233 WaitForCmd();
4234 result->CopyResult(params);
4235 GPU_CLIENT_LOG_CODE_BLOCK({
4236 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4237 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4240 CheckGLError();
4243 GLenum GLES2Implementation::GetGraphicsResetStatusKHR() {
4244 GPU_CLIENT_SINGLE_THREAD_CHECK();
4245 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetGraphicsResetStatusKHR()");
4246 // If we can't make command buffers then the context is lost.
4247 if (gpu_control_->IsGpuChannelLost())
4248 return GL_UNKNOWN_CONTEXT_RESET_KHR;
4249 // Otherwise, check the command buffer if it is lost.
4250 if (helper_->IsContextLost()) {
4251 // TODO(danakj): We could GetLastState() off the CommandBuffer and return
4252 // the actual reason here if we cared to.
4253 return GL_UNKNOWN_CONTEXT_RESET_KHR;
4255 return GL_NO_ERROR;
4258 void GLES2Implementation::Swap() {
4259 SwapBuffers();
4262 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
4263 PostSubBufferCHROMIUM(
4264 sub_buffer.x(), sub_buffer.y(), sub_buffer.width(), sub_buffer.height());
4267 static GLenum GetGLESOverlayTransform(gfx::OverlayTransform plane_transform) {
4268 switch (plane_transform) {
4269 case gfx::OVERLAY_TRANSFORM_INVALID:
4270 break;
4271 case gfx::OVERLAY_TRANSFORM_NONE:
4272 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
4273 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
4274 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM;
4275 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
4276 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM;
4277 case gfx::OVERLAY_TRANSFORM_ROTATE_90:
4278 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM;
4279 case gfx::OVERLAY_TRANSFORM_ROTATE_180:
4280 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM;
4281 case gfx::OVERLAY_TRANSFORM_ROTATE_270:
4282 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM;
4284 NOTREACHED();
4285 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
4288 void GLES2Implementation::ScheduleOverlayPlane(
4289 int plane_z_order,
4290 gfx::OverlayTransform plane_transform,
4291 unsigned overlay_texture_id,
4292 const gfx::Rect& display_bounds,
4293 const gfx::RectF& uv_rect) {
4294 ScheduleOverlayPlaneCHROMIUM(plane_z_order,
4295 GetGLESOverlayTransform(plane_transform),
4296 overlay_texture_id,
4297 display_bounds.x(),
4298 display_bounds.y(),
4299 display_bounds.width(),
4300 display_bounds.height(),
4301 uv_rect.x(),
4302 uv_rect.y(),
4303 uv_rect.width(),
4304 uv_rect.height());
4307 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
4308 const char* feature) {
4309 GPU_CLIENT_SINGLE_THREAD_CHECK();
4310 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
4311 << feature << ")");
4312 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
4313 typedef cmds::EnableFeatureCHROMIUM::Result Result;
4314 Result* result = GetResultAs<Result*>();
4315 if (!result) {
4316 return false;
4318 *result = 0;
4319 SetBucketAsCString(kResultBucketId, feature);
4320 helper_->EnableFeatureCHROMIUM(
4321 kResultBucketId, GetResultShmId(), GetResultShmOffset());
4322 WaitForCmd();
4323 helper_->SetBucketSize(kResultBucketId, 0);
4324 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
4325 return *result != 0;
4328 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
4329 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
4330 GPU_CLIENT_SINGLE_THREAD_CHECK();
4331 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
4332 << target << ", " << offset << ", " << size << ", "
4333 << GLES2Util::GetStringEnum(access) << ")");
4334 // NOTE: target is NOT checked because the service will check it
4335 // and we don't know what targets are valid.
4336 if (access != GL_WRITE_ONLY) {
4337 SetGLErrorInvalidEnum(
4338 "glMapBufferSubDataCHROMIUM", access, "access");
4339 return NULL;
4341 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
4342 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
4343 return NULL;
4346 int32 shm_id;
4347 unsigned int shm_offset;
4348 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4349 if (!mem) {
4350 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
4351 return NULL;
4354 std::pair<MappedBufferMap::iterator, bool> result =
4355 mapped_buffers_.insert(std::make_pair(
4356 mem,
4357 MappedBuffer(
4358 access, shm_id, mem, shm_offset, target, offset, size)));
4359 DCHECK(result.second);
4360 GPU_CLIENT_LOG(" returned " << mem);
4361 return mem;
4364 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
4365 GPU_CLIENT_SINGLE_THREAD_CHECK();
4366 GPU_CLIENT_LOG(
4367 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
4368 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
4369 if (it == mapped_buffers_.end()) {
4370 SetGLError(
4371 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
4372 return;
4374 const MappedBuffer& mb = it->second;
4375 helper_->BufferSubData(
4376 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
4377 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
4378 mapped_buffers_.erase(it);
4379 CheckGLError();
4382 GLuint GLES2Implementation::GetBoundBufferHelper(GLenum target) {
4383 GLenum binding = GLES2Util::MapBufferTargetToBindingEnum(target);
4384 GLint id = 0;
4385 bool cached = GetHelper(binding, &id);
4386 DCHECK(cached);
4387 return static_cast<GLuint>(id);
4390 void GLES2Implementation::RemoveMappedBufferRangeByTarget(GLenum target) {
4391 GLuint buffer = GetBoundBufferHelper(target);
4392 RemoveMappedBufferRangeById(buffer);
4395 void GLES2Implementation::RemoveMappedBufferRangeById(GLuint buffer) {
4396 if (buffer > 0) {
4397 auto iter = mapped_buffer_range_map_.find(buffer);
4398 if (iter != mapped_buffer_range_map_.end() && iter->second.shm_memory) {
4399 mapped_memory_->FreePendingToken(
4400 iter->second.shm_memory, helper_->InsertToken());
4401 mapped_buffer_range_map_.erase(iter);
4406 void GLES2Implementation::ClearMappedBufferRangeMap() {
4407 for (auto& buffer_range : mapped_buffer_range_map_) {
4408 if (buffer_range.second.shm_memory) {
4409 mapped_memory_->FreePendingToken(
4410 buffer_range.second.shm_memory, helper_->InsertToken());
4413 mapped_buffer_range_map_.clear();
4416 void* GLES2Implementation::MapBufferRange(
4417 GLenum target, GLintptr offset, GLsizeiptr size, GLbitfield access) {
4418 GPU_CLIENT_SINGLE_THREAD_CHECK();
4419 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferRange("
4420 << GLES2Util::GetStringEnum(target) << ", " << offset << ", "
4421 << size << ", " << access << ")");
4422 if (!ValidateSize("glMapBufferRange", size) ||
4423 !ValidateOffset("glMapBufferRange", offset)) {
4424 return nullptr;
4427 int32 shm_id;
4428 unsigned int shm_offset;
4429 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4430 if (!mem) {
4431 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferRange", "out of memory");
4432 return nullptr;
4435 typedef cmds::MapBufferRange::Result Result;
4436 Result* result = GetResultAs<Result*>();
4437 *result = 0;
4438 helper_->MapBufferRange(target, offset, size, access, shm_id, shm_offset,
4439 GetResultShmId(), GetResultShmOffset());
4440 // TODO(zmo): For write only mode with MAP_INVALID_*_BIT, we should
4441 // consider an early return without WaitForCmd(). crbug.com/465804.
4442 WaitForCmd();
4443 if (*result) {
4444 const GLbitfield kInvalidateBits =
4445 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
4446 if ((access & kInvalidateBits) != 0) {
4447 // We do not read back from the buffer, therefore, we set the client
4448 // side memory to zero to avoid uninitialized data.
4449 memset(mem, 0, size);
4451 GLuint buffer = GetBoundBufferHelper(target);
4452 DCHECK_NE(0u, buffer);
4453 // glMapBufferRange fails on an already mapped buffer.
4454 DCHECK(mapped_buffer_range_map_.find(buffer) ==
4455 mapped_buffer_range_map_.end());
4456 auto iter = mapped_buffer_range_map_.insert(std::make_pair(
4457 buffer,
4458 MappedBuffer(access, shm_id, mem, shm_offset, target, offset, size)));
4459 DCHECK(iter.second);
4460 } else {
4461 mapped_memory_->Free(mem);
4462 mem = nullptr;
4465 GPU_CLIENT_LOG(" returned " << mem);
4466 CheckGLError();
4467 return mem;
4470 GLboolean GLES2Implementation::UnmapBuffer(GLenum target) {
4471 GPU_CLIENT_SINGLE_THREAD_CHECK();
4472 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapBuffer("
4473 << GLES2Util::GetStringEnum(target) << ")");
4474 switch (target) {
4475 case GL_ARRAY_BUFFER:
4476 case GL_ELEMENT_ARRAY_BUFFER:
4477 case GL_COPY_READ_BUFFER:
4478 case GL_COPY_WRITE_BUFFER:
4479 case GL_PIXEL_PACK_BUFFER:
4480 case GL_PIXEL_UNPACK_BUFFER:
4481 case GL_TRANSFORM_FEEDBACK_BUFFER:
4482 case GL_UNIFORM_BUFFER:
4483 break;
4484 default:
4485 SetGLError(GL_INVALID_ENUM, "glUnmapBuffer", "invalid target");
4486 return GL_FALSE;
4488 GLuint buffer = GetBoundBufferHelper(target);
4489 if (buffer == 0) {
4490 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "no buffer bound");
4491 return GL_FALSE;
4493 auto iter = mapped_buffer_range_map_.find(buffer);
4494 if (iter == mapped_buffer_range_map_.end()) {
4495 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "buffer is unmapped");
4496 return GL_FALSE;
4499 helper_->UnmapBuffer(target);
4500 RemoveMappedBufferRangeById(buffer);
4501 // TODO(zmo): There is a rare situation that data might be corrupted and
4502 // GL_FALSE should be returned. We lose context on that sitatuon, so we
4503 // don't have to WaitForCmd().
4504 GPU_CLIENT_LOG(" returned " << GL_TRUE);
4505 CheckGLError();
4506 return GL_TRUE;
4509 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
4510 GLenum target,
4511 GLint level,
4512 GLint xoffset,
4513 GLint yoffset,
4514 GLsizei width,
4515 GLsizei height,
4516 GLenum format,
4517 GLenum type,
4518 GLenum access) {
4519 GPU_CLIENT_SINGLE_THREAD_CHECK();
4520 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
4521 << target << ", " << level << ", "
4522 << xoffset << ", " << yoffset << ", "
4523 << width << ", " << height << ", "
4524 << GLES2Util::GetStringTextureFormat(format) << ", "
4525 << GLES2Util::GetStringPixelType(type) << ", "
4526 << GLES2Util::GetStringEnum(access) << ")");
4527 if (access != GL_WRITE_ONLY) {
4528 SetGLErrorInvalidEnum(
4529 "glMapTexSubImage2DCHROMIUM", access, "access");
4530 return NULL;
4532 // NOTE: target is NOT checked because the service will check it
4533 // and we don't know what targets are valid.
4534 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
4535 SetGLError(
4536 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
4537 return NULL;
4539 uint32 size;
4540 if (!GLES2Util::ComputeImageDataSizes(
4541 width, height, 1, format, type, unpack_alignment_, &size, NULL, NULL)) {
4542 SetGLError(
4543 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
4544 return NULL;
4546 int32 shm_id;
4547 unsigned int shm_offset;
4548 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4549 if (!mem) {
4550 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
4551 return NULL;
4554 std::pair<MappedTextureMap::iterator, bool> result =
4555 mapped_textures_.insert(std::make_pair(
4556 mem,
4557 MappedTexture(
4558 access, shm_id, mem, shm_offset,
4559 target, level, xoffset, yoffset, width, height, format, type)));
4560 DCHECK(result.second);
4561 GPU_CLIENT_LOG(" returned " << mem);
4562 return mem;
4565 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
4566 GPU_CLIENT_SINGLE_THREAD_CHECK();
4567 GPU_CLIENT_LOG(
4568 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
4569 MappedTextureMap::iterator it = mapped_textures_.find(mem);
4570 if (it == mapped_textures_.end()) {
4571 SetGLError(
4572 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
4573 return;
4575 const MappedTexture& mt = it->second;
4576 helper_->TexSubImage2D(
4577 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
4578 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
4579 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
4580 mapped_textures_.erase(it);
4581 CheckGLError();
4584 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
4585 float scale_factor) {
4586 GPU_CLIENT_SINGLE_THREAD_CHECK();
4587 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
4588 << width << ", " << height << ", " << scale_factor << ")");
4589 helper_->ResizeCHROMIUM(width, height, scale_factor);
4590 CheckGLError();
4593 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
4594 GPU_CLIENT_SINGLE_THREAD_CHECK();
4595 GPU_CLIENT_LOG("[" << GetLogPrefix()
4596 << "] glGetRequestableExtensionsCHROMIUM()");
4597 TRACE_EVENT0("gpu",
4598 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
4599 const char* result = NULL;
4600 // Clear the bucket so if the command fails nothing will be in it.
4601 helper_->SetBucketSize(kResultBucketId, 0);
4602 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
4603 std::string str;
4604 if (GetBucketAsString(kResultBucketId, &str)) {
4605 // The set of requestable extensions shrinks as we enable
4606 // them. Because we don't know when the client will stop referring
4607 // to a previous one it queries (see GetString) we need to cache
4608 // the unique results.
4609 std::set<std::string>::const_iterator sit =
4610 requestable_extensions_set_.find(str);
4611 if (sit != requestable_extensions_set_.end()) {
4612 result = sit->c_str();
4613 } else {
4614 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
4615 requestable_extensions_set_.insert(str);
4616 DCHECK(insert_result.second);
4617 result = insert_result.first->c_str();
4620 GPU_CLIENT_LOG(" returned " << result);
4621 return reinterpret_cast<const GLchar*>(result);
4624 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
4625 // with VirtualGL contexts.
4626 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
4627 GPU_CLIENT_SINGLE_THREAD_CHECK();
4628 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
4629 << extension << ")");
4630 SetBucketAsCString(kResultBucketId, extension);
4631 helper_->RequestExtensionCHROMIUM(kResultBucketId);
4632 helper_->SetBucketSize(kResultBucketId, 0);
4634 struct ExtensionCheck {
4635 const char* extension;
4636 ExtensionStatus* status;
4638 const ExtensionCheck checks[] = {
4640 "GL_ANGLE_pack_reverse_row_order",
4641 &angle_pack_reverse_row_order_status_,
4644 "GL_CHROMIUM_framebuffer_multisample",
4645 &chromium_framebuffer_multisample_,
4648 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
4649 for (size_t ii = 0; ii < kNumChecks; ++ii) {
4650 const ExtensionCheck& check = checks[ii];
4651 if (*check.status == kUnavailableExtensionStatus &&
4652 !strcmp(extension, check.extension)) {
4653 *check.status = kUnknownExtensionStatus;
4658 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
4659 GPU_CLIENT_SINGLE_THREAD_CHECK();
4660 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
4661 // Wait if this would add too many rate limit tokens.
4662 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
4663 helper_->WaitForToken(rate_limit_tokens_.front());
4664 rate_limit_tokens_.pop();
4666 rate_limit_tokens_.push(helper_->InsertToken());
4669 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
4670 GLuint program, std::vector<int8>* result) {
4671 DCHECK(result);
4672 // Clear the bucket so if the command fails nothing will be in it.
4673 helper_->SetBucketSize(kResultBucketId, 0);
4674 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
4675 GetBucketContents(kResultBucketId, result);
4678 void GLES2Implementation::GetProgramInfoCHROMIUM(
4679 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4680 GPU_CLIENT_SINGLE_THREAD_CHECK();
4681 if (bufsize < 0) {
4682 SetGLError(
4683 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
4684 return;
4686 if (size == NULL) {
4687 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
4688 return;
4690 // Make sure they've set size to 0 else the value will be undefined on
4691 // lost context.
4692 DCHECK_EQ(0, *size);
4693 std::vector<int8> result;
4694 GetProgramInfoCHROMIUMHelper(program, &result);
4695 if (result.empty()) {
4696 return;
4698 *size = result.size();
4699 if (!info) {
4700 return;
4702 if (static_cast<size_t>(bufsize) < result.size()) {
4703 SetGLError(GL_INVALID_OPERATION,
4704 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
4705 return;
4707 memcpy(info, &result[0], result.size());
4710 void GLES2Implementation::GetUniformBlocksCHROMIUMHelper(
4711 GLuint program, std::vector<int8>* result) {
4712 DCHECK(result);
4713 // Clear the bucket so if the command fails nothing will be in it.
4714 helper_->SetBucketSize(kResultBucketId, 0);
4715 helper_->GetUniformBlocksCHROMIUM(program, kResultBucketId);
4716 GetBucketContents(kResultBucketId, result);
4719 void GLES2Implementation::GetUniformBlocksCHROMIUM(
4720 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4721 GPU_CLIENT_SINGLE_THREAD_CHECK();
4722 if (bufsize < 0) {
4723 SetGLError(
4724 GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "bufsize less than 0.");
4725 return;
4727 if (size == NULL) {
4728 SetGLError(GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "size is null.");
4729 return;
4731 // Make sure they've set size to 0 else the value will be undefined on
4732 // lost context.
4733 DCHECK_EQ(0, *size);
4734 std::vector<int8> result;
4735 GetUniformBlocksCHROMIUMHelper(program, &result);
4736 if (result.empty()) {
4737 return;
4739 *size = result.size();
4740 if (!info) {
4741 return;
4743 if (static_cast<size_t>(bufsize) < result.size()) {
4744 SetGLError(GL_INVALID_OPERATION, "glGetUniformBlocksCHROMIUM",
4745 "bufsize is too small for result.");
4746 return;
4748 memcpy(info, &result[0], result.size());
4751 void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
4752 GLuint program, std::vector<int8>* result) {
4753 DCHECK(result);
4754 // Clear the bucket so if the command fails nothing will be in it.
4755 helper_->SetBucketSize(kResultBucketId, 0);
4756 helper_->GetUniformsES3CHROMIUM(program, kResultBucketId);
4757 GetBucketContents(kResultBucketId, result);
4760 void GLES2Implementation::GetUniformsES3CHROMIUM(
4761 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4762 GPU_CLIENT_SINGLE_THREAD_CHECK();
4763 if (bufsize < 0) {
4764 SetGLError(
4765 GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "bufsize less than 0.");
4766 return;
4768 if (size == NULL) {
4769 SetGLError(GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "size is null.");
4770 return;
4772 // Make sure they've set size to 0 else the value will be undefined on
4773 // lost context.
4774 DCHECK_EQ(0, *size);
4775 std::vector<int8> result;
4776 GetUniformsES3CHROMIUMHelper(program, &result);
4777 if (result.empty()) {
4778 return;
4780 *size = result.size();
4781 if (!info) {
4782 return;
4784 if (static_cast<size_t>(bufsize) < result.size()) {
4785 SetGLError(GL_INVALID_OPERATION,
4786 "glGetUniformsES3CHROMIUM", "bufsize is too small for result.");
4787 return;
4789 memcpy(info, &result[0], result.size());
4792 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
4793 GLuint program, std::vector<int8>* result) {
4794 DCHECK(result);
4795 // Clear the bucket so if the command fails nothing will be in it.
4796 helper_->SetBucketSize(kResultBucketId, 0);
4797 helper_->GetTransformFeedbackVaryingsCHROMIUM(program, kResultBucketId);
4798 GetBucketContents(kResultBucketId, result);
4801 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(
4802 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4803 GPU_CLIENT_SINGLE_THREAD_CHECK();
4804 if (bufsize < 0) {
4805 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4806 "bufsize less than 0.");
4807 return;
4809 if (size == NULL) {
4810 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4811 "size is null.");
4812 return;
4814 // Make sure they've set size to 0 else the value will be undefined on
4815 // lost context.
4816 DCHECK_EQ(0, *size);
4817 std::vector<int8> result;
4818 GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
4819 if (result.empty()) {
4820 return;
4822 *size = result.size();
4823 if (!info) {
4824 return;
4826 if (static_cast<size_t>(bufsize) < result.size()) {
4827 SetGLError(GL_INVALID_OPERATION, "glGetTransformFeedbackVaryingsCHROMIUM",
4828 "bufsize is too small for result.");
4829 return;
4831 memcpy(info, &result[0], result.size());
4834 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
4835 GPU_CLIENT_SINGLE_THREAD_CHECK();
4836 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
4837 << texture << ")");
4838 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
4839 helper_->CommandBufferHelper::Flush();
4840 return gpu_control_->CreateStreamTexture(texture);
4843 void GLES2Implementation::PostSubBufferCHROMIUM(
4844 GLint x, GLint y, GLint width, GLint height) {
4845 GPU_CLIENT_SINGLE_THREAD_CHECK();
4846 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
4847 << x << ", " << y << ", " << width << ", " << height << ")");
4848 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
4849 "width", width, "height", height);
4851 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
4852 swap_buffers_tokens_.push(helper_->InsertToken());
4853 helper_->PostSubBufferCHROMIUM(x, y, width, height);
4854 helper_->CommandBufferHelper::Flush();
4855 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
4856 helper_->WaitForToken(swap_buffers_tokens_.front());
4857 swap_buffers_tokens_.pop();
4861 void GLES2Implementation::DeleteQueriesEXTHelper(
4862 GLsizei n, const GLuint* queries) {
4863 for (GLsizei ii = 0; ii < n; ++ii) {
4864 query_tracker_->RemoveQuery(queries[ii]);
4865 query_id_allocator_->FreeID(queries[ii]);
4868 helper_->DeleteQueriesEXTImmediate(n, queries);
4871 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
4872 GPU_CLIENT_SINGLE_THREAD_CHECK();
4873 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
4875 // TODO(gman): To be spec compliant IDs from other contexts sharing
4876 // resources need to return true here even though you can't share
4877 // queries across contexts?
4878 return query_tracker_->GetQuery(id) != NULL;
4881 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
4882 GPU_CLIENT_SINGLE_THREAD_CHECK();
4883 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
4884 << GLES2Util::GetStringQueryTarget(target)
4885 << ", " << id << ")");
4887 switch (target) {
4888 case GL_COMMANDS_ISSUED_CHROMIUM:
4889 case GL_LATENCY_QUERY_CHROMIUM:
4890 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
4891 case GL_GET_ERROR_QUERY_CHROMIUM:
4892 break;
4893 case GL_COMMANDS_COMPLETED_CHROMIUM:
4894 if (!capabilities_.sync_query) {
4895 SetGLError(
4896 GL_INVALID_OPERATION, "glBeginQueryEXT",
4897 "not enabled for commands completed queries");
4898 return;
4900 break;
4901 case GL_ANY_SAMPLES_PASSED:
4902 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
4903 if (!capabilities_.occlusion_query_boolean) {
4904 SetGLError(
4905 GL_INVALID_OPERATION, "glBeginQueryEXT",
4906 "not enabled for occlusion queries");
4907 return;
4909 break;
4910 case GL_TIME_ELAPSED_EXT:
4911 if (!capabilities_.timer_queries) {
4912 SetGLError(
4913 GL_INVALID_OPERATION, "glBeginQueryEXT",
4914 "not enabled for timing queries");
4915 return;
4917 break;
4918 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
4919 if (capabilities_.major_version >= 3)
4920 break;
4921 // Fall through
4922 default:
4923 SetGLError(
4924 GL_INVALID_ENUM, "glBeginQueryEXT", "unknown query target");
4925 return;
4928 // if any outstanding queries INV_OP
4929 if (query_tracker_->GetCurrentQuery(target)) {
4930 SetGLError(
4931 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
4932 return;
4935 if (id == 0) {
4936 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
4937 return;
4940 if (!query_id_allocator_->InUse(id)) {
4941 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "invalid id");
4942 return;
4945 // Extra setups some targets might need.
4946 switch (target) {
4947 case GL_TIME_ELAPSED_EXT:
4948 if (!query_tracker_->SetDisjointSync(this)) {
4949 SetGLError(GL_OUT_OF_MEMORY,
4950 "glBeginQueryEXT",
4951 "buffer allocation failed");
4952 return;
4954 break;
4955 default:
4956 break;
4959 if (query_tracker_->BeginQuery(id, target, this))
4960 CheckGLError();
4963 void GLES2Implementation::EndQueryEXT(GLenum target) {
4964 GPU_CLIENT_SINGLE_THREAD_CHECK();
4965 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
4966 << GLES2Util::GetStringQueryTarget(target) << ")");
4967 // Don't do anything if the context is lost.
4968 if (helper_->IsContextLost()) {
4969 return;
4972 if (query_tracker_->EndQuery(target, this))
4973 CheckGLError();
4976 void GLES2Implementation::QueryCounterEXT(GLuint id, GLenum target) {
4977 GPU_CLIENT_SINGLE_THREAD_CHECK();
4978 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] QueryCounterEXT("
4979 << id
4980 << ", " << GLES2Util::GetStringQueryTarget(target) << ")");
4982 switch (target) {
4983 case GL_TIMESTAMP_EXT:
4984 if (!capabilities_.timer_queries) {
4985 SetGLError(
4986 GL_INVALID_OPERATION, "glQueryCounterEXT",
4987 "not enabled for timing queries");
4988 return;
4990 break;
4991 default:
4992 SetGLError(
4993 GL_INVALID_ENUM, "glQueryCounterEXT", "unknown query target");
4994 return;
4997 if (id == 0) {
4998 SetGLError(GL_INVALID_OPERATION, "glQueryCounterEXT", "id is 0");
4999 return;
5002 if (!query_id_allocator_->InUse(id)) {
5003 SetGLError(GL_INVALID_OPERATION, "glQueryCounterEXT", "invalid id");
5004 return;
5007 // Extra setups some targets might need.
5008 switch (target) {
5009 case GL_TIMESTAMP_EXT:
5010 if (!query_tracker_->SetDisjointSync(this)) {
5011 SetGLError(GL_OUT_OF_MEMORY,
5012 "glQueryCounterEXT",
5013 "buffer allocation failed");
5014 return;
5016 break;
5017 default:
5018 break;
5021 if (query_tracker_->QueryCounter(id, target, this))
5022 CheckGLError();
5025 void GLES2Implementation::GetQueryivEXT(
5026 GLenum target, GLenum pname, GLint* params) {
5027 GPU_CLIENT_SINGLE_THREAD_CHECK();
5028 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
5029 << GLES2Util::GetStringQueryTarget(target) << ", "
5030 << GLES2Util::GetStringQueryParameter(pname) << ", "
5031 << static_cast<const void*>(params) << ")");
5032 if (pname == GL_QUERY_COUNTER_BITS_EXT) {
5033 // We convert all queries to CPU time so we support 64 bits.
5034 *params = 64;
5035 return;
5036 } else if (pname != GL_CURRENT_QUERY_EXT) {
5037 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
5038 return;
5040 QueryTracker::Query* query = query_tracker_->GetCurrentQuery(target);
5041 *params = query ? query->id() : 0;
5042 GPU_CLIENT_LOG(" " << *params);
5043 CheckGLError();
5046 void GLES2Implementation::GetQueryObjectivEXT(
5047 GLuint id, GLenum pname, GLint* params) {
5048 GLuint64 result = 0;
5049 if (GetQueryObjectValueHelper("glGetQueryObjectivEXT", id, pname, &result))
5050 *params = base::saturated_cast<GLint>(result);
5053 void GLES2Implementation::GetQueryObjectuivEXT(
5054 GLuint id, GLenum pname, GLuint* params) {
5055 GLuint64 result = 0;
5056 if (GetQueryObjectValueHelper("glGetQueryObjectuivEXT", id, pname, &result))
5057 *params = base::saturated_cast<GLuint>(result);
5060 void GLES2Implementation::GetQueryObjecti64vEXT(
5061 GLuint id, GLenum pname, GLint64* params) {
5062 GLuint64 result = 0;
5063 if (GetQueryObjectValueHelper("glGetQueryObjectiv64vEXT", id, pname, &result))
5064 *params = base::saturated_cast<GLint64>(result);
5067 void GLES2Implementation::GetQueryObjectui64vEXT(
5068 GLuint id, GLenum pname, GLuint64* params) {
5069 GLuint64 result = 0;
5070 if (GetQueryObjectValueHelper("glGetQueryObjectui64vEXT", id, pname, &result))
5071 *params = result;
5074 void GLES2Implementation::SetDisjointValueSyncCHROMIUM() {
5075 query_tracker_->SetDisjointSync(this);
5078 void GLES2Implementation::DrawArraysInstancedANGLE(
5079 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
5080 GPU_CLIENT_SINGLE_THREAD_CHECK();
5081 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
5082 << GLES2Util::GetStringDrawMode(mode) << ", "
5083 << first << ", " << count << ", " << primcount << ")");
5084 if (count < 0) {
5085 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
5086 return;
5088 if (primcount < 0) {
5089 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
5090 return;
5092 if (primcount == 0) {
5093 return;
5095 bool simulated = false;
5096 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
5097 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
5098 &simulated)) {
5099 return;
5101 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
5102 RestoreArrayBuffer(simulated);
5103 CheckGLError();
5106 void GLES2Implementation::DrawElementsInstancedANGLE(
5107 GLenum mode, GLsizei count, GLenum type, const void* indices,
5108 GLsizei primcount) {
5109 GPU_CLIENT_SINGLE_THREAD_CHECK();
5110 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
5111 << GLES2Util::GetStringDrawMode(mode) << ", "
5112 << count << ", "
5113 << GLES2Util::GetStringIndexType(type) << ", "
5114 << static_cast<const void*>(indices) << ", "
5115 << primcount << ")");
5116 if (count < 0) {
5117 SetGLError(GL_INVALID_VALUE,
5118 "glDrawElementsInstancedANGLE", "count less than 0.");
5119 return;
5121 if (count == 0) {
5122 return;
5124 if (primcount < 0) {
5125 SetGLError(GL_INVALID_VALUE,
5126 "glDrawElementsInstancedANGLE", "primcount < 0");
5127 return;
5129 if (primcount == 0) {
5130 return;
5132 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
5133 !ValidateOffset("glDrawElementsInstancedANGLE",
5134 reinterpret_cast<GLintptr>(indices))) {
5135 return;
5137 GLuint offset = 0;
5138 bool simulated = false;
5139 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
5140 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
5141 indices, &offset, &simulated)) {
5142 return;
5144 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
5145 RestoreElementAndArrayBuffers(simulated);
5146 CheckGLError();
5149 void GLES2Implementation::GenMailboxCHROMIUM(
5150 GLbyte* mailbox) {
5151 GPU_CLIENT_SINGLE_THREAD_CHECK();
5152 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
5153 << static_cast<const void*>(mailbox) << ")");
5154 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
5156 gpu::Mailbox result = gpu::Mailbox::Generate();
5157 memcpy(mailbox, result.name, sizeof(result.name));
5160 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target,
5161 const GLbyte* data) {
5162 GPU_CLIENT_SINGLE_THREAD_CHECK();
5163 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
5164 << static_cast<const void*>(data) << ")");
5165 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5166 DCHECK(mailbox.Verify()) << "ProduceTextureCHROMIUM was passed a "
5167 "mailbox that was not generated by "
5168 "GenMailboxCHROMIUM.";
5169 helper_->ProduceTextureCHROMIUMImmediate(target, data);
5170 CheckGLError();
5173 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
5174 GLuint texture, GLenum target, const GLbyte* data) {
5175 GPU_CLIENT_SINGLE_THREAD_CHECK();
5176 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
5177 << static_cast<const void*>(data) << ")");
5178 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5179 DCHECK(mailbox.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
5180 "mailbox that was not generated by "
5181 "GenMailboxCHROMIUM.";
5182 helper_->ProduceTextureDirectCHROMIUMImmediate(texture, target, data);
5183 CheckGLError();
5186 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target,
5187 const GLbyte* data) {
5188 GPU_CLIENT_SINGLE_THREAD_CHECK();
5189 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
5190 << static_cast<const void*>(data) << ")");
5191 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5192 DCHECK(mailbox.Verify()) << "ConsumeTextureCHROMIUM was passed a "
5193 "mailbox that was not generated by "
5194 "GenMailboxCHROMIUM.";
5195 helper_->ConsumeTextureCHROMIUMImmediate(target, data);
5196 CheckGLError();
5199 GLuint GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
5200 GLenum target, const GLbyte* data) {
5201 GPU_CLIENT_SINGLE_THREAD_CHECK();
5202 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
5203 << static_cast<const void*>(data) << ")");
5204 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5205 DCHECK(mailbox.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
5206 "mailbox that was not generated by "
5207 "GenMailboxCHROMIUM.";
5208 GLuint client_id;
5209 GetIdHandler(id_namespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
5210 helper_->CreateAndConsumeTextureCHROMIUMImmediate(target,
5211 client_id, data);
5212 if (share_group_->bind_generates_resource())
5213 helper_->CommandBufferHelper::Flush();
5214 CheckGLError();
5215 return client_id;
5218 void GLES2Implementation::PushGroupMarkerEXT(
5219 GLsizei length, const GLchar* marker) {
5220 GPU_CLIENT_SINGLE_THREAD_CHECK();
5221 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
5222 << length << ", " << marker << ")");
5223 if (!marker) {
5224 marker = "";
5226 SetBucketAsString(
5227 kResultBucketId,
5228 (length ? std::string(marker, length) : std::string(marker)));
5229 helper_->PushGroupMarkerEXT(kResultBucketId);
5230 helper_->SetBucketSize(kResultBucketId, 0);
5231 debug_marker_manager_.PushGroup(
5232 length ? std::string(marker, length) : std::string(marker));
5235 void GLES2Implementation::InsertEventMarkerEXT(
5236 GLsizei length, const GLchar* marker) {
5237 GPU_CLIENT_SINGLE_THREAD_CHECK();
5238 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
5239 << length << ", " << marker << ")");
5240 if (!marker) {
5241 marker = "";
5243 SetBucketAsString(
5244 kResultBucketId,
5245 (length ? std::string(marker, length) : std::string(marker)));
5246 helper_->InsertEventMarkerEXT(kResultBucketId);
5247 helper_->SetBucketSize(kResultBucketId, 0);
5248 debug_marker_manager_.SetMarker(
5249 length ? std::string(marker, length) : std::string(marker));
5252 void GLES2Implementation::PopGroupMarkerEXT() {
5253 GPU_CLIENT_SINGLE_THREAD_CHECK();
5254 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
5255 helper_->PopGroupMarkerEXT();
5256 debug_marker_manager_.PopGroup();
5259 void GLES2Implementation::TraceBeginCHROMIUM(
5260 const char* category_name, const char* trace_name) {
5261 GPU_CLIENT_SINGLE_THREAD_CHECK();
5262 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
5263 << category_name << ", " << trace_name << ")");
5264 SetBucketAsCString(kResultBucketId, category_name);
5265 SetBucketAsCString(kResultBucketId + 1, trace_name);
5266 helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1);
5267 helper_->SetBucketSize(kResultBucketId, 0);
5268 helper_->SetBucketSize(kResultBucketId + 1, 0);
5269 current_trace_stack_++;
5272 void GLES2Implementation::TraceEndCHROMIUM() {
5273 GPU_CLIENT_SINGLE_THREAD_CHECK();
5274 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
5275 if (current_trace_stack_ == 0) {
5276 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
5277 "missing begin trace");
5278 return;
5280 helper_->TraceEndCHROMIUM();
5281 current_trace_stack_--;
5284 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
5285 GPU_CLIENT_SINGLE_THREAD_CHECK();
5286 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
5287 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
5288 switch (target) {
5289 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
5290 if (access != GL_READ_ONLY) {
5291 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
5292 return NULL;
5294 break;
5295 default:
5296 SetGLError(
5297 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
5298 return NULL;
5300 GLuint buffer_id;
5301 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
5302 if (!buffer_id) {
5303 return NULL;
5305 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
5306 if (!buffer) {
5307 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
5308 return NULL;
5310 if (buffer->mapped()) {
5311 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
5312 return NULL;
5314 // Here we wait for previous transfer operations to be finished.
5315 if (buffer->last_usage_token()) {
5316 helper_->WaitForToken(buffer->last_usage_token());
5317 buffer->set_last_usage_token(0);
5319 buffer->set_mapped(true);
5321 GPU_CLIENT_LOG(" returned " << buffer->address());
5322 CheckGLError();
5323 return buffer->address();
5326 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
5327 GPU_CLIENT_SINGLE_THREAD_CHECK();
5328 GPU_CLIENT_LOG(
5329 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
5330 GLuint buffer_id;
5331 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
5332 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
5334 if (!buffer_id) {
5335 return false;
5337 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
5338 if (!buffer) {
5339 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
5340 return false;
5342 if (!buffer->mapped()) {
5343 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
5344 return false;
5346 buffer->set_mapped(false);
5347 CheckGLError();
5348 return true;
5351 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
5352 GPU_CLIENT_SINGLE_THREAD_CHECK();
5353 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
5354 helper_->CommandBufferHelper::Flush();
5355 return gpu_control_->InsertSyncPoint();
5358 GLuint GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
5359 GPU_CLIENT_SINGLE_THREAD_CHECK();
5360 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
5361 DCHECK(capabilities_.future_sync_points);
5362 return gpu_control_->InsertFutureSyncPoint();
5365 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point) {
5366 GPU_CLIENT_SINGLE_THREAD_CHECK();
5367 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
5368 << sync_point << ")");
5369 DCHECK(capabilities_.future_sync_points);
5370 helper_->CommandBufferHelper::Flush();
5371 gpu_control_->RetireSyncPoint(sync_point);
5374 uint64_t GLES2Implementation::ShareGroupTracingGUID() const {
5375 return share_group_->TracingGUID();
5378 namespace {
5380 bool ValidImageFormat(GLenum internalformat,
5381 const Capabilities& capabilities) {
5382 switch (internalformat) {
5383 case GL_ATC_RGB_AMD:
5384 case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
5385 return capabilities.texture_format_atc;
5386 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
5387 return capabilities.texture_format_dxt1;
5388 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
5389 return capabilities.texture_format_dxt5;
5390 case GL_ETC1_RGB8_OES:
5391 return capabilities.texture_format_etc1;
5392 case GL_R8:
5393 case GL_RGB:
5394 case GL_RGBA:
5395 case GL_RGB_YCBCR_422_CHROMIUM:
5396 case GL_BGRA_EXT:
5397 return true;
5398 default:
5399 return false;
5403 bool ValidImageUsage(GLenum usage) {
5404 switch (usage) {
5405 case GL_MAP_CHROMIUM:
5406 case GL_SCANOUT_CHROMIUM:
5407 return true;
5408 default:
5409 return false;
5413 } // namespace
5415 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer,
5416 GLsizei width,
5417 GLsizei height,
5418 GLenum internalformat) {
5419 if (width <= 0) {
5420 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
5421 return 0;
5424 if (height <= 0) {
5425 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
5426 return 0;
5429 if (!ValidImageFormat(internalformat, capabilities_)) {
5430 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "invalid format");
5431 return 0;
5434 int32_t image_id =
5435 gpu_control_->CreateImage(buffer, width, height, internalformat);
5436 if (image_id < 0) {
5437 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "image_id < 0");
5438 return 0;
5440 return image_id;
5443 GLuint GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer,
5444 GLsizei width,
5445 GLsizei height,
5446 GLenum internalformat) {
5447 GPU_CLIENT_SINGLE_THREAD_CHECK();
5448 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
5449 << ", " << height << ", "
5450 << GLES2Util::GetStringImageInternalFormat(internalformat)
5451 << ")");
5452 GLuint image_id =
5453 CreateImageCHROMIUMHelper(buffer, width, height, internalformat);
5454 CheckGLError();
5455 return image_id;
5458 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
5459 // Flush the command stream to make sure all pending commands
5460 // that may refer to the image_id are executed on the service side.
5461 helper_->CommandBufferHelper::Flush();
5462 gpu_control_->DestroyImage(image_id);
5465 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
5466 GPU_CLIENT_SINGLE_THREAD_CHECK();
5467 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
5468 << image_id << ")");
5469 DestroyImageCHROMIUMHelper(image_id);
5470 CheckGLError();
5473 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
5474 GLsizei width,
5475 GLsizei height,
5476 GLenum internalformat,
5477 GLenum usage) {
5478 if (width <= 0) {
5479 SetGLError(
5480 GL_INVALID_VALUE, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
5481 return 0;
5484 if (height <= 0) {
5485 SetGLError(GL_INVALID_VALUE,
5486 "glCreateGpuMemoryBufferImageCHROMIUM",
5487 "height <= 0");
5488 return 0;
5491 if (!ValidImageFormat(internalformat, capabilities_)) {
5492 SetGLError(GL_INVALID_VALUE,
5493 "glCreateGpuMemoryBufferImageCHROMIUM",
5494 "invalid format");
5495 return 0;
5498 if (!ValidImageUsage(usage)) {
5499 SetGLError(GL_INVALID_VALUE,
5500 "glCreateGpuMemoryBufferImageCHROMIUM",
5501 "invalid usage");
5502 return 0;
5505 // Flush the command stream to ensure ordering in case the newly
5506 // returned image_id has recently been in use with a different buffer.
5507 helper_->CommandBufferHelper::Flush();
5508 int32_t image_id = gpu_control_->CreateGpuMemoryBufferImage(
5509 width, height, internalformat, usage);
5510 if (image_id < 0) {
5511 SetGLError(GL_OUT_OF_MEMORY,
5512 "glCreateGpuMemoryBufferImageCHROMIUM",
5513 "image_id < 0");
5514 return 0;
5516 return image_id;
5519 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
5520 GLsizei width,
5521 GLsizei height,
5522 GLenum internalformat,
5523 GLenum usage) {
5524 GPU_CLIENT_SINGLE_THREAD_CHECK();
5525 GPU_CLIENT_LOG("[" << GetLogPrefix()
5526 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
5527 << ", " << height << ", "
5528 << GLES2Util::GetStringImageInternalFormat(internalformat)
5529 << ", " << GLES2Util::GetStringImageUsage(usage) << ")");
5530 GLuint image_id = CreateGpuMemoryBufferImageCHROMIUMHelper(
5531 width, height, internalformat, usage);
5532 CheckGLError();
5533 return image_id;
5536 bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
5537 if (size < 0) {
5538 SetGLError(GL_INVALID_VALUE, func, "size < 0");
5539 return false;
5541 if (!base::IsValueInRangeForNumericType<int32_t>(size)) {
5542 SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
5543 return false;
5545 return true;
5548 bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
5549 if (offset < 0) {
5550 SetGLError(GL_INVALID_VALUE, func, "offset < 0");
5551 return false;
5553 if (!base::IsValueInRangeForNumericType<int32_t>(offset)) {
5554 SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
5555 return false;
5557 return true;
5560 bool GLES2Implementation::GetSamplerParameterfvHelper(
5561 GLuint /* sampler */, GLenum /* pname */, GLfloat* /* params */) {
5562 // TODO(zmo): Implement client side caching.
5563 return false;
5566 bool GLES2Implementation::GetSamplerParameterivHelper(
5567 GLuint /* sampler */, GLenum /* pname */, GLint* /* params */) {
5568 // TODO(zmo): Implement client side caching.
5569 return false;
5572 bool GLES2Implementation::PackStringsToBucket(GLsizei count,
5573 const char* const* str,
5574 const GLint* length,
5575 const char* func_name) {
5576 DCHECK_LE(0, count);
5577 // Compute the total size.
5578 base::CheckedNumeric<size_t> total_size = count;
5579 total_size += 1;
5580 total_size *= sizeof(GLint);
5581 if (!total_size.IsValid()) {
5582 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5583 return false;
5585 size_t header_size = total_size.ValueOrDefault(0);
5586 std::vector<GLint> header(count + 1);
5587 header[0] = static_cast<GLint>(count);
5588 for (GLsizei ii = 0; ii < count; ++ii) {
5589 GLint len = 0;
5590 if (str[ii]) {
5591 len = (length && length[ii] >= 0)
5592 ? length[ii]
5593 : base::checked_cast<GLint>(strlen(str[ii]));
5595 total_size += len;
5596 total_size += 1; // NULL at the end of each char array.
5597 if (!total_size.IsValid()) {
5598 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5599 return false;
5601 header[ii + 1] = len;
5603 // Pack data into a bucket on the service.
5604 helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
5605 size_t offset = 0;
5606 for (GLsizei ii = 0; ii <= count; ++ii) {
5607 const char* src =
5608 (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
5609 base::CheckedNumeric<size_t> checked_size =
5610 (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
5611 if (ii > 0) {
5612 checked_size += 1; // NULL in the end.
5614 if (!checked_size.IsValid()) {
5615 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5616 return false;
5618 size_t size = checked_size.ValueOrDefault(0);
5619 while (size) {
5620 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
5621 if (!buffer.valid() || buffer.size() == 0) {
5622 SetGLError(GL_OUT_OF_MEMORY, func_name, "too large");
5623 return false;
5625 size_t copy_size = buffer.size();
5626 if (ii > 0 && buffer.size() == size)
5627 --copy_size;
5628 if (copy_size)
5629 memcpy(buffer.address(), src, copy_size);
5630 if (copy_size < buffer.size()) {
5631 // Append NULL in the end.
5632 DCHECK(copy_size + 1 == buffer.size());
5633 char* str = reinterpret_cast<char*>(buffer.address());
5634 str[copy_size] = 0;
5636 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
5637 buffer.shm_id(), buffer.offset());
5638 offset += buffer.size();
5639 src += buffer.size();
5640 size -= buffer.size();
5643 DCHECK_EQ(total_size.ValueOrDefault(0), offset);
5644 return true;
5647 void GLES2Implementation::UniformBlockBinding(GLuint program,
5648 GLuint index,
5649 GLuint binding) {
5650 GPU_CLIENT_SINGLE_THREAD_CHECK();
5651 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
5652 << ", " << index << ", " << binding << ")");
5653 share_group_->program_info_manager()->UniformBlockBinding(
5654 this, program, index, binding);
5655 helper_->UniformBlockBinding(program, index, binding);
5656 CheckGLError();
5659 GLenum GLES2Implementation::ClientWaitSync(
5660 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5661 GPU_CLIENT_SINGLE_THREAD_CHECK();
5662 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync
5663 << ", " << flags << ", " << timeout << ")");
5664 typedef cmds::ClientWaitSync::Result Result;
5665 Result* result = GetResultAs<Result*>();
5666 if (!result) {
5667 SetGLError(GL_OUT_OF_MEMORY, "ClientWaitSync", "");
5668 return GL_WAIT_FAILED;
5670 *result = GL_WAIT_FAILED;
5671 uint32_t v32_0 = 0, v32_1 = 0;
5672 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5673 helper_->ClientWaitSync(
5674 ToGLuint(sync), flags, v32_0, v32_1,
5675 GetResultShmId(), GetResultShmOffset());
5676 WaitForCmd();
5677 GPU_CLIENT_LOG("returned " << *result);
5678 CheckGLError();
5679 return *result;
5682 void GLES2Implementation::WaitSync(
5683 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5684 GPU_CLIENT_SINGLE_THREAD_CHECK();
5685 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync << ", "
5686 << flags << ", " << timeout << ")");
5687 uint32_t v32_0 = 0, v32_1 = 0;
5688 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5689 helper_->WaitSync(ToGLuint(sync), flags, v32_0, v32_1);
5690 CheckGLError();
5693 void GLES2Implementation::GetInternalformativ(
5694 GLenum target, GLenum format, GLenum pname,
5695 GLsizei buf_size, GLint* params) {
5696 GPU_CLIENT_SINGLE_THREAD_CHECK();
5697 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
5698 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetInternalformativ("
5699 << GLES2Util::GetStringRenderBufferTarget(target) << ", "
5700 << GLES2Util::GetStringRenderBufferFormat(format) << ", "
5701 << GLES2Util::GetStringInternalFormatParameter(pname)
5702 << ", " << buf_size << ", "
5703 << static_cast<const void*>(params) << ")");
5704 if (buf_size < 0) {
5705 SetGLError(GL_INVALID_VALUE, "glGetInternalformativ", "bufSize < 0");
5706 return;
5708 TRACE_EVENT0("gpu", "GLES2Implementation::GetInternalformativ");
5709 if (GetInternalformativHelper(target, format, pname, buf_size, params)) {
5710 return;
5712 typedef cmds::GetInternalformativ::Result Result;
5713 Result* result = GetResultAs<Result*>();
5714 if (!result) {
5715 return;
5717 result->SetNumResults(0);
5718 helper_->GetInternalformativ(target, format, pname,
5719 GetResultShmId(), GetResultShmOffset());
5720 WaitForCmd();
5721 GPU_CLIENT_LOG_CODE_BLOCK({
5722 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
5723 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
5726 if (buf_size > 0 && params) {
5727 GLint* data = result->GetData();
5728 if (buf_size >= result->GetNumResults()) {
5729 buf_size = result->GetNumResults();
5731 for (GLsizei ii = 0; ii < buf_size; ++ii) {
5732 params[ii] = data[ii];
5735 CheckGLError();
5738 GLuint GLES2Implementation::GenPathsCHROMIUM(GLsizei range) {
5739 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenPathsCHROMIUM(" << range
5740 << ")");
5741 GPU_CLIENT_SINGLE_THREAD_CHECK();
5742 static const char kFunctionName[] = "glGenPathsCHROMIUM";
5743 if (range < 0) {
5744 SetGLError(GL_INVALID_VALUE, kFunctionName, "range < 0");
5745 return 0;
5747 if (!base::IsValueInRangeForNumericType<int32_t>(range)) {
5748 SetGLError(GL_INVALID_OPERATION, kFunctionName, "range more than 32-bit");
5749 return 0;
5751 if (range == 0)
5752 return 0;
5754 GLuint first_client_id = 0;
5755 GetRangeIdHandler(id_namespaces::kPaths)
5756 ->MakeIdRange(this, range, &first_client_id);
5758 if (first_client_id == 0) {
5759 // Ran out of id space. Is not specified to raise any gl errors.
5760 return 0;
5763 helper_->GenPathsCHROMIUM(first_client_id, range);
5765 GPU_CLIENT_LOG_CODE_BLOCK({
5766 for (GLsizei i = 0; i < range; ++i) {
5767 GPU_CLIENT_LOG(" " << i << ": " << (first_client_id + i));
5770 CheckGLError();
5771 return first_client_id;
5774 void GLES2Implementation::DeletePathsCHROMIUM(GLuint first_client_id,
5775 GLsizei range) {
5776 GPU_CLIENT_SINGLE_THREAD_CHECK();
5777 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeletePathsCHROMIUM("
5778 << first_client_id << ", " << range << ")");
5779 static const char kFunctionName[] = "glDeletePathsCHROMIUM";
5781 if (range < 0) {
5782 SetGLError(GL_INVALID_VALUE, kFunctionName, "range < 0");
5783 return;
5785 if (!base::IsValueInRangeForNumericType<int32_t>(range)) {
5786 SetGLError(GL_INVALID_OPERATION, kFunctionName, "range more than 32-bit");
5787 return;
5789 if (range == 0)
5790 return;
5792 GLuint last_client_id;
5793 if (!SafeAddUint32(first_client_id, range - 1, &last_client_id)) {
5794 SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow");
5795 return;
5798 GetRangeIdHandler(id_namespaces::kPaths)
5799 ->FreeIdRange(this, first_client_id, range,
5800 &GLES2Implementation::DeletePathsCHROMIUMStub);
5801 CheckGLError();
5804 void GLES2Implementation::DeletePathsCHROMIUMStub(GLuint first_client_id,
5805 GLsizei range) {
5806 helper_->DeletePathsCHROMIUM(first_client_id, range);
5809 void GLES2Implementation::PathCommandsCHROMIUM(GLuint path,
5810 GLsizei num_commands,
5811 const GLubyte* commands,
5812 GLsizei num_coords,
5813 GLenum coord_type,
5814 const void* coords) {
5815 GPU_CLIENT_SINGLE_THREAD_CHECK();
5816 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPathCommandsCHROMIUM(" << path
5817 << ", " << num_commands << ", " << commands << ", "
5818 << num_coords << ", " << coords << ")");
5819 static const char kFunctionName[] = "glPathCommandsCHROMIUM";
5820 if (path == 0) {
5821 SetGLError(GL_INVALID_VALUE, kFunctionName, "invalid path object");
5822 return;
5824 if (num_commands < 0) {
5825 SetGLError(GL_INVALID_VALUE, kFunctionName, "numCommands < 0");
5826 return;
5828 if (num_commands != 0 && !commands) {
5829 SetGLError(GL_INVALID_VALUE, kFunctionName, "missing commands");
5830 return;
5832 if (num_coords < 0) {
5833 SetGLError(GL_INVALID_VALUE, kFunctionName, "numCoords < 0");
5834 return;
5836 if (num_coords != 0 && !coords) {
5837 SetGLError(GL_INVALID_VALUE, kFunctionName, "missing coords");
5838 return;
5840 uint32 coord_type_size = GLES2Util::GetGLTypeSizeForPathCoordType(coord_type);
5841 if (coord_type_size == 0) {
5842 SetGLError(GL_INVALID_ENUM, kFunctionName, "invalid coordType");
5843 return;
5845 if (num_commands == 0) {
5846 // No commands must mean no coords, thus nothing to memcpy. Let
5847 // the service validate the call. Validate coord_type above, so
5848 // that the parameters will be checked the in the same order
5849 // regardless of num_commands.
5850 helper_->PathCommandsCHROMIUM(path, num_commands, 0, 0, num_coords,
5851 coord_type, 0, 0);
5852 CheckGLError();
5853 return;
5856 uint32 coords_size;
5857 if (!SafeMultiplyUint32(num_coords, coord_type_size, &coords_size)) {
5858 SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow");
5859 return;
5862 uint32 required_buffer_size;
5863 if (!SafeAddUint32(coords_size, num_commands, &required_buffer_size)) {
5864 SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow");
5865 return;
5868 ScopedTransferBufferPtr buffer(required_buffer_size, helper_,
5869 transfer_buffer_);
5870 if (!buffer.valid() || buffer.size() < required_buffer_size) {
5871 SetGLError(GL_OUT_OF_MEMORY, kFunctionName, "too large");
5872 return;
5875 uint32 coords_shm_id = 0;
5876 uint32 coords_shm_offset = 0;
5877 // Copy coords first because they need more strict alignment.
5878 if (coords_size > 0) {
5879 unsigned char* coords_addr = static_cast<unsigned char*>(buffer.address());
5880 memcpy(coords_addr, coords, coords_size);
5881 coords_shm_id = buffer.shm_id();
5882 coords_shm_offset = buffer.offset();
5885 DCHECK(num_commands > 0);
5886 unsigned char* commands_addr =
5887 static_cast<unsigned char*>(buffer.address()) + coords_size;
5888 memcpy(commands_addr, commands, num_commands);
5890 helper_->PathCommandsCHROMIUM(path, num_commands, buffer.shm_id(),
5891 buffer.offset() + coords_size, num_coords,
5892 coord_type, coords_shm_id, coords_shm_offset);
5893 CheckGLError();
5896 // Include the auto-generated part of this file. We split this because it means
5897 // we can easily edit the non-auto generated parts right here in this file
5898 // instead of having to edit some template or the code generator.
5899 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
5901 } // namespace gles2
5902 } // namespace gpu