mac: Let IPhotoDataProvider::GetAlbumNames() return albums in a deterministic order.
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blobde46cf4a5b32b44cbdf53303266ddbeec22d91c8
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 : new ShareGroup(bind_generates_resource));
134 DCHECK(share_group_->bind_generates_resource() == bind_generates_resource);
136 memset(&reserved_ids_, 0, sizeof(reserved_ids_));
139 bool GLES2Implementation::Initialize(
140 unsigned int starting_transfer_buffer_size,
141 unsigned int min_transfer_buffer_size,
142 unsigned int max_transfer_buffer_size,
143 unsigned int mapped_memory_limit) {
144 TRACE_EVENT0("gpu", "GLES2Implementation::Initialize");
145 DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
146 DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
147 DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
149 if (!transfer_buffer_->Initialize(
150 starting_transfer_buffer_size,
151 kStartingOffset,
152 min_transfer_buffer_size,
153 max_transfer_buffer_size,
154 kAlignment,
155 kSizeToFlush)) {
156 return false;
159 mapped_memory_.reset(new MappedMemoryManager(helper_, mapped_memory_limit));
161 unsigned chunk_size = 2 * 1024 * 1024;
162 if (mapped_memory_limit != kNoLimit) {
163 // Use smaller chunks if the client is very memory conscientious.
164 chunk_size = std::min(mapped_memory_limit / 4, chunk_size);
166 mapped_memory_->set_chunk_size_multiple(chunk_size);
168 GLStaticState::ShaderPrecisionMap* shader_precisions =
169 &static_state_.shader_precisions;
170 capabilities_.VisitPrecisions([shader_precisions](
171 GLenum shader, GLenum type, Capabilities::ShaderPrecision* result) {
172 const GLStaticState::ShaderPrecisionKey key(shader, type);
173 cmds::GetShaderPrecisionFormat::Result cached_result = {
174 true, result->min_range, result->max_range, result->precision};
175 shader_precisions->insert(std::make_pair(key, cached_result));
178 util_.set_num_compressed_texture_formats(
179 capabilities_.num_compressed_texture_formats);
180 util_.set_num_shader_binary_formats(capabilities_.num_shader_binary_formats);
182 texture_units_.reset(
183 new TextureUnit[capabilities_.max_combined_texture_image_units]);
185 query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
186 buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
188 query_id_allocator_.reset(new IdAllocator());
189 if (support_client_side_arrays_) {
190 GetIdHandler(id_namespaces::kBuffers)->MakeIds(
191 this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
194 vertex_array_object_manager_.reset(new VertexArrayObjectManager(
195 capabilities_.max_vertex_attribs, reserved_ids_[0], reserved_ids_[1],
196 support_client_side_arrays_));
198 // GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
199 // on Client & Service.
200 if (capabilities_.bind_generates_resource_chromium !=
201 (share_group_->bind_generates_resource() ? 1 : 0)) {
202 SetGLError(GL_INVALID_OPERATION,
203 "Initialize",
204 "Service bind_generates_resource mismatch.");
205 return false;
208 // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
209 // Don't register a dump provider in these cases.
210 // TODO(ericrk): Get this working in Android Webview. crbug.com/517156
211 if (base::ThreadTaskRunnerHandle::IsSet()) {
212 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
213 this, base::ThreadTaskRunnerHandle::Get());
216 return true;
219 GLES2Implementation::~GLES2Implementation() {
220 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
221 this);
223 // Make sure the queries are finished otherwise we'll delete the
224 // shared memory (mapped_memory_) which will free the memory used
225 // by the queries. The GPU process when validating that memory is still
226 // shared will fail and abort (ie, it will stop running).
227 WaitForCmd();
228 query_tracker_.reset();
230 // GLES2Implementation::Initialize() could fail before allocating
231 // reserved_ids_, so we need delete them carefully.
232 if (support_client_side_arrays_ && reserved_ids_[0]) {
233 DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
236 // Release remaining BufferRange mem; This is when a MapBufferRange() is
237 // called but not the UnmapBuffer() pair.
238 ClearMappedBufferRangeMap();
240 // Release any per-context data in share group.
241 share_group_->FreeContext(this);
243 buffer_tracker_.reset();
245 // Make sure the commands make it the service.
246 WaitForCmd();
249 GLES2CmdHelper* GLES2Implementation::helper() const {
250 return helper_;
253 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
254 return share_group_->GetIdHandler(namespace_id);
257 RangeIdHandlerInterface* GLES2Implementation::GetRangeIdHandler(
258 int namespace_id) const {
259 return share_group_->GetRangeIdHandler(namespace_id);
262 IdAllocator* GLES2Implementation::GetIdAllocator(int namespace_id) const {
263 if (namespace_id == id_namespaces::kQueries)
264 return query_id_allocator_.get();
265 NOTREACHED();
266 return NULL;
269 void* GLES2Implementation::GetResultBuffer() {
270 return transfer_buffer_->GetResultBuffer();
273 int32 GLES2Implementation::GetResultShmId() {
274 return transfer_buffer_->GetShmId();
277 uint32 GLES2Implementation::GetResultShmOffset() {
278 return transfer_buffer_->GetResultOffset();
281 void GLES2Implementation::FreeUnusedSharedMemory() {
282 mapped_memory_->FreeUnused();
285 void GLES2Implementation::FreeEverything() {
286 WaitForCmd();
287 query_tracker_->Shrink();
288 FreeUnusedSharedMemory();
289 transfer_buffer_->Free();
290 helper_->FreeRingBuffer();
293 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
294 if (!helper_->IsContextLost())
295 callback.Run();
298 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
299 const base::Closure& callback) {
300 gpu_control_->SignalSyncPoint(
301 sync_point,
302 base::Bind(&GLES2Implementation::RunIfContextNotLost,
303 weak_ptr_factory_.GetWeakPtr(),
304 callback));
307 void GLES2Implementation::SignalQuery(uint32 query,
308 const base::Closure& callback) {
309 // Flush previously entered commands to ensure ordering with any
310 // glBeginQueryEXT() calls that may have been put into the context.
311 ShallowFlushCHROMIUM();
312 gpu_control_->SignalQuery(
313 query,
314 base::Bind(&GLES2Implementation::RunIfContextNotLost,
315 weak_ptr_factory_.GetWeakPtr(),
316 callback));
319 void GLES2Implementation::SetSurfaceVisible(bool visible) {
320 TRACE_EVENT1(
321 "gpu", "GLES2Implementation::SetSurfaceVisible", "visible", visible);
322 ShallowFlushCHROMIUM();
323 gpu_control_->SetSurfaceVisible(visible);
326 void GLES2Implementation::SetAggressivelyFreeResources(
327 bool aggressively_free_resources) {
328 TRACE_EVENT1("gpu", "GLES2Implementation::SetAggressivelyFreeResources",
329 "aggressively_free_resources", aggressively_free_resources);
330 aggressively_free_resources_ = aggressively_free_resources;
332 if (aggressively_free_resources_ && helper_->HaveRingBuffer()) {
333 // Ensure that we clean up as much cache memory as possible and fully flush.
334 FlushDriverCachesCHROMIUM();
336 // Flush will delete transfer buffer resources if
337 // |aggressively_free_resources_| is true.
338 Flush();
339 } else {
340 ShallowFlushCHROMIUM();
344 bool GLES2Implementation::OnMemoryDump(
345 const base::trace_event::MemoryDumpArgs& args,
346 base::trace_event::ProcessMemoryDump* pmd) {
347 if (!transfer_buffer_->HaveBuffer())
348 return true;
350 const uint64 tracing_process_id =
351 base::trace_event::MemoryDumpManager::GetInstance()
352 ->GetTracingProcessId();
354 base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
355 base::StringPrintf("gpu/transfer_buffer_memory/buffer_%d",
356 transfer_buffer_->GetShmId()));
357 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
358 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
359 transfer_buffer_->GetSize());
360 dump->AddScalar("free_size",
361 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
362 transfer_buffer_->GetFreeSize());
363 auto guid =
364 GetBufferGUIDForTracing(tracing_process_id, transfer_buffer_->GetShmId());
365 const int kImportance = 2;
366 pmd->CreateSharedGlobalAllocatorDump(guid);
367 pmd->AddOwnershipEdge(dump->guid(), guid, kImportance);
369 return true;
372 void GLES2Implementation::WaitForCmd() {
373 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
374 helper_->CommandBufferHelper::Finish();
377 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
378 const char* extensions =
379 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
380 if (!extensions)
381 return false;
383 int length = strlen(ext);
384 while (true) {
385 int n = strcspn(extensions, " ");
386 if (n == length && 0 == strncmp(ext, extensions, length)) {
387 return true;
389 if ('\0' == extensions[n]) {
390 return false;
392 extensions += n + 1;
396 bool GLES2Implementation::IsExtensionAvailableHelper(
397 const char* extension, ExtensionStatus* status) {
398 switch (*status) {
399 case kAvailableExtensionStatus:
400 return true;
401 case kUnavailableExtensionStatus:
402 return false;
403 default: {
404 bool available = IsExtensionAvailable(extension);
405 *status = available ? kAvailableExtensionStatus :
406 kUnavailableExtensionStatus;
407 return available;
412 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
413 return IsExtensionAvailableHelper(
414 "GL_ANGLE_pack_reverse_row_order",
415 &angle_pack_reverse_row_order_status_);
418 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
419 return IsExtensionAvailableHelper(
420 "GL_CHROMIUM_framebuffer_multisample",
421 &chromium_framebuffer_multisample_);
424 const std::string& GLES2Implementation::GetLogPrefix() const {
425 const std::string& prefix(debug_marker_manager_.GetMarker());
426 return prefix.empty() ? this_in_hex_ : prefix;
429 GLenum GLES2Implementation::GetError() {
430 GPU_CLIENT_SINGLE_THREAD_CHECK();
431 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
432 GLenum err = GetGLError();
433 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
434 return err;
437 GLenum GLES2Implementation::GetClientSideGLError() {
438 if (error_bits_ == 0) {
439 return GL_NO_ERROR;
442 GLenum error = GL_NO_ERROR;
443 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
444 if ((error_bits_ & mask) != 0) {
445 error = GLES2Util::GLErrorBitToGLError(mask);
446 break;
449 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
450 return error;
453 GLenum GLES2Implementation::GetGLError() {
454 TRACE_EVENT0("gpu", "GLES2::GetGLError");
455 // Check the GL error first, then our wrapped error.
456 typedef cmds::GetError::Result Result;
457 Result* result = GetResultAs<Result*>();
458 // If we couldn't allocate a result the context is lost.
459 if (!result) {
460 return GL_NO_ERROR;
462 *result = GL_NO_ERROR;
463 helper_->GetError(GetResultShmId(), GetResultShmOffset());
464 WaitForCmd();
465 GLenum error = *result;
466 if (error == GL_NO_ERROR) {
467 error = GetClientSideGLError();
468 } else {
469 // There was an error, clear the corresponding wrapped error.
470 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
472 return error;
475 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
476 void GLES2Implementation::FailGLError(GLenum error) {
477 if (error != GL_NO_ERROR) {
478 NOTREACHED() << "Error";
481 // NOTE: Calling GetGLError overwrites data in the result buffer.
482 void GLES2Implementation::CheckGLError() {
483 FailGLError(GetGLError());
485 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
487 void GLES2Implementation::SetGLError(
488 GLenum error, const char* function_name, const char* msg) {
489 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
490 << GLES2Util::GetStringError(error) << ": "
491 << function_name << ": " << msg);
492 FailGLError(error);
493 if (msg) {
494 last_error_ = msg;
496 if (error_message_callback_) {
497 std::string temp(GLES2Util::GetStringError(error) + " : " +
498 function_name + ": " + (msg ? msg : ""));
499 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
501 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
503 if (error == GL_OUT_OF_MEMORY && lose_context_when_out_of_memory_) {
504 helper_->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
505 GL_UNKNOWN_CONTEXT_RESET_ARB);
509 void GLES2Implementation::SetGLErrorInvalidEnum(
510 const char* function_name, GLenum value, const char* label) {
511 SetGLError(GL_INVALID_ENUM, function_name,
512 (std::string(label) + " was " +
513 GLES2Util::GetStringEnum(value)).c_str());
516 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
517 std::vector<int8>* data) {
518 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
519 DCHECK(data);
520 const uint32 kStartSize = 32 * 1024;
521 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
522 if (!buffer.valid()) {
523 return false;
525 typedef cmd::GetBucketStart::Result Result;
526 Result* result = GetResultAs<Result*>();
527 if (!result) {
528 return false;
530 *result = 0;
531 helper_->GetBucketStart(
532 bucket_id, GetResultShmId(), GetResultShmOffset(),
533 buffer.size(), buffer.shm_id(), buffer.offset());
534 WaitForCmd();
535 uint32 size = *result;
536 data->resize(size);
537 if (size > 0u) {
538 uint32 offset = 0;
539 while (size) {
540 if (!buffer.valid()) {
541 buffer.Reset(size);
542 if (!buffer.valid()) {
543 return false;
545 helper_->GetBucketData(
546 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
547 WaitForCmd();
549 uint32 size_to_copy = std::min(size, buffer.size());
550 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
551 offset += size_to_copy;
552 size -= size_to_copy;
553 buffer.Release();
555 // Free the bucket. This is not required but it does free up the memory.
556 // and we don't have to wait for the result so from the client's perspective
557 // it's cheap.
558 helper_->SetBucketSize(bucket_id, 0);
560 return true;
563 void GLES2Implementation::SetBucketContents(
564 uint32 bucket_id, const void* data, size_t size) {
565 DCHECK(data);
566 helper_->SetBucketSize(bucket_id, size);
567 if (size > 0u) {
568 uint32 offset = 0;
569 while (size) {
570 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
571 if (!buffer.valid()) {
572 return;
574 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
575 buffer.size());
576 helper_->SetBucketData(
577 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
578 offset += buffer.size();
579 size -= buffer.size();
584 void GLES2Implementation::SetBucketAsCString(
585 uint32 bucket_id, const char* str) {
586 // NOTE: strings are passed NULL terminated. That means the empty
587 // string will have a size of 1 and no-string will have a size of 0
588 if (str) {
589 SetBucketContents(bucket_id, str, strlen(str) + 1);
590 } else {
591 helper_->SetBucketSize(bucket_id, 0);
595 bool GLES2Implementation::GetBucketAsString(
596 uint32 bucket_id, std::string* str) {
597 DCHECK(str);
598 std::vector<int8> data;
599 // NOTE: strings are passed NULL terminated. That means the empty
600 // string will have a size of 1 and no-string will have a size of 0
601 if (!GetBucketContents(bucket_id, &data)) {
602 return false;
604 if (data.empty()) {
605 return false;
607 str->assign(&data[0], &data[0] + data.size() - 1);
608 return true;
611 void GLES2Implementation::SetBucketAsString(
612 uint32 bucket_id, const std::string& str) {
613 // NOTE: strings are passed NULL terminated. That means the empty
614 // string will have a size of 1 and no-string will have a size of 0
615 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
618 void GLES2Implementation::Disable(GLenum cap) {
619 GPU_CLIENT_SINGLE_THREAD_CHECK();
620 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
621 << GLES2Util::GetStringCapability(cap) << ")");
622 bool changed = false;
623 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
624 helper_->Disable(cap);
626 CheckGLError();
629 void GLES2Implementation::Enable(GLenum cap) {
630 GPU_CLIENT_SINGLE_THREAD_CHECK();
631 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
632 << GLES2Util::GetStringCapability(cap) << ")");
633 bool changed = false;
634 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
635 helper_->Enable(cap);
637 CheckGLError();
640 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
641 GPU_CLIENT_SINGLE_THREAD_CHECK();
642 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
643 << GLES2Util::GetStringCapability(cap) << ")");
644 bool state = false;
645 if (!state_.GetEnabled(cap, &state)) {
646 typedef cmds::IsEnabled::Result Result;
647 Result* result = GetResultAs<Result*>();
648 if (!result) {
649 return GL_FALSE;
651 *result = 0;
652 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
653 WaitForCmd();
654 state = (*result) != 0;
657 GPU_CLIENT_LOG("returned " << state);
658 CheckGLError();
659 return state;
662 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
663 // TODO(zmo): For all the BINDING points, there is a possibility where
664 // resources are shared among multiple contexts, that the cached points
665 // are invalid. It is not a problem for now, but once we allow resource
666 // sharing in WebGL, we need to implement a mechanism to allow correct
667 // client side binding points tracking. crbug.com/465562.
669 // ES2 parameters.
670 switch (pname) {
671 case GL_ACTIVE_TEXTURE:
672 *params = active_texture_unit_ + GL_TEXTURE0;
673 return true;
674 case GL_ARRAY_BUFFER_BINDING:
675 *params = bound_array_buffer_;
676 return true;
677 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
678 *params =
679 vertex_array_object_manager_->bound_element_array_buffer();
680 return true;
681 case GL_FRAMEBUFFER_BINDING:
682 *params = bound_framebuffer_;
683 return true;
684 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
685 *params = capabilities_.max_combined_texture_image_units;
686 return true;
687 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
688 *params = capabilities_.max_cube_map_texture_size;
689 return true;
690 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
691 *params = capabilities_.max_fragment_uniform_vectors;
692 return true;
693 case GL_MAX_RENDERBUFFER_SIZE:
694 *params = capabilities_.max_renderbuffer_size;
695 return true;
696 case GL_MAX_TEXTURE_IMAGE_UNITS:
697 *params = capabilities_.max_texture_image_units;
698 return true;
699 case GL_MAX_TEXTURE_SIZE:
700 *params = capabilities_.max_texture_size;
701 return true;
702 case GL_MAX_VARYING_VECTORS:
703 *params = capabilities_.max_varying_vectors;
704 return true;
705 case GL_MAX_VERTEX_ATTRIBS:
706 *params = capabilities_.max_vertex_attribs;
707 return true;
708 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
709 *params = capabilities_.max_vertex_texture_image_units;
710 return true;
711 case GL_MAX_VERTEX_UNIFORM_VECTORS:
712 *params = capabilities_.max_vertex_uniform_vectors;
713 return true;
714 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
715 *params = capabilities_.num_compressed_texture_formats;
716 return true;
717 case GL_NUM_SHADER_BINARY_FORMATS:
718 *params = capabilities_.num_shader_binary_formats;
719 return true;
720 case GL_RENDERBUFFER_BINDING:
721 *params = bound_renderbuffer_;
722 return true;
723 case GL_TEXTURE_BINDING_2D:
724 *params = texture_units_[active_texture_unit_].bound_texture_2d;
725 return true;
726 case GL_TEXTURE_BINDING_CUBE_MAP:
727 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
728 return true;
730 // Non-standard parameters.
731 case GL_TEXTURE_BINDING_EXTERNAL_OES:
732 *params =
733 texture_units_[active_texture_unit_].bound_texture_external_oes;
734 return true;
735 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
736 *params = bound_pixel_pack_transfer_buffer_id_;
737 return true;
738 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
739 *params = bound_pixel_unpack_transfer_buffer_id_;
740 return true;
741 case GL_READ_FRAMEBUFFER_BINDING:
742 if (IsChromiumFramebufferMultisampleAvailable()) {
743 *params = bound_read_framebuffer_;
744 return true;
746 break;
747 case GL_TIMESTAMP_EXT:
748 // We convert all GPU timestamps to CPU time.
749 *params = base::saturated_cast<GLint>(
750 (base::TraceTicks::Now() - base::TraceTicks()).InMicroseconds()
751 * base::Time::kNanosecondsPerMicrosecond);
752 return true;
753 case GL_GPU_DISJOINT_EXT:
754 *params = static_cast<GLint>(query_tracker_->CheckAndResetDisjoint());
755 return true;
757 // Non-cached parameters.
758 case GL_ALIASED_LINE_WIDTH_RANGE:
759 case GL_ALIASED_POINT_SIZE_RANGE:
760 case GL_ALPHA_BITS:
761 case GL_BLEND:
762 case GL_BLEND_COLOR:
763 case GL_BLEND_DST_ALPHA:
764 case GL_BLEND_DST_RGB:
765 case GL_BLEND_EQUATION_ALPHA:
766 case GL_BLEND_EQUATION_RGB:
767 case GL_BLEND_SRC_ALPHA:
768 case GL_BLEND_SRC_RGB:
769 case GL_BLUE_BITS:
770 case GL_COLOR_CLEAR_VALUE:
771 case GL_COLOR_WRITEMASK:
772 case GL_COMPRESSED_TEXTURE_FORMATS:
773 case GL_CULL_FACE:
774 case GL_CULL_FACE_MODE:
775 case GL_CURRENT_PROGRAM:
776 case GL_DEPTH_BITS:
777 case GL_DEPTH_CLEAR_VALUE:
778 case GL_DEPTH_FUNC:
779 case GL_DEPTH_RANGE:
780 case GL_DEPTH_TEST:
781 case GL_DEPTH_WRITEMASK:
782 case GL_DITHER:
783 case GL_FRONT_FACE:
784 case GL_GENERATE_MIPMAP_HINT:
785 case GL_GREEN_BITS:
786 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
787 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
788 case GL_LINE_WIDTH:
789 case GL_MAX_VIEWPORT_DIMS:
790 case GL_PACK_ALIGNMENT:
791 case GL_POLYGON_OFFSET_FACTOR:
792 case GL_POLYGON_OFFSET_FILL:
793 case GL_POLYGON_OFFSET_UNITS:
794 case GL_RED_BITS:
795 case GL_SAMPLE_ALPHA_TO_COVERAGE:
796 case GL_SAMPLE_BUFFERS:
797 case GL_SAMPLE_COVERAGE:
798 case GL_SAMPLE_COVERAGE_INVERT:
799 case GL_SAMPLE_COVERAGE_VALUE:
800 case GL_SAMPLES:
801 case GL_SCISSOR_BOX:
802 case GL_SCISSOR_TEST:
803 case GL_SHADER_BINARY_FORMATS:
804 case GL_SHADER_COMPILER:
805 case GL_STENCIL_BACK_FAIL:
806 case GL_STENCIL_BACK_FUNC:
807 case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
808 case GL_STENCIL_BACK_PASS_DEPTH_PASS:
809 case GL_STENCIL_BACK_REF:
810 case GL_STENCIL_BACK_VALUE_MASK:
811 case GL_STENCIL_BACK_WRITEMASK:
812 case GL_STENCIL_BITS:
813 case GL_STENCIL_CLEAR_VALUE:
814 case GL_STENCIL_FAIL:
815 case GL_STENCIL_FUNC:
816 case GL_STENCIL_PASS_DEPTH_FAIL:
817 case GL_STENCIL_PASS_DEPTH_PASS:
818 case GL_STENCIL_REF:
819 case GL_STENCIL_TEST:
820 case GL_STENCIL_VALUE_MASK:
821 case GL_STENCIL_WRITEMASK:
822 case GL_SUBPIXEL_BITS:
823 case GL_UNPACK_ALIGNMENT:
824 case GL_VIEWPORT:
825 return false;
826 default:
827 break;
830 if (capabilities_.major_version < 3) {
831 return false;
834 // ES3 parameters.
835 switch (pname) {
836 case GL_COPY_READ_BUFFER_BINDING:
837 *params = bound_copy_read_buffer_;
838 return true;
839 case GL_COPY_WRITE_BUFFER_BINDING:
840 *params = bound_copy_write_buffer_;
841 return true;
842 case GL_MAJOR_VERSION:
843 *params = capabilities_.major_version;
844 return true;
845 case GL_MAX_3D_TEXTURE_SIZE:
846 *params = capabilities_.max_3d_texture_size;
847 return true;
848 case GL_MAX_ARRAY_TEXTURE_LAYERS:
849 *params = capabilities_.max_array_texture_layers;
850 return true;
851 case GL_MAX_COLOR_ATTACHMENTS:
852 *params = capabilities_.max_color_attachments;
853 return true;
854 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
855 *params = static_cast<GLint>(
856 capabilities_.max_combined_fragment_uniform_components);
857 return true;
858 case GL_MAX_COMBINED_UNIFORM_BLOCKS:
859 *params = capabilities_.max_combined_uniform_blocks;
860 return true;
861 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
862 *params = static_cast<GLint>(
863 capabilities_.max_combined_vertex_uniform_components);
864 return true;
865 case GL_MAX_DRAW_BUFFERS:
866 *params = capabilities_.max_draw_buffers;
867 return true;
868 case GL_MAX_ELEMENT_INDEX:
869 *params = static_cast<GLint>(capabilities_.max_element_index);
870 return true;
871 case GL_MAX_ELEMENTS_INDICES:
872 *params = capabilities_.max_elements_indices;
873 return true;
874 case GL_MAX_ELEMENTS_VERTICES:
875 *params = capabilities_.max_elements_vertices;
876 return true;
877 case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
878 *params = capabilities_.max_fragment_input_components;
879 return true;
880 case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
881 *params = capabilities_.max_fragment_uniform_blocks;
882 return true;
883 case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
884 *params = capabilities_.max_fragment_uniform_components;
885 return true;
886 case GL_MAX_PROGRAM_TEXEL_OFFSET:
887 *params = capabilities_.max_program_texel_offset;
888 return true;
889 case GL_MAX_SAMPLES:
890 *params = capabilities_.max_samples;
891 return true;
892 case GL_MAX_SERVER_WAIT_TIMEOUT:
893 *params = static_cast<GLint>(capabilities_.max_server_wait_timeout);
894 return true;
895 case GL_MAX_TEXTURE_LOD_BIAS:
896 *params = static_cast<GLint>(capabilities_.max_texture_lod_bias);
897 return true;
898 case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
899 *params = capabilities_.max_transform_feedback_interleaved_components;
900 return true;
901 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
902 *params = capabilities_.max_transform_feedback_separate_attribs;
903 return true;
904 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
905 *params = capabilities_.max_transform_feedback_separate_components;
906 return true;
907 case GL_MAX_UNIFORM_BLOCK_SIZE:
908 *params = static_cast<GLint>(capabilities_.max_uniform_block_size);
909 return true;
910 case GL_MAX_UNIFORM_BUFFER_BINDINGS:
911 *params = capabilities_.max_uniform_buffer_bindings;
912 return true;
913 case GL_MAX_VARYING_COMPONENTS:
914 *params = capabilities_.max_varying_components;
915 return true;
916 case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
917 *params = capabilities_.max_vertex_output_components;
918 return true;
919 case GL_MAX_VERTEX_UNIFORM_BLOCKS:
920 *params = capabilities_.max_vertex_uniform_blocks;
921 return true;
922 case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
923 *params = capabilities_.max_vertex_uniform_components;
924 return true;
925 case GL_MIN_PROGRAM_TEXEL_OFFSET:
926 *params = capabilities_.min_program_texel_offset;
927 return true;
928 case GL_MINOR_VERSION:
929 *params = capabilities_.minor_version;
930 return true;
931 case GL_NUM_EXTENSIONS:
932 *params = capabilities_.num_extensions;
933 return true;
934 case GL_NUM_PROGRAM_BINARY_FORMATS:
935 *params = capabilities_.num_program_binary_formats;
936 return true;
937 case GL_PIXEL_PACK_BUFFER_BINDING:
938 *params = bound_pixel_pack_buffer_;
939 return true;
940 case GL_PIXEL_UNPACK_BUFFER_BINDING:
941 *params = bound_pixel_unpack_buffer_;
942 return true;
943 case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
944 *params = bound_transform_feedback_buffer_;
945 return true;
946 case GL_UNIFORM_BUFFER_BINDING:
947 *params = bound_uniform_buffer_;
948 return true;
949 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
950 *params = capabilities_.uniform_buffer_offset_alignment;
951 return true;
953 // Non-cached ES3 parameters.
954 case GL_DRAW_BUFFER0:
955 case GL_DRAW_BUFFER1:
956 case GL_DRAW_BUFFER2:
957 case GL_DRAW_BUFFER3:
958 case GL_DRAW_BUFFER4:
959 case GL_DRAW_BUFFER5:
960 case GL_DRAW_BUFFER6:
961 case GL_DRAW_BUFFER7:
962 case GL_DRAW_BUFFER8:
963 case GL_DRAW_BUFFER9:
964 case GL_DRAW_BUFFER10:
965 case GL_DRAW_BUFFER11:
966 case GL_DRAW_BUFFER12:
967 case GL_DRAW_BUFFER13:
968 case GL_DRAW_BUFFER14:
969 case GL_DRAW_BUFFER15:
970 case GL_DRAW_FRAMEBUFFER_BINDING:
971 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
972 case GL_PACK_ROW_LENGTH:
973 case GL_PACK_SKIP_PIXELS:
974 case GL_PACK_SKIP_ROWS:
975 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
976 case GL_PROGRAM_BINARY_FORMATS:
977 case GL_RASTERIZER_DISCARD:
978 case GL_READ_BUFFER:
979 case GL_READ_FRAMEBUFFER_BINDING:
980 case GL_SAMPLER_BINDING:
981 case GL_TEXTURE_BINDING_2D_ARRAY:
982 case GL_TEXTURE_BINDING_3D:
983 case GL_TRANSFORM_FEEDBACK_BINDING:
984 case GL_TRANSFORM_FEEDBACK_ACTIVE:
985 case GL_TRANSFORM_FEEDBACK_PAUSED:
986 case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
987 case GL_TRANSFORM_FEEDBACK_BUFFER_START:
988 case GL_UNIFORM_BUFFER_SIZE:
989 case GL_UNIFORM_BUFFER_START:
990 case GL_UNPACK_IMAGE_HEIGHT:
991 case GL_UNPACK_ROW_LENGTH:
992 case GL_UNPACK_SKIP_IMAGES:
993 case GL_UNPACK_SKIP_PIXELS:
994 case GL_UNPACK_SKIP_ROWS:
995 case GL_VERTEX_ARRAY_BINDING:
996 return false;
997 default:
998 return false;
1002 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
1003 // TODO(gman): Make this handle pnames that return more than 1 value.
1004 GLint value;
1005 if (!GetHelper(pname, &value)) {
1006 return false;
1008 *params = static_cast<GLboolean>(value);
1009 return true;
1012 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
1013 // TODO(gman): Make this handle pnames that return more than 1 value.
1014 switch (pname) {
1015 case GL_MAX_TEXTURE_LOD_BIAS:
1016 *params = capabilities_.max_texture_lod_bias;
1017 return true;
1018 default:
1019 break;
1021 GLint value;
1022 if (!GetHelper(pname, &value)) {
1023 return false;
1025 *params = static_cast<GLfloat>(value);
1026 return true;
1029 bool GLES2Implementation::GetInteger64vHelper(GLenum pname, GLint64* params) {
1030 switch (pname) {
1031 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
1032 *params = capabilities_.max_combined_fragment_uniform_components;
1033 return true;
1034 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
1035 *params = capabilities_.max_combined_vertex_uniform_components;
1036 return true;
1037 case GL_MAX_ELEMENT_INDEX:
1038 *params = capabilities_.max_element_index;
1039 return true;
1040 case GL_MAX_SERVER_WAIT_TIMEOUT:
1041 *params = capabilities_.max_server_wait_timeout;
1042 return true;
1043 case GL_MAX_UNIFORM_BLOCK_SIZE:
1044 *params = capabilities_.max_uniform_block_size;
1045 return true;
1046 case GL_TIMESTAMP_EXT:
1047 // We convert all GPU timestamps to CPU time.
1048 *params = (base::TraceTicks::Now() - base::TraceTicks()).InMicroseconds()
1049 * base::Time::kNanosecondsPerMicrosecond;
1050 return true;
1051 default:
1052 break;
1054 GLint value;
1055 if (!GetHelper(pname, &value)) {
1056 return false;
1058 *params = static_cast<GLint64>(value);
1059 return true;
1062 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
1063 return GetHelper(pname, params);
1066 bool GLES2Implementation::GetIntegeri_vHelper(
1067 GLenum pname, GLuint index, GLint* data) {
1068 // TODO(zmo): Implement client side caching.
1069 return false;
1072 bool GLES2Implementation::GetInteger64i_vHelper(
1073 GLenum pname, GLuint index, GLint64* data) {
1074 // TODO(zmo): Implement client side caching.
1075 return false;
1078 bool GLES2Implementation::GetInternalformativHelper(
1079 GLenum target, GLenum format, GLenum pname, GLsizei bufSize,
1080 GLint* params) {
1081 // TODO(zmo): Implement the client side caching.
1082 return false;
1085 bool GLES2Implementation::GetSyncivHelper(
1086 GLsync sync, GLenum pname, GLsizei bufsize, GLsizei* length,
1087 GLint* values) {
1088 GLint value = 0;
1089 switch (pname) {
1090 case GL_OBJECT_TYPE:
1091 value = GL_SYNC_FENCE;
1092 break;
1093 case GL_SYNC_CONDITION:
1094 value = GL_SYNC_GPU_COMMANDS_COMPLETE;
1095 break;
1096 case GL_SYNC_FLAGS:
1097 value = 0;
1098 break;
1099 default:
1100 return false;
1102 if (bufsize > 0) {
1103 DCHECK(values);
1104 *values = value;
1106 if (length) {
1107 *length = 1;
1109 return true;
1112 bool GLES2Implementation::GetQueryObjectValueHelper(
1113 const char* function_name, GLuint id, GLenum pname, GLuint64* params) {
1114 GPU_CLIENT_SINGLE_THREAD_CHECK();
1115 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryObjectValueHelper("
1116 << id << ", "
1117 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
1118 << static_cast<const void*>(params) << ")");
1120 QueryTracker::Query* query = query_tracker_->GetQuery(id);
1121 if (!query) {
1122 SetGLError(GL_INVALID_OPERATION,
1123 function_name, "unknown query id");
1124 return false;
1127 if (query->Active()) {
1128 SetGLError(
1129 GL_INVALID_OPERATION,
1130 function_name,
1131 "query active. Did you call glEndQueryEXT?");
1132 return false;
1135 if (query->NeverUsed()) {
1136 SetGLError(
1137 GL_INVALID_OPERATION,
1138 function_name, "Never used. Did you call glBeginQueryEXT?");
1139 return false;
1142 bool valid_value = false;
1143 switch (pname) {
1144 case GL_QUERY_RESULT_EXT:
1145 if (!query->CheckResultsAvailable(helper_)) {
1146 helper_->WaitForToken(query->token());
1147 if (!query->CheckResultsAvailable(helper_)) {
1148 FinishHelper();
1149 CHECK(query->CheckResultsAvailable(helper_));
1152 *params = query->GetResult();
1153 valid_value = true;
1154 break;
1155 case GL_QUERY_RESULT_AVAILABLE_EXT:
1156 *params = query->CheckResultsAvailable(helper_);
1157 valid_value = true;
1158 break;
1159 default:
1160 SetGLErrorInvalidEnum(function_name, pname, "pname");
1161 break;
1163 GPU_CLIENT_LOG(" " << *params);
1164 CheckGLError();
1165 return valid_value;
1168 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
1169 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1170 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
1171 Result* result = GetResultAs<Result*>();
1172 if (!result) {
1173 return 0;
1175 *result = 0;
1176 helper_->GetMaxValueInBufferCHROMIUM(
1177 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
1178 WaitForCmd();
1179 return *result;
1182 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
1183 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
1184 GPU_CLIENT_SINGLE_THREAD_CHECK();
1185 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
1186 << buffer_id << ", " << count << ", "
1187 << GLES2Util::GetStringGetMaxIndexType(type)
1188 << ", " << offset << ")");
1189 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
1190 buffer_id, count, type, offset);
1191 GPU_CLIENT_LOG("returned " << result);
1192 CheckGLError();
1193 return result;
1196 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
1197 if (restore) {
1198 RestoreArrayBuffer(restore);
1199 // Restore the element array binding.
1200 // We only need to restore it if it wasn't a client side array.
1201 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
1202 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1207 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
1208 if (restore) {
1209 // Restore the user's current binding.
1210 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_);
1214 void GLES2Implementation::DrawElements(
1215 GLenum mode, GLsizei count, GLenum type, const void* indices) {
1216 GPU_CLIENT_SINGLE_THREAD_CHECK();
1217 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
1218 << GLES2Util::GetStringDrawMode(mode) << ", "
1219 << count << ", "
1220 << GLES2Util::GetStringIndexType(type) << ", "
1221 << static_cast<const void*>(indices) << ")");
1222 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1225 void GLES2Implementation::DrawRangeElements(
1226 GLenum mode, GLuint start, GLuint end,
1227 GLsizei count, GLenum type, const void* indices) {
1228 GPU_CLIENT_SINGLE_THREAD_CHECK();
1229 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawRangeElements("
1230 << GLES2Util::GetStringDrawMode(mode) << ", "
1231 << start << ", " << end << ", " << count << ", "
1232 << GLES2Util::GetStringIndexType(type) << ", "
1233 << static_cast<const void*>(indices) << ")");
1234 if (end < start) {
1235 SetGLError(GL_INVALID_VALUE, "glDrawRangeElements", "end < start");
1236 return;
1238 DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
1241 void GLES2Implementation::DrawElementsImpl(
1242 GLenum mode, GLsizei count, GLenum type, const void* indices,
1243 const char* func_name) {
1244 if (count < 0) {
1245 SetGLError(GL_INVALID_VALUE, func_name, "count < 0");
1246 return;
1248 bool simulated = false;
1249 GLuint offset = ToGLuint(indices);
1250 if (count > 0) {
1251 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
1252 !ValidateOffset(func_name, reinterpret_cast<GLintptr>(indices))) {
1253 return;
1255 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
1256 func_name, this, helper_, count, type, 0, indices,
1257 &offset, &simulated)) {
1258 return;
1261 helper_->DrawElements(mode, count, type, offset);
1262 RestoreElementAndArrayBuffers(simulated);
1263 CheckGLError();
1266 void GLES2Implementation::Flush() {
1267 GPU_CLIENT_SINGLE_THREAD_CHECK();
1268 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
1269 // Insert the cmd to call glFlush
1270 helper_->Flush();
1271 FlushHelper();
1274 void GLES2Implementation::ShallowFlushCHROMIUM() {
1275 GPU_CLIENT_SINGLE_THREAD_CHECK();
1276 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
1277 FlushHelper();
1280 void GLES2Implementation::FlushHelper() {
1281 // Flush our command buffer
1282 // (tell the service to execute up to the flush cmd.)
1283 helper_->CommandBufferHelper::Flush();
1285 if (aggressively_free_resources_)
1286 FreeEverything();
1289 void GLES2Implementation::OrderingBarrierCHROMIUM() {
1290 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOrderingBarrierCHROMIUM");
1291 // Flush command buffer at the GPU channel level. May be implemented as
1292 // Flush().
1293 helper_->CommandBufferHelper::OrderingBarrier();
1296 void GLES2Implementation::Finish() {
1297 GPU_CLIENT_SINGLE_THREAD_CHECK();
1298 FinishHelper();
1301 void GLES2Implementation::ShallowFinishCHROMIUM() {
1302 GPU_CLIENT_SINGLE_THREAD_CHECK();
1303 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
1304 // Flush our command buffer (tell the service to execute up to the flush cmd
1305 // and don't return until it completes).
1306 helper_->CommandBufferHelper::Finish();
1308 if (aggressively_free_resources_)
1309 FreeEverything();
1312 void GLES2Implementation::FinishHelper() {
1313 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
1314 TRACE_EVENT0("gpu", "GLES2::Finish");
1315 // Insert the cmd to call glFinish
1316 helper_->Finish();
1317 // Finish our command buffer
1318 // (tell the service to execute up to the Finish cmd and wait for it to
1319 // execute.)
1320 helper_->CommandBufferHelper::Finish();
1322 if (aggressively_free_resources_)
1323 FreeEverything();
1326 void GLES2Implementation::SwapBuffers() {
1327 GPU_CLIENT_SINGLE_THREAD_CHECK();
1328 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
1329 // TODO(piman): Strictly speaking we'd want to insert the token after the
1330 // swap, but the state update with the updated token might not have happened
1331 // by the time the SwapBuffer callback gets called, forcing us to synchronize
1332 // with the GPU process more than needed. So instead, make it happen before.
1333 // All it means is that we could be slightly looser on the kMaxSwapBuffers
1334 // semantics if the client doesn't use the callback mechanism, and by chance
1335 // the scheduler yields between the InsertToken and the SwapBuffers.
1336 swap_buffers_tokens_.push(helper_->InsertToken());
1337 helper_->SwapBuffers();
1338 helper_->CommandBufferHelper::Flush();
1339 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
1340 // compensate for TODO above.
1341 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
1342 helper_->WaitForToken(swap_buffers_tokens_.front());
1343 swap_buffers_tokens_.pop();
1347 void GLES2Implementation::SwapInterval(int interval) {
1348 GPU_CLIENT_SINGLE_THREAD_CHECK();
1349 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapInterval("
1350 << interval << ")");
1351 helper_->SwapInterval(interval);
1354 void GLES2Implementation::BindAttribLocation(
1355 GLuint program, GLuint index, const char* name) {
1356 GPU_CLIENT_SINGLE_THREAD_CHECK();
1357 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
1358 << program << ", " << index << ", " << name << ")");
1359 SetBucketAsString(kResultBucketId, name);
1360 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
1361 helper_->SetBucketSize(kResultBucketId, 0);
1362 CheckGLError();
1365 void GLES2Implementation::BindUniformLocationCHROMIUM(
1366 GLuint program, GLint location, const char* name) {
1367 GPU_CLIENT_SINGLE_THREAD_CHECK();
1368 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1369 << program << ", " << location << ", " << name << ")");
1370 SetBucketAsString(kResultBucketId, name);
1371 helper_->BindUniformLocationCHROMIUMBucket(
1372 program, location, kResultBucketId);
1373 helper_->SetBucketSize(kResultBucketId, 0);
1374 CheckGLError();
1377 void GLES2Implementation::GetVertexAttribPointerv(
1378 GLuint index, GLenum pname, void** ptr) {
1379 GPU_CLIENT_SINGLE_THREAD_CHECK();
1380 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1381 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1382 << static_cast<void*>(ptr) << ")");
1383 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
1384 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1385 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1386 typedef cmds::GetVertexAttribPointerv::Result Result;
1387 Result* result = GetResultAs<Result*>();
1388 if (!result) {
1389 return;
1391 result->SetNumResults(0);
1392 helper_->GetVertexAttribPointerv(
1393 index, pname, GetResultShmId(), GetResultShmOffset());
1394 WaitForCmd();
1395 result->CopyResult(ptr);
1396 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1398 GPU_CLIENT_LOG_CODE_BLOCK({
1399 for (int32 i = 0; i < num_results; ++i) {
1400 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
1403 CheckGLError();
1406 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1407 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1408 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
1409 SetGLError(
1410 GL_INVALID_VALUE,
1411 "glDeleteProgram", "id not created by this context.");
1412 return false;
1414 if (program == current_program_) {
1415 current_program_ = 0;
1417 return true;
1420 void GLES2Implementation::DeleteProgramStub(
1421 GLsizei n, const GLuint* programs) {
1422 DCHECK_EQ(1, n);
1423 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1424 helper_->DeleteProgram(programs[0]);
1427 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1428 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1429 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1430 SetGLError(
1431 GL_INVALID_VALUE,
1432 "glDeleteShader", "id not created by this context.");
1433 return false;
1435 return true;
1438 void GLES2Implementation::DeleteShaderStub(
1439 GLsizei n, const GLuint* shaders) {
1440 DCHECK_EQ(1, n);
1441 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1442 helper_->DeleteShader(shaders[0]);
1445 void GLES2Implementation::DeleteSyncHelper(GLsync sync) {
1446 GLuint sync_uint = ToGLuint(sync);
1447 if (!GetIdHandler(id_namespaces::kSyncs)->FreeIds(
1448 this, 1, &sync_uint, &GLES2Implementation::DeleteSyncStub)) {
1449 SetGLError(
1450 GL_INVALID_VALUE,
1451 "glDeleteSync", "id not created by this context.");
1455 void GLES2Implementation::DeleteSyncStub(GLsizei n, const GLuint* syncs) {
1456 DCHECK_EQ(1, n);
1457 helper_->DeleteSync(syncs[0]);
1460 GLint GLES2Implementation::GetAttribLocationHelper(
1461 GLuint program, const char* name) {
1462 typedef cmds::GetAttribLocation::Result Result;
1463 Result* result = GetResultAs<Result*>();
1464 if (!result) {
1465 return -1;
1467 *result = -1;
1468 SetBucketAsCString(kResultBucketId, name);
1469 helper_->GetAttribLocation(
1470 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1471 WaitForCmd();
1472 helper_->SetBucketSize(kResultBucketId, 0);
1473 return *result;
1476 GLint GLES2Implementation::GetAttribLocation(
1477 GLuint program, const char* name) {
1478 GPU_CLIENT_SINGLE_THREAD_CHECK();
1479 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1480 << ", " << name << ")");
1481 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1482 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1483 this, program, name);
1484 GPU_CLIENT_LOG("returned " << loc);
1485 CheckGLError();
1486 return loc;
1489 GLint GLES2Implementation::GetUniformLocationHelper(
1490 GLuint program, const char* name) {
1491 typedef cmds::GetUniformLocation::Result Result;
1492 Result* result = GetResultAs<Result*>();
1493 if (!result) {
1494 return -1;
1496 *result = -1;
1497 SetBucketAsCString(kResultBucketId, name);
1498 helper_->GetUniformLocation(program, kResultBucketId,
1499 GetResultShmId(), GetResultShmOffset());
1500 WaitForCmd();
1501 helper_->SetBucketSize(kResultBucketId, 0);
1502 return *result;
1505 GLint GLES2Implementation::GetUniformLocation(
1506 GLuint program, const char* name) {
1507 GPU_CLIENT_SINGLE_THREAD_CHECK();
1508 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1509 << ", " << name << ")");
1510 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1511 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1512 this, program, name);
1513 GPU_CLIENT_LOG("returned " << loc);
1514 CheckGLError();
1515 return loc;
1518 bool GLES2Implementation::GetUniformIndicesHelper(
1519 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1520 typedef cmds::GetUniformIndices::Result Result;
1521 Result* result = GetResultAs<Result*>();
1522 if (!result) {
1523 return false;
1525 result->SetNumResults(0);
1526 if (!PackStringsToBucket(count, names, NULL, "glGetUniformIndices")) {
1527 return false;
1529 helper_->GetUniformIndices(program, kResultBucketId,
1530 GetResultShmId(), GetResultShmOffset());
1531 WaitForCmd();
1532 if (result->GetNumResults() != count) {
1533 return false;
1535 result->CopyResult(indices);
1536 return true;
1539 void GLES2Implementation::GetUniformIndices(
1540 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
1541 GPU_CLIENT_SINGLE_THREAD_CHECK();
1542 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
1543 << ", " << count << ", " << names << ", " << indices << ")");
1544 TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
1545 if (count < 0) {
1546 SetGLError(GL_INVALID_VALUE, "glGetUniformIndices", "count < 0");
1547 return;
1549 if (count == 0) {
1550 return;
1552 bool success = share_group_->program_info_manager()->GetUniformIndices(
1553 this, program, count, names, indices);
1554 if (success) {
1555 GPU_CLIENT_LOG_CODE_BLOCK({
1556 for (GLsizei ii = 0; ii < count; ++ii) {
1557 GPU_CLIENT_LOG(" " << ii << ": " << indices[ii]);
1561 CheckGLError();
1564 bool GLES2Implementation::GetProgramivHelper(
1565 GLuint program, GLenum pname, GLint* params) {
1566 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1567 this, program, pname, params);
1568 GPU_CLIENT_LOG_CODE_BLOCK({
1569 if (got_value) {
1570 GPU_CLIENT_LOG(" 0: " << *params);
1573 return got_value;
1576 GLint GLES2Implementation::GetFragDataLocationHelper(
1577 GLuint program, const char* name) {
1578 typedef cmds::GetFragDataLocation::Result Result;
1579 Result* result = GetResultAs<Result*>();
1580 if (!result) {
1581 return -1;
1583 *result = -1;
1584 SetBucketAsCString(kResultBucketId, name);
1585 helper_->GetFragDataLocation(
1586 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1587 WaitForCmd();
1588 helper_->SetBucketSize(kResultBucketId, 0);
1589 return *result;
1592 GLint GLES2Implementation::GetFragDataLocation(
1593 GLuint program, const char* name) {
1594 GPU_CLIENT_SINGLE_THREAD_CHECK();
1595 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataLocation("
1596 << program << ", " << name << ")");
1597 TRACE_EVENT0("gpu", "GLES2::GetFragDataLocation");
1598 GLint loc = share_group_->program_info_manager()->GetFragDataLocation(
1599 this, program, name);
1600 GPU_CLIENT_LOG("returned " << loc);
1601 CheckGLError();
1602 return loc;
1605 GLuint GLES2Implementation::GetUniformBlockIndexHelper(
1606 GLuint program, const char* name) {
1607 typedef cmds::GetUniformBlockIndex::Result Result;
1608 Result* result = GetResultAs<Result*>();
1609 if (!result) {
1610 return GL_INVALID_INDEX;
1612 *result = GL_INVALID_INDEX;
1613 SetBucketAsCString(kResultBucketId, name);
1614 helper_->GetUniformBlockIndex(
1615 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1616 WaitForCmd();
1617 helper_->SetBucketSize(kResultBucketId, 0);
1618 return *result;
1621 GLuint GLES2Implementation::GetUniformBlockIndex(
1622 GLuint program, const char* name) {
1623 GPU_CLIENT_SINGLE_THREAD_CHECK();
1624 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformBlockIndex("
1625 << program << ", " << name << ")");
1626 TRACE_EVENT0("gpu", "GLES2::GetUniformBlockIndex");
1627 GLuint index = share_group_->program_info_manager()->GetUniformBlockIndex(
1628 this, program, name);
1629 GPU_CLIENT_LOG("returned " << index);
1630 CheckGLError();
1631 return index;
1634 void GLES2Implementation::LinkProgram(GLuint program) {
1635 GPU_CLIENT_SINGLE_THREAD_CHECK();
1636 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1637 helper_->LinkProgram(program);
1638 share_group_->program_info_manager()->CreateInfo(program);
1639 CheckGLError();
1642 void GLES2Implementation::ShaderBinary(
1643 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1644 GLsizei length) {
1645 GPU_CLIENT_SINGLE_THREAD_CHECK();
1646 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1647 << static_cast<const void*>(shaders) << ", "
1648 << GLES2Util::GetStringEnum(binaryformat) << ", "
1649 << static_cast<const void*>(binary) << ", "
1650 << length << ")");
1651 if (n < 0) {
1652 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1653 return;
1655 if (length < 0) {
1656 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1657 return;
1659 // TODO(gman): ShaderBinary should use buckets.
1660 unsigned int shader_id_size = n * sizeof(*shaders);
1661 ScopedTransferBufferArray<GLint> buffer(
1662 shader_id_size + length, helper_, transfer_buffer_);
1663 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1664 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1665 return;
1667 void* shader_ids = buffer.elements();
1668 void* shader_data = buffer.elements() + shader_id_size;
1669 memcpy(shader_ids, shaders, shader_id_size);
1670 memcpy(shader_data, binary, length);
1671 helper_->ShaderBinary(
1673 buffer.shm_id(),
1674 buffer.offset(),
1675 binaryformat,
1676 buffer.shm_id(),
1677 buffer.offset() + shader_id_size,
1678 length);
1679 CheckGLError();
1682 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1683 GPU_CLIENT_SINGLE_THREAD_CHECK();
1684 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1685 << GLES2Util::GetStringPixelStore(pname) << ", "
1686 << param << ")");
1687 switch (pname) {
1688 case GL_PACK_ALIGNMENT:
1689 pack_alignment_ = param;
1690 break;
1691 case GL_UNPACK_ALIGNMENT:
1692 unpack_alignment_ = param;
1693 break;
1694 case GL_UNPACK_ROW_LENGTH_EXT:
1695 unpack_row_length_ = param;
1696 return;
1697 case GL_UNPACK_IMAGE_HEIGHT:
1698 unpack_image_height_ = param;
1699 return;
1700 case GL_UNPACK_SKIP_ROWS_EXT:
1701 unpack_skip_rows_ = param;
1702 return;
1703 case GL_UNPACK_SKIP_PIXELS_EXT:
1704 unpack_skip_pixels_ = param;
1705 return;
1706 case GL_UNPACK_SKIP_IMAGES:
1707 unpack_skip_images_ = param;
1708 return;
1709 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1710 pack_reverse_row_order_ =
1711 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1712 break;
1713 default:
1714 break;
1716 helper_->PixelStorei(pname, param);
1717 CheckGLError();
1720 void GLES2Implementation::VertexAttribIPointer(
1721 GLuint index, GLint size, GLenum type, GLsizei stride, const void* ptr) {
1722 GPU_CLIENT_SINGLE_THREAD_CHECK();
1723 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribIPointer("
1724 << index << ", "
1725 << size << ", "
1726 << GLES2Util::GetStringVertexAttribIType(type) << ", "
1727 << stride << ", "
1728 << ptr << ")");
1729 // Record the info on the client side.
1730 if (!vertex_array_object_manager_->SetAttribPointer(bound_array_buffer_,
1731 index,
1732 size,
1733 type,
1734 GL_FALSE,
1735 stride,
1736 ptr,
1737 GL_TRUE)) {
1738 SetGLError(GL_INVALID_OPERATION, "glVertexAttribIPointer",
1739 "client side arrays are not allowed in vertex array objects.");
1740 return;
1742 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
1743 // Only report NON client side buffers to the service.
1744 if (!ValidateOffset("glVertexAttribIPointer",
1745 reinterpret_cast<GLintptr>(ptr))) {
1746 return;
1748 helper_->VertexAttribIPointer(index, size, type, stride, ToGLuint(ptr));
1750 CheckGLError();
1753 void GLES2Implementation::VertexAttribPointer(
1754 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1755 const void* ptr) {
1756 GPU_CLIENT_SINGLE_THREAD_CHECK();
1757 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1758 << index << ", "
1759 << size << ", "
1760 << GLES2Util::GetStringVertexAttribType(type) << ", "
1761 << GLES2Util::GetStringBool(normalized) << ", "
1762 << stride << ", "
1763 << ptr << ")");
1764 // Record the info on the client side.
1765 if (!vertex_array_object_manager_->SetAttribPointer(bound_array_buffer_,
1766 index,
1767 size,
1768 type,
1769 normalized,
1770 stride,
1771 ptr,
1772 GL_FALSE)) {
1773 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1774 "client side arrays are not allowed in vertex array objects.");
1775 return;
1777 if (!support_client_side_arrays_ || bound_array_buffer_ != 0) {
1778 // Only report NON client side buffers to the service.
1779 if (!ValidateOffset("glVertexAttribPointer",
1780 reinterpret_cast<GLintptr>(ptr))) {
1781 return;
1783 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1784 ToGLuint(ptr));
1786 CheckGLError();
1789 void GLES2Implementation::VertexAttribDivisorANGLE(
1790 GLuint index, GLuint divisor) {
1791 GPU_CLIENT_SINGLE_THREAD_CHECK();
1792 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1793 << index << ", "
1794 << divisor << ") ");
1795 // Record the info on the client side.
1796 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1797 helper_->VertexAttribDivisorANGLE(index, divisor);
1798 CheckGLError();
1801 void GLES2Implementation::BufferDataHelper(
1802 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1803 if (!ValidateSize("glBufferData", size))
1804 return;
1806 #if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
1807 // Do not upload uninitialized data. Even if it's not a bug, it can cause a
1808 // bogus MSan report during a readback later. This is because MSan doesn't
1809 // understand shared memory and would assume we were reading back the same
1810 // unintialized data.
1811 if (data) __msan_check_mem_is_initialized(data, size);
1812 #endif
1814 GLuint buffer_id;
1815 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1816 if (!buffer_id) {
1817 return;
1820 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1821 if (buffer)
1822 RemoveTransferBuffer(buffer);
1824 // Create new buffer.
1825 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1826 DCHECK(buffer);
1827 if (buffer->address() && data)
1828 memcpy(buffer->address(), data, size);
1829 return;
1832 RemoveMappedBufferRangeByTarget(target);
1834 // If there is no data just send BufferData
1835 if (size == 0 || !data) {
1836 helper_->BufferData(target, size, 0, 0, usage);
1837 return;
1840 // See if we can send all at once.
1841 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1842 if (!buffer.valid()) {
1843 return;
1846 if (buffer.size() >= static_cast<unsigned int>(size)) {
1847 memcpy(buffer.address(), data, size);
1848 helper_->BufferData(
1849 target,
1850 size,
1851 buffer.shm_id(),
1852 buffer.offset(),
1853 usage);
1854 return;
1857 // Make the buffer with BufferData then send via BufferSubData
1858 helper_->BufferData(target, size, 0, 0, usage);
1859 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1860 CheckGLError();
1863 void GLES2Implementation::BufferData(
1864 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1865 GPU_CLIENT_SINGLE_THREAD_CHECK();
1866 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1867 << GLES2Util::GetStringBufferTarget(target) << ", "
1868 << size << ", "
1869 << static_cast<const void*>(data) << ", "
1870 << GLES2Util::GetStringBufferUsage(usage) << ")");
1871 BufferDataHelper(target, size, data, usage);
1872 CheckGLError();
1875 void GLES2Implementation::BufferSubDataHelper(
1876 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1877 if (size == 0) {
1878 return;
1881 if (!ValidateSize("glBufferSubData", size) ||
1882 !ValidateOffset("glBufferSubData", offset)) {
1883 return;
1886 GLuint buffer_id;
1887 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1888 if (!buffer_id) {
1889 return;
1891 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1892 if (!buffer) {
1893 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1894 return;
1897 int32 end = 0;
1898 int32 buffer_size = buffer->size();
1899 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1900 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1901 return;
1904 if (buffer->address() && data)
1905 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1906 return;
1909 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1910 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1913 void GLES2Implementation::BufferSubDataHelperImpl(
1914 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1915 ScopedTransferBufferPtr* buffer) {
1916 DCHECK(buffer);
1917 DCHECK_GT(size, 0);
1919 const int8* source = static_cast<const int8*>(data);
1920 while (size) {
1921 if (!buffer->valid() || buffer->size() == 0) {
1922 buffer->Reset(size);
1923 if (!buffer->valid()) {
1924 return;
1927 memcpy(buffer->address(), source, buffer->size());
1928 helper_->BufferSubData(
1929 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1930 offset += buffer->size();
1931 source += buffer->size();
1932 size -= buffer->size();
1933 buffer->Release();
1937 void GLES2Implementation::BufferSubData(
1938 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1939 GPU_CLIENT_SINGLE_THREAD_CHECK();
1940 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1941 << GLES2Util::GetStringBufferTarget(target) << ", "
1942 << offset << ", " << size << ", "
1943 << static_cast<const void*>(data) << ")");
1944 BufferSubDataHelper(target, offset, size, data);
1945 CheckGLError();
1948 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
1949 int32 token = buffer->last_usage_token();
1951 if (token) {
1952 if (helper_->HasTokenPassed(token))
1953 buffer_tracker_->Free(buffer);
1954 else
1955 buffer_tracker_->FreePendingToken(buffer, token);
1956 } else {
1957 buffer_tracker_->Free(buffer);
1960 buffer_tracker_->RemoveBuffer(buffer->id());
1963 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1964 GLenum target,
1965 const char* function_name,
1966 GLuint* buffer_id) {
1967 *buffer_id = 0;
1969 switch (target) {
1970 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1971 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1972 break;
1973 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1974 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1975 break;
1976 default:
1977 // Unknown target
1978 return false;
1980 if (!*buffer_id) {
1981 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1983 return true;
1986 BufferTracker::Buffer*
1987 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1988 GLuint buffer_id,
1989 const char* function_name,
1990 GLuint offset, GLsizei size) {
1991 DCHECK(buffer_id);
1992 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1993 if (!buffer) {
1994 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1995 return NULL;
1997 if (buffer->mapped()) {
1998 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1999 return NULL;
2001 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
2002 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
2003 return NULL;
2005 return buffer;
2008 void GLES2Implementation::CompressedTexImage2D(
2009 GLenum target, GLint level, GLenum internalformat, GLsizei width,
2010 GLsizei height, GLint border, GLsizei image_size, const void* data) {
2011 GPU_CLIENT_SINGLE_THREAD_CHECK();
2012 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
2013 << GLES2Util::GetStringTextureTarget(target) << ", "
2014 << level << ", "
2015 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
2016 << width << ", " << height << ", " << border << ", "
2017 << image_size << ", "
2018 << static_cast<const void*>(data) << ")");
2019 if (width < 0 || height < 0 || level < 0) {
2020 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
2021 return;
2023 if (border != 0) {
2024 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "border != 0");
2025 return;
2027 if (height == 0 || width == 0) {
2028 return;
2030 // If there's a pixel unpack buffer bound use it when issuing
2031 // CompressedTexImage2D.
2032 if (bound_pixel_unpack_transfer_buffer_id_) {
2033 GLuint offset = ToGLuint(data);
2034 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2035 bound_pixel_unpack_transfer_buffer_id_,
2036 "glCompressedTexImage2D", offset, image_size);
2037 if (buffer && buffer->shm_id() != -1) {
2038 helper_->CompressedTexImage2D(
2039 target, level, internalformat, width, height, image_size,
2040 buffer->shm_id(), buffer->shm_offset() + offset);
2041 buffer->set_last_usage_token(helper_->InsertToken());
2043 return;
2045 SetBucketContents(kResultBucketId, data, image_size);
2046 helper_->CompressedTexImage2DBucket(
2047 target, level, internalformat, width, height, kResultBucketId);
2048 // Free the bucket. This is not required but it does free up the memory.
2049 // and we don't have to wait for the result so from the client's perspective
2050 // it's cheap.
2051 helper_->SetBucketSize(kResultBucketId, 0);
2052 CheckGLError();
2055 void GLES2Implementation::CompressedTexSubImage2D(
2056 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2057 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
2058 GPU_CLIENT_SINGLE_THREAD_CHECK();
2059 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
2060 << GLES2Util::GetStringTextureTarget(target) << ", "
2061 << level << ", "
2062 << xoffset << ", " << yoffset << ", "
2063 << width << ", " << height << ", "
2064 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
2065 << image_size << ", "
2066 << static_cast<const void*>(data) << ")");
2067 if (width < 0 || height < 0 || level < 0) {
2068 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
2069 return;
2071 // If there's a pixel unpack buffer bound use it when issuing
2072 // CompressedTexSubImage2D.
2073 if (bound_pixel_unpack_transfer_buffer_id_) {
2074 GLuint offset = ToGLuint(data);
2075 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2076 bound_pixel_unpack_transfer_buffer_id_,
2077 "glCompressedTexSubImage2D", offset, image_size);
2078 if (buffer && buffer->shm_id() != -1) {
2079 helper_->CompressedTexSubImage2D(
2080 target, level, xoffset, yoffset, width, height, format, image_size,
2081 buffer->shm_id(), buffer->shm_offset() + offset);
2082 buffer->set_last_usage_token(helper_->InsertToken());
2083 CheckGLError();
2085 return;
2087 SetBucketContents(kResultBucketId, data, image_size);
2088 helper_->CompressedTexSubImage2DBucket(
2089 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
2090 // Free the bucket. This is not required but it does free up the memory.
2091 // and we don't have to wait for the result so from the client's perspective
2092 // it's cheap.
2093 helper_->SetBucketSize(kResultBucketId, 0);
2094 CheckGLError();
2097 void GLES2Implementation::CompressedTexImage3D(
2098 GLenum target, GLint level, GLenum internalformat, GLsizei width,
2099 GLsizei height, GLsizei depth, GLint border, GLsizei image_size,
2100 const void* data) {
2101 GPU_CLIENT_SINGLE_THREAD_CHECK();
2102 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage3D("
2103 << GLES2Util::GetStringTexture3DTarget(target) << ", " << level << ", "
2104 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
2105 << width << ", " << height << ", " << depth << ", " << border << ", "
2106 << image_size << ", " << static_cast<const void*>(data) << ")");
2107 if (width < 0 || height < 0 || depth < 0 || level < 0) {
2108 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "dimension < 0");
2109 return;
2111 if (border != 0) {
2112 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage3D", "border != 0");
2113 return;
2115 if (height == 0 || width == 0 || depth == 0) {
2116 return;
2118 // If there's a pixel unpack buffer bound use it when issuing
2119 // CompressedTexImage3D.
2120 if (bound_pixel_unpack_transfer_buffer_id_) {
2121 GLuint offset = ToGLuint(data);
2122 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2123 bound_pixel_unpack_transfer_buffer_id_,
2124 "glCompressedTexImage3D", offset, image_size);
2125 if (buffer && buffer->shm_id() != -1) {
2126 helper_->CompressedTexImage3D(
2127 target, level, internalformat, width, height, depth, image_size,
2128 buffer->shm_id(), buffer->shm_offset() + offset);
2129 buffer->set_last_usage_token(helper_->InsertToken());
2131 return;
2133 SetBucketContents(kResultBucketId, data, image_size);
2134 helper_->CompressedTexImage3DBucket(
2135 target, level, internalformat, width, height, depth, kResultBucketId);
2136 // Free the bucket. This is not required but it does free up the memory.
2137 // and we don't have to wait for the result so from the client's perspective
2138 // it's cheap.
2139 helper_->SetBucketSize(kResultBucketId, 0);
2140 CheckGLError();
2143 void GLES2Implementation::CompressedTexSubImage3D(
2144 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2145 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2146 GLsizei image_size, const void* data) {
2147 GPU_CLIENT_SINGLE_THREAD_CHECK();
2148 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage3D("
2149 << GLES2Util::GetStringTextureTarget(target) << ", "
2150 << level << ", "
2151 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2152 << width << ", " << height << ", " << depth << ", "
2153 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
2154 << image_size << ", "
2155 << static_cast<const void*>(data) << ")");
2156 if (width < 0 || height < 0 || depth < 0 || level < 0) {
2157 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage3D", "dimension < 0");
2158 return;
2160 // If there's a pixel unpack buffer bound use it when issuing
2161 // CompressedTexSubImage3D.
2162 if (bound_pixel_unpack_transfer_buffer_id_) {
2163 GLuint offset = ToGLuint(data);
2164 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2165 bound_pixel_unpack_transfer_buffer_id_,
2166 "glCompressedTexSubImage3D", offset, image_size);
2167 if (buffer && buffer->shm_id() != -1) {
2168 helper_->CompressedTexSubImage3D(
2169 target, level, xoffset, yoffset, zoffset,
2170 width, height, depth, format, image_size,
2171 buffer->shm_id(), buffer->shm_offset() + offset);
2172 buffer->set_last_usage_token(helper_->InsertToken());
2173 CheckGLError();
2175 return;
2177 SetBucketContents(kResultBucketId, data, image_size);
2178 helper_->CompressedTexSubImage3DBucket(
2179 target, level, xoffset, yoffset, zoffset, width, height, depth, format,
2180 kResultBucketId);
2181 // Free the bucket. This is not required but it does free up the memory.
2182 // and we don't have to wait for the result so from the client's perspective
2183 // it's cheap.
2184 helper_->SetBucketSize(kResultBucketId, 0);
2185 CheckGLError();
2188 namespace {
2190 void CopyRectToBuffer(
2191 const void* pixels,
2192 uint32 height,
2193 uint32 unpadded_row_size,
2194 uint32 pixels_padded_row_size,
2195 void* buffer,
2196 uint32 buffer_padded_row_size) {
2197 const int8* source = static_cast<const int8*>(pixels);
2198 int8* dest = static_cast<int8*>(buffer);
2199 if (pixels_padded_row_size != buffer_padded_row_size) {
2200 // the last row is copied unpadded at the end
2201 for (; height > 1; --height) {
2202 memcpy(dest, source, buffer_padded_row_size);
2203 dest += buffer_padded_row_size;
2204 source += pixels_padded_row_size;
2206 memcpy(dest, source, unpadded_row_size);
2207 } else {
2208 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
2209 memcpy(dest, source, size);
2213 } // anonymous namespace
2215 void GLES2Implementation::TexImage2D(
2216 GLenum target, GLint level, GLint internalformat, GLsizei width,
2217 GLsizei height, GLint border, GLenum format, GLenum type,
2218 const void* pixels) {
2219 GPU_CLIENT_SINGLE_THREAD_CHECK();
2220 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
2221 << GLES2Util::GetStringTextureTarget(target) << ", "
2222 << level << ", "
2223 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2224 << width << ", " << height << ", " << border << ", "
2225 << GLES2Util::GetStringTextureFormat(format) << ", "
2226 << GLES2Util::GetStringPixelType(type) << ", "
2227 << static_cast<const void*>(pixels) << ")");
2228 if (level < 0 || height < 0 || width < 0) {
2229 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
2230 return;
2232 if (border != 0) {
2233 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
2234 return;
2236 uint32 size;
2237 uint32 unpadded_row_size;
2238 uint32 padded_row_size;
2239 if (!GLES2Util::ComputeImageDataSizes(
2240 width, height, 1, format, type, unpack_alignment_, &size,
2241 &unpadded_row_size, &padded_row_size)) {
2242 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
2243 return;
2246 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
2247 if (bound_pixel_unpack_transfer_buffer_id_) {
2248 GLuint offset = ToGLuint(pixels);
2249 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2250 bound_pixel_unpack_transfer_buffer_id_,
2251 "glTexImage2D", offset, size);
2252 if (buffer && buffer->shm_id() != -1) {
2253 helper_->TexImage2D(
2254 target, level, internalformat, width, height, format, type,
2255 buffer->shm_id(), buffer->shm_offset() + offset);
2256 buffer->set_last_usage_token(helper_->InsertToken());
2257 CheckGLError();
2259 return;
2262 // If there's no data just issue TexImage2D
2263 if (!pixels) {
2264 helper_->TexImage2D(
2265 target, level, internalformat, width, height, format, type,
2266 0, 0);
2267 CheckGLError();
2268 return;
2271 // compute the advance bytes per row for the src pixels
2272 uint32 src_padded_row_size;
2273 if (unpack_row_length_ > 0) {
2274 if (!GLES2Util::ComputeImagePaddedRowSize(
2275 unpack_row_length_, format, type, unpack_alignment_,
2276 &src_padded_row_size)) {
2277 SetGLError(
2278 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2279 return;
2281 } else {
2282 src_padded_row_size = padded_row_size;
2285 // advance pixels pointer past the skip rows and skip pixels
2286 pixels = reinterpret_cast<const int8*>(pixels) +
2287 unpack_skip_rows_ * src_padded_row_size;
2288 if (unpack_skip_pixels_) {
2289 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2290 pixels = reinterpret_cast<const int8*>(pixels) +
2291 unpack_skip_pixels_ * group_size;
2294 // Check if we can send it all at once.
2295 int32_t shm_id = 0;
2296 uint32_t shm_offset = 0;
2297 void* buffer_pointer = nullptr;
2299 ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
2300 ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
2302 if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
2303 shm_id = transfer_alloc.shm_id();
2304 shm_offset = transfer_alloc.offset();
2305 buffer_pointer = transfer_alloc.address();
2306 } else {
2307 mapped_alloc.Reset(size);
2308 if (mapped_alloc.valid()) {
2309 transfer_alloc.Discard();
2311 mapped_alloc.SetFlushAfterRelease(true);
2312 shm_id = mapped_alloc.shm_id();
2313 shm_offset = mapped_alloc.offset();
2314 buffer_pointer = mapped_alloc.address();
2318 if (buffer_pointer) {
2319 CopyRectToBuffer(
2320 pixels, height, unpadded_row_size, src_padded_row_size,
2321 buffer_pointer, padded_row_size);
2322 helper_->TexImage2D(
2323 target, level, internalformat, width, height, format, type,
2324 shm_id, shm_offset);
2325 CheckGLError();
2326 return;
2329 // No, so send it using TexSubImage2D.
2330 helper_->TexImage2D(
2331 target, level, internalformat, width, height, format, type,
2332 0, 0);
2333 TexSubImage2DImpl(
2334 target, level, 0, 0, width, height, format, type, unpadded_row_size,
2335 pixels, src_padded_row_size, GL_TRUE, &transfer_alloc, padded_row_size);
2336 CheckGLError();
2339 void GLES2Implementation::TexImage3D(
2340 GLenum target, GLint level, GLint internalformat, GLsizei width,
2341 GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type,
2342 const void* pixels) {
2343 GPU_CLIENT_SINGLE_THREAD_CHECK();
2344 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D("
2345 << GLES2Util::GetStringTextureTarget(target) << ", "
2346 << level << ", "
2347 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
2348 << width << ", " << height << ", " << depth << ", " << border << ", "
2349 << GLES2Util::GetStringTextureFormat(format) << ", "
2350 << GLES2Util::GetStringPixelType(type) << ", "
2351 << static_cast<const void*>(pixels) << ")");
2352 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2353 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "dimension < 0");
2354 return;
2356 if (border != 0) {
2357 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "border != 0");
2358 return;
2360 uint32 size;
2361 uint32 unpadded_row_size;
2362 uint32 padded_row_size;
2363 if (!GLES2Util::ComputeImageDataSizes(
2364 width, height, depth, format, type, unpack_alignment_, &size,
2365 &unpadded_row_size, &padded_row_size)) {
2366 SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large");
2367 return;
2370 // If there's a pixel unpack buffer bound use it when issuing TexImage3D.
2371 if (bound_pixel_unpack_transfer_buffer_id_) {
2372 GLuint offset = ToGLuint(pixels);
2373 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2374 bound_pixel_unpack_transfer_buffer_id_,
2375 "glTexImage3D", offset, size);
2376 if (buffer && buffer->shm_id() != -1) {
2377 helper_->TexImage3D(
2378 target, level, internalformat, width, height, depth, format, type,
2379 buffer->shm_id(), buffer->shm_offset() + offset);
2380 buffer->set_last_usage_token(helper_->InsertToken());
2381 CheckGLError();
2383 return;
2386 // If there's no data just issue TexImage3D
2387 if (!pixels) {
2388 helper_->TexImage3D(
2389 target, level, internalformat, width, height, depth, format, type,
2390 0, 0);
2391 CheckGLError();
2392 return;
2395 // compute the advance bytes per row for the src pixels
2396 uint32 src_padded_row_size;
2397 if (unpack_row_length_ > 0) {
2398 if (!GLES2Util::ComputeImagePaddedRowSize(
2399 unpack_row_length_, format, type, unpack_alignment_,
2400 &src_padded_row_size)) {
2401 SetGLError(
2402 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2403 return;
2405 } else {
2406 src_padded_row_size = padded_row_size;
2408 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2410 // advance pixels pointer past the skip images/rows/pixels
2411 pixels = reinterpret_cast<const int8*>(pixels) +
2412 unpack_skip_images_ * src_padded_row_size * src_height +
2413 unpack_skip_rows_ * src_padded_row_size;
2414 if (unpack_skip_pixels_) {
2415 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2416 pixels = reinterpret_cast<const int8*>(pixels) +
2417 unpack_skip_pixels_ * group_size;
2420 // Check if we can send it all at once.
2421 int32_t shm_id = 0;
2422 uint32_t shm_offset = 0;
2423 void* buffer_pointer = nullptr;
2425 ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
2426 ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
2428 if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
2429 shm_id = transfer_alloc.shm_id();
2430 shm_offset = transfer_alloc.offset();
2431 buffer_pointer = transfer_alloc.address();
2432 } else {
2433 mapped_alloc.Reset(size);
2434 if (mapped_alloc.valid()) {
2435 transfer_alloc.Discard();
2437 mapped_alloc.SetFlushAfterRelease(true);
2438 shm_id = mapped_alloc.shm_id();
2439 shm_offset = mapped_alloc.offset();
2440 buffer_pointer = mapped_alloc.address();
2444 if (buffer_pointer) {
2445 for (GLsizei z = 0; z < depth; ++z) {
2446 // Only the last row of the last image is unpadded.
2447 uint32 src_unpadded_row_size =
2448 (z == depth - 1) ? unpadded_row_size : src_padded_row_size;
2449 CopyRectToBuffer(
2450 pixels, height, src_unpadded_row_size, src_padded_row_size,
2451 buffer_pointer, padded_row_size);
2452 pixels = reinterpret_cast<const int8*>(pixels) +
2453 src_padded_row_size * src_height;
2454 buffer_pointer = reinterpret_cast<int8*>(buffer_pointer) +
2455 padded_row_size * height;
2457 helper_->TexImage3D(
2458 target, level, internalformat, width, height, depth, format, type,
2459 shm_id, shm_offset);
2460 CheckGLError();
2461 return;
2464 // No, so send it using TexSubImage3D.
2465 helper_->TexImage3D(
2466 target, level, internalformat, width, height, depth, format, type,
2467 0, 0);
2468 TexSubImage3DImpl(
2469 target, level, 0, 0, 0, width, height, depth, format, type,
2470 unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &transfer_alloc,
2471 padded_row_size);
2472 CheckGLError();
2475 void GLES2Implementation::TexSubImage2D(
2476 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2477 GLsizei height, GLenum format, GLenum type, const void* pixels) {
2478 GPU_CLIENT_SINGLE_THREAD_CHECK();
2479 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
2480 << GLES2Util::GetStringTextureTarget(target) << ", "
2481 << level << ", "
2482 << xoffset << ", " << yoffset << ", "
2483 << width << ", " << height << ", "
2484 << GLES2Util::GetStringTextureFormat(format) << ", "
2485 << GLES2Util::GetStringPixelType(type) << ", "
2486 << static_cast<const void*>(pixels) << ")");
2488 if (level < 0 || height < 0 || width < 0) {
2489 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
2490 return;
2492 if (height == 0 || width == 0) {
2493 return;
2496 uint32 temp_size;
2497 uint32 unpadded_row_size;
2498 uint32 padded_row_size;
2499 if (!GLES2Util::ComputeImageDataSizes(
2500 width, height, 1, format, type, unpack_alignment_, &temp_size,
2501 &unpadded_row_size, &padded_row_size)) {
2502 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
2503 return;
2506 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2507 if (bound_pixel_unpack_transfer_buffer_id_) {
2508 GLuint offset = ToGLuint(pixels);
2509 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2510 bound_pixel_unpack_transfer_buffer_id_,
2511 "glTexSubImage2D", offset, temp_size);
2512 if (buffer && buffer->shm_id() != -1) {
2513 helper_->TexSubImage2D(
2514 target, level, xoffset, yoffset, width, height, format, type,
2515 buffer->shm_id(), buffer->shm_offset() + offset, false);
2516 buffer->set_last_usage_token(helper_->InsertToken());
2517 CheckGLError();
2519 return;
2522 // compute the advance bytes per row for the src pixels
2523 uint32 src_padded_row_size;
2524 if (unpack_row_length_ > 0) {
2525 if (!GLES2Util::ComputeImagePaddedRowSize(
2526 unpack_row_length_, format, type, unpack_alignment_,
2527 &src_padded_row_size)) {
2528 SetGLError(
2529 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
2530 return;
2532 } else {
2533 src_padded_row_size = padded_row_size;
2536 // advance pixels pointer past the skip rows and skip pixels
2537 pixels = reinterpret_cast<const int8*>(pixels) +
2538 unpack_skip_rows_ * src_padded_row_size;
2539 if (unpack_skip_pixels_) {
2540 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2541 pixels = reinterpret_cast<const int8*>(pixels) +
2542 unpack_skip_pixels_ * group_size;
2545 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2546 TexSubImage2DImpl(
2547 target, level, xoffset, yoffset, width, height, format, type,
2548 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
2549 padded_row_size);
2550 CheckGLError();
2553 void GLES2Implementation::TexSubImage3D(
2554 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2555 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2556 const void* pixels) {
2557 GPU_CLIENT_SINGLE_THREAD_CHECK();
2558 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D("
2559 << GLES2Util::GetStringTextureTarget(target) << ", "
2560 << level << ", "
2561 << xoffset << ", " << yoffset << ", " << zoffset << ", "
2562 << width << ", " << height << ", " << depth << ", "
2563 << GLES2Util::GetStringTextureFormat(format) << ", "
2564 << GLES2Util::GetStringPixelType(type) << ", "
2565 << static_cast<const void*>(pixels) << ")");
2567 if (level < 0 || height < 0 || width < 0 || depth < 0) {
2568 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "dimension < 0");
2569 return;
2571 if (height == 0 || width == 0 || depth == 0) {
2572 return;
2575 uint32 temp_size;
2576 uint32 unpadded_row_size;
2577 uint32 padded_row_size;
2578 if (!GLES2Util::ComputeImageDataSizes(
2579 width, height, depth, format, type, unpack_alignment_, &temp_size,
2580 &unpadded_row_size, &padded_row_size)) {
2581 SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "size to large");
2582 return;
2585 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
2586 if (bound_pixel_unpack_transfer_buffer_id_) {
2587 GLuint offset = ToGLuint(pixels);
2588 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2589 bound_pixel_unpack_transfer_buffer_id_,
2590 "glTexSubImage3D", offset, temp_size);
2591 if (buffer && buffer->shm_id() != -1) {
2592 helper_->TexSubImage3D(
2593 target, level, xoffset, yoffset, zoffset, width, height, depth,
2594 format, type, buffer->shm_id(), buffer->shm_offset() + offset, false);
2595 buffer->set_last_usage_token(helper_->InsertToken());
2596 CheckGLError();
2598 return;
2601 // compute the advance bytes per row for the src pixels
2602 uint32 src_padded_row_size;
2603 if (unpack_row_length_ > 0) {
2604 if (!GLES2Util::ComputeImagePaddedRowSize(
2605 unpack_row_length_, format, type, unpack_alignment_,
2606 &src_padded_row_size)) {
2607 SetGLError(
2608 GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large");
2609 return;
2611 } else {
2612 src_padded_row_size = padded_row_size;
2614 uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height;
2616 // advance pixels pointer past the skip images/rows/pixels
2617 pixels = reinterpret_cast<const int8*>(pixels) +
2618 unpack_skip_images_ * src_padded_row_size * src_height +
2619 unpack_skip_rows_ * src_padded_row_size;
2620 if (unpack_skip_pixels_) {
2621 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
2622 pixels = reinterpret_cast<const int8*>(pixels) +
2623 unpack_skip_pixels_ * group_size;
2626 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
2627 TexSubImage3DImpl(
2628 target, level, xoffset, yoffset, zoffset, width, height, depth,
2629 format, type, unpadded_row_size, pixels, src_padded_row_size, GL_FALSE,
2630 &buffer, padded_row_size);
2631 CheckGLError();
2634 static GLint ComputeNumRowsThatFitInBuffer(
2635 uint32 padded_row_size, uint32 unpadded_row_size,
2636 unsigned int size, GLsizei remaining_rows) {
2637 DCHECK_GE(unpadded_row_size, 0u);
2638 if (padded_row_size == 0) {
2639 return 1;
2641 GLint num_rows = size / padded_row_size;
2642 if (num_rows + 1 == remaining_rows &&
2643 size - num_rows * padded_row_size >= unpadded_row_size) {
2644 num_rows++;
2646 return num_rows;
2649 void GLES2Implementation::TexSubImage2DImpl(
2650 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
2651 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
2652 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
2653 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
2654 DCHECK(buffer);
2655 DCHECK_GE(level, 0);
2656 DCHECK_GT(height, 0);
2657 DCHECK_GT(width, 0);
2659 const int8* source = reinterpret_cast<const int8*>(pixels);
2660 // Transfer by rows.
2661 while (height) {
2662 unsigned int desired_size =
2663 buffer_padded_row_size * (height - 1) + unpadded_row_size;
2664 if (!buffer->valid() || buffer->size() == 0) {
2665 buffer->Reset(desired_size);
2666 if (!buffer->valid()) {
2667 return;
2671 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2672 buffer_padded_row_size, unpadded_row_size, buffer->size(), height);
2673 num_rows = std::min(num_rows, height);
2674 CopyRectToBuffer(
2675 source, num_rows, unpadded_row_size, pixels_padded_row_size,
2676 buffer->address(), buffer_padded_row_size);
2677 helper_->TexSubImage2D(
2678 target, level, xoffset, yoffset, width, num_rows, format, type,
2679 buffer->shm_id(), buffer->offset(), internal);
2680 buffer->Release();
2681 yoffset += num_rows;
2682 source += num_rows * pixels_padded_row_size;
2683 height -= num_rows;
2687 void GLES2Implementation::TexSubImage3DImpl(
2688 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei zoffset,
2689 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2690 uint32 unpadded_row_size, const void* pixels, uint32 pixels_padded_row_size,
2691 GLboolean internal, ScopedTransferBufferPtr* buffer,
2692 uint32 buffer_padded_row_size) {
2693 DCHECK(buffer);
2694 DCHECK_GE(level, 0);
2695 DCHECK_GT(height, 0);
2696 DCHECK_GT(width, 0);
2697 DCHECK_GT(depth, 0);
2698 const int8* source = reinterpret_cast<const int8*>(pixels);
2699 GLsizei total_rows = height * depth;
2700 GLint row_index = 0, depth_index = 0;
2701 while (total_rows) {
2702 // Each time, we either copy one or more images, or copy one or more rows
2703 // within a single image, depending on the buffer size limit.
2704 GLsizei max_rows;
2705 unsigned int desired_size;
2706 if (row_index > 0) {
2707 // We are in the middle of an image. Send the remaining of the image.
2708 max_rows = height - row_index;
2709 if (total_rows <= height) {
2710 // Last image, so last row is unpadded.
2711 desired_size = buffer_padded_row_size * (max_rows - 1) +
2712 unpadded_row_size;
2713 } else {
2714 desired_size = buffer_padded_row_size * max_rows;
2716 } else {
2717 // Send all the remaining data if possible.
2718 max_rows = total_rows;
2719 desired_size =
2720 buffer_padded_row_size * (max_rows - 1) + unpadded_row_size;
2722 if (!buffer->valid() || buffer->size() == 0) {
2723 buffer->Reset(desired_size);
2724 if (!buffer->valid()) {
2725 return;
2728 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2729 buffer_padded_row_size, unpadded_row_size, buffer->size(), total_rows);
2730 num_rows = std::min(num_rows, max_rows);
2731 GLint num_images = num_rows / height;
2732 GLsizei my_height, my_depth;
2733 if (num_images > 0) {
2734 num_rows = num_images * height;
2735 my_height = height;
2736 my_depth = num_images;
2737 } else {
2738 my_height = num_rows;
2739 my_depth = 1;
2742 if (num_images > 0) {
2743 int8* buffer_pointer = reinterpret_cast<int8*>(buffer->address());
2744 uint32 src_height =
2745 unpack_image_height_ > 0 ? unpack_image_height_ : height;
2746 uint32 image_size_dst = buffer_padded_row_size * height;
2747 uint32 image_size_src = pixels_padded_row_size * src_height;
2748 for (GLint ii = 0; ii < num_images; ++ii) {
2749 uint32 my_unpadded_row_size;
2750 if (total_rows == num_rows && ii + 1 == num_images)
2751 my_unpadded_row_size = unpadded_row_size;
2752 else
2753 my_unpadded_row_size = pixels_padded_row_size;
2754 CopyRectToBuffer(
2755 source + ii * image_size_src, my_height, my_unpadded_row_size,
2756 pixels_padded_row_size, buffer_pointer + ii * image_size_dst,
2757 buffer_padded_row_size);
2759 } else {
2760 uint32 my_unpadded_row_size;
2761 if (total_rows == num_rows)
2762 my_unpadded_row_size = unpadded_row_size;
2763 else
2764 my_unpadded_row_size = pixels_padded_row_size;
2765 CopyRectToBuffer(
2766 source, my_height, my_unpadded_row_size, pixels_padded_row_size,
2767 buffer->address(), buffer_padded_row_size);
2769 helper_->TexSubImage3D(
2770 target, level, xoffset, yoffset + row_index, zoffset + depth_index,
2771 width, my_height, my_depth,
2772 format, type, buffer->shm_id(), buffer->offset(), internal);
2773 buffer->Release();
2775 total_rows -= num_rows;
2776 if (total_rows > 0) {
2777 GLint num_image_paddings;
2778 if (num_images > 0) {
2779 DCHECK_EQ(row_index, 0);
2780 depth_index += num_images;
2781 num_image_paddings = num_images;
2782 } else {
2783 row_index = (row_index + my_height) % height;
2784 num_image_paddings = 0;
2785 if (my_height > 0 && row_index == 0) {
2786 depth_index++;
2787 num_image_paddings++;
2790 source += num_rows * pixels_padded_row_size;
2791 if (unpack_image_height_ > height && num_image_paddings > 0) {
2792 source += num_image_paddings * (unpack_image_height_ - height) *
2793 pixels_padded_row_size;
2799 bool GLES2Implementation::GetActiveAttribHelper(
2800 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2801 GLenum* type, char* name) {
2802 // Clear the bucket so if the command fails nothing will be in it.
2803 helper_->SetBucketSize(kResultBucketId, 0);
2804 typedef cmds::GetActiveAttrib::Result Result;
2805 Result* result = GetResultAs<Result*>();
2806 if (!result) {
2807 return false;
2809 // Set as failed so if the command fails we'll recover.
2810 result->success = false;
2811 helper_->GetActiveAttrib(program, index, kResultBucketId,
2812 GetResultShmId(), GetResultShmOffset());
2813 WaitForCmd();
2814 if (result->success) {
2815 if (size) {
2816 *size = result->size;
2818 if (type) {
2819 *type = result->type;
2821 if (length || name) {
2822 std::vector<int8> str;
2823 GetBucketContents(kResultBucketId, &str);
2824 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2825 std::max(static_cast<size_t>(0),
2826 str.size() - 1));
2827 if (length) {
2828 *length = max_size;
2830 if (name && bufsize > 0) {
2831 memcpy(name, &str[0], max_size);
2832 name[max_size] = '\0';
2836 return result->success != 0;
2839 void GLES2Implementation::GetActiveAttrib(
2840 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2841 GLenum* type, char* name) {
2842 GPU_CLIENT_SINGLE_THREAD_CHECK();
2843 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2844 << program << ", " << index << ", " << bufsize << ", "
2845 << static_cast<const void*>(length) << ", "
2846 << static_cast<const void*>(size) << ", "
2847 << static_cast<const void*>(type) << ", "
2848 << static_cast<const void*>(name) << ", ");
2849 if (bufsize < 0) {
2850 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
2851 return;
2853 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2854 bool success = share_group_->program_info_manager()->GetActiveAttrib(
2855 this, program, index, bufsize, length, size, type, name);
2856 if (success) {
2857 if (size) {
2858 GPU_CLIENT_LOG(" size: " << *size);
2860 if (type) {
2861 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2863 if (name) {
2864 GPU_CLIENT_LOG(" name: " << name);
2867 CheckGLError();
2870 bool GLES2Implementation::GetActiveUniformHelper(
2871 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2872 GLenum* type, char* name) {
2873 // Clear the bucket so if the command fails nothing will be in it.
2874 helper_->SetBucketSize(kResultBucketId, 0);
2875 typedef cmds::GetActiveUniform::Result Result;
2876 Result* result = GetResultAs<Result*>();
2877 if (!result) {
2878 return false;
2880 // Set as failed so if the command fails we'll recover.
2881 result->success = false;
2882 helper_->GetActiveUniform(program, index, kResultBucketId,
2883 GetResultShmId(), GetResultShmOffset());
2884 WaitForCmd();
2885 if (result->success) {
2886 if (size) {
2887 *size = result->size;
2889 if (type) {
2890 *type = result->type;
2892 if (length || name) {
2893 std::vector<int8> str;
2894 GetBucketContents(kResultBucketId, &str);
2895 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2896 std::max(static_cast<size_t>(0),
2897 str.size() - 1));
2898 if (length) {
2899 *length = max_size;
2901 if (name && bufsize > 0) {
2902 memcpy(name, &str[0], max_size);
2903 name[max_size] = '\0';
2907 return result->success != 0;
2910 void GLES2Implementation::GetActiveUniform(
2911 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2912 GLenum* type, char* name) {
2913 GPU_CLIENT_SINGLE_THREAD_CHECK();
2914 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2915 << program << ", " << index << ", " << bufsize << ", "
2916 << static_cast<const void*>(length) << ", "
2917 << static_cast<const void*>(size) << ", "
2918 << static_cast<const void*>(type) << ", "
2919 << static_cast<const void*>(name) << ", ");
2920 if (bufsize < 0) {
2921 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2922 return;
2924 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2925 bool success = share_group_->program_info_manager()->GetActiveUniform(
2926 this, program, index, bufsize, length, size, type, name);
2927 if (success) {
2928 if (size) {
2929 GPU_CLIENT_LOG(" size: " << *size);
2931 if (type) {
2932 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2934 if (name) {
2935 GPU_CLIENT_LOG(" name: " << name);
2938 CheckGLError();
2941 bool GLES2Implementation::GetActiveUniformBlockNameHelper(
2942 GLuint program, GLuint index, GLsizei bufsize,
2943 GLsizei* length, char* name) {
2944 DCHECK_LE(0, bufsize);
2945 // Clear the bucket so if the command fails nothing will be in it.
2946 helper_->SetBucketSize(kResultBucketId, 0);
2947 typedef cmds::GetActiveUniformBlockName::Result Result;
2948 Result* result = GetResultAs<Result*>();
2949 if (!result) {
2950 return false;
2952 // Set as failed so if the command fails we'll recover.
2953 *result = 0;
2954 helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
2955 GetResultShmId(), GetResultShmOffset());
2956 WaitForCmd();
2957 if (*result) {
2958 if (bufsize == 0) {
2959 if (length) {
2960 *length = 0;
2962 } else if (length || name) {
2963 std::vector<int8> str;
2964 GetBucketContents(kResultBucketId, &str);
2965 DCHECK_GT(str.size(), 0u);
2966 GLsizei max_size =
2967 std::min(bufsize, static_cast<GLsizei>(str.size())) - 1;
2968 if (length) {
2969 *length = max_size;
2971 if (name) {
2972 memcpy(name, &str[0], max_size);
2973 name[max_size] = '\0';
2977 return *result != 0;
2980 void GLES2Implementation::GetActiveUniformBlockName(
2981 GLuint program, GLuint index, GLsizei bufsize,
2982 GLsizei* length, char* name) {
2983 GPU_CLIENT_SINGLE_THREAD_CHECK();
2984 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
2985 << program << ", " << index << ", " << bufsize << ", "
2986 << static_cast<const void*>(length) << ", "
2987 << static_cast<const void*>(name) << ")");
2988 if (bufsize < 0) {
2989 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformBlockName", "bufsize < 0");
2990 return;
2992 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockName");
2993 bool success =
2994 share_group_->program_info_manager()->GetActiveUniformBlockName(
2995 this, program, index, bufsize, length, name);
2996 if (success) {
2997 if (name) {
2998 GPU_CLIENT_LOG(" name: " << name);
3001 CheckGLError();
3004 bool GLES2Implementation::GetActiveUniformBlockivHelper(
3005 GLuint program, GLuint index, GLenum pname, GLint* params) {
3006 typedef cmds::GetActiveUniformBlockiv::Result Result;
3007 Result* result = GetResultAs<Result*>();
3008 if (!result) {
3009 return false;
3011 result->SetNumResults(0);
3012 helper_->GetActiveUniformBlockiv(
3013 program, index, pname, GetResultShmId(), GetResultShmOffset());
3014 WaitForCmd();
3015 if (result->GetNumResults() > 0) {
3016 if (params) {
3017 result->CopyResult(params);
3019 GPU_CLIENT_LOG_CODE_BLOCK({
3020 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
3021 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3024 return true;
3026 return false;
3029 void GLES2Implementation::GetActiveUniformBlockiv(
3030 GLuint program, GLuint index, GLenum pname, GLint* params) {
3031 GPU_CLIENT_SINGLE_THREAD_CHECK();
3032 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
3033 << program << ", " << index << ", "
3034 << GLES2Util::GetStringUniformBlockParameter(pname) << ", "
3035 << static_cast<const void*>(params) << ")");
3036 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
3037 bool success =
3038 share_group_->program_info_manager()->GetActiveUniformBlockiv(
3039 this, program, index, pname, params);
3040 if (success) {
3041 if (params) {
3042 // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
3043 // be more than one value returned in params.
3044 GPU_CLIENT_LOG(" params: " << params[0]);
3047 CheckGLError();
3050 bool GLES2Implementation::GetActiveUniformsivHelper(
3051 GLuint program, GLsizei count, const GLuint* indices,
3052 GLenum pname, GLint* params) {
3053 typedef cmds::GetActiveUniformsiv::Result Result;
3054 Result* result = GetResultAs<Result*>();
3055 if (!result) {
3056 return false;
3058 result->SetNumResults(0);
3059 base::CheckedNumeric<size_t> bytes = static_cast<size_t>(count);
3060 bytes *= sizeof(GLuint);
3061 if (!bytes.IsValid()) {
3062 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count overflow");
3063 return false;
3065 SetBucketContents(kResultBucketId, indices, bytes.ValueOrDefault(0));
3066 helper_->GetActiveUniformsiv(
3067 program, kResultBucketId, pname, GetResultShmId(), GetResultShmOffset());
3068 WaitForCmd();
3069 bool success = result->GetNumResults() == count;
3070 if (success) {
3071 if (params) {
3072 result->CopyResult(params);
3074 GPU_CLIENT_LOG_CODE_BLOCK({
3075 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
3076 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3080 helper_->SetBucketSize(kResultBucketId, 0);
3081 return success;
3084 void GLES2Implementation::GetActiveUniformsiv(
3085 GLuint program, GLsizei count, const GLuint* indices,
3086 GLenum pname, GLint* params) {
3087 GPU_CLIENT_SINGLE_THREAD_CHECK();
3088 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv("
3089 << program << ", " << count << ", "
3090 << static_cast<const void*>(indices) << ", "
3091 << GLES2Util::GetStringUniformParameter(pname) << ", "
3092 << static_cast<const void*>(params) << ")");
3093 TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
3094 if (count < 0) {
3095 SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count < 0");
3096 return;
3098 bool success = share_group_->program_info_manager()->GetActiveUniformsiv(
3099 this, program, count, indices, pname, params);
3100 if (success) {
3101 if (params) {
3102 GPU_CLIENT_LOG_CODE_BLOCK({
3103 for (GLsizei ii = 0; ii < count; ++ii) {
3104 GPU_CLIENT_LOG(" " << ii << ": " << params[ii]);
3109 CheckGLError();
3112 void GLES2Implementation::GetAttachedShaders(
3113 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
3114 GPU_CLIENT_SINGLE_THREAD_CHECK();
3115 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
3116 << program << ", " << maxcount << ", "
3117 << static_cast<const void*>(count) << ", "
3118 << static_cast<const void*>(shaders) << ", ");
3119 if (maxcount < 0) {
3120 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
3121 return;
3123 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
3124 typedef cmds::GetAttachedShaders::Result Result;
3125 uint32 size = Result::ComputeSize(maxcount);
3126 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
3127 if (!result) {
3128 return;
3130 result->SetNumResults(0);
3131 helper_->GetAttachedShaders(
3132 program,
3133 transfer_buffer_->GetShmId(),
3134 transfer_buffer_->GetOffset(result),
3135 size);
3136 int32 token = helper_->InsertToken();
3137 WaitForCmd();
3138 if (count) {
3139 *count = result->GetNumResults();
3141 result->CopyResult(shaders);
3142 GPU_CLIENT_LOG_CODE_BLOCK({
3143 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3144 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3147 transfer_buffer_->FreePendingToken(result, token);
3148 CheckGLError();
3151 void GLES2Implementation::GetShaderPrecisionFormat(
3152 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
3153 GPU_CLIENT_SINGLE_THREAD_CHECK();
3154 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
3155 << GLES2Util::GetStringShaderType(shadertype) << ", "
3156 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
3157 << static_cast<const void*>(range) << ", "
3158 << static_cast<const void*>(precision) << ", ");
3159 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
3160 typedef cmds::GetShaderPrecisionFormat::Result Result;
3161 Result* result = GetResultAs<Result*>();
3162 if (!result) {
3163 return;
3166 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
3167 GLStaticState::ShaderPrecisionMap::iterator i =
3168 static_state_.shader_precisions.find(key);
3169 if (i != static_state_.shader_precisions.end()) {
3170 *result = i->second;
3171 } else {
3172 result->success = false;
3173 helper_->GetShaderPrecisionFormat(
3174 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
3175 WaitForCmd();
3176 if (result->success)
3177 static_state_.shader_precisions[key] = *result;
3180 if (result->success) {
3181 if (range) {
3182 range[0] = result->min_range;
3183 range[1] = result->max_range;
3184 GPU_CLIENT_LOG(" min_range: " << range[0]);
3185 GPU_CLIENT_LOG(" min_range: " << range[1]);
3187 if (precision) {
3188 precision[0] = result->precision;
3189 GPU_CLIENT_LOG(" min_range: " << precision[0]);
3192 CheckGLError();
3195 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
3196 const char* result = NULL;
3197 // Clears the bucket so if the command fails nothing will be in it.
3198 helper_->SetBucketSize(kResultBucketId, 0);
3199 helper_->GetString(name, kResultBucketId);
3200 std::string str;
3201 if (GetBucketAsString(kResultBucketId, &str)) {
3202 // Adds extensions implemented on client side only.
3203 switch (name) {
3204 case GL_EXTENSIONS:
3205 str += std::string(str.empty() ? "" : " ") +
3206 "GL_EXT_unpack_subimage "
3207 "GL_CHROMIUM_map_sub";
3208 if (capabilities_.image)
3209 str += " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
3210 if (capabilities_.future_sync_points)
3211 str += " GL_CHROMIUM_future_sync_point";
3212 break;
3213 default:
3214 break;
3217 // Because of WebGL the extensions can change. We have to cache each unique
3218 // result since we don't know when the client will stop referring to a
3219 // previous one it queries.
3220 GLStringMap::iterator it = gl_strings_.find(name);
3221 if (it == gl_strings_.end()) {
3222 std::set<std::string> strings;
3223 std::pair<GLStringMap::iterator, bool> insert_result =
3224 gl_strings_.insert(std::make_pair(name, strings));
3225 DCHECK(insert_result.second);
3226 it = insert_result.first;
3228 std::set<std::string>& string_set = it->second;
3229 std::set<std::string>::const_iterator sit = string_set.find(str);
3230 if (sit != string_set.end()) {
3231 result = sit->c_str();
3232 } else {
3233 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
3234 string_set.insert(str);
3235 DCHECK(insert_result.second);
3236 result = insert_result.first->c_str();
3239 return reinterpret_cast<const GLubyte*>(result);
3242 const GLubyte* GLES2Implementation::GetString(GLenum name) {
3243 GPU_CLIENT_SINGLE_THREAD_CHECK();
3244 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
3245 << GLES2Util::GetStringStringType(name) << ")");
3246 TRACE_EVENT0("gpu", "GLES2::GetString");
3247 const GLubyte* result = GetStringHelper(name);
3248 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
3249 CheckGLError();
3250 return result;
3253 bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
3254 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3255 GLenum* type, char* name) {
3256 // Clear the bucket so if the command fails nothing will be in it.
3257 helper_->SetBucketSize(kResultBucketId, 0);
3258 typedef cmds::GetTransformFeedbackVarying::Result Result;
3259 Result* result = GetResultAs<Result*>();
3260 if (!result) {
3261 return false;
3263 // Set as failed so if the command fails we'll recover.
3264 result->success = false;
3265 helper_->GetTransformFeedbackVarying(
3266 program, index, kResultBucketId, GetResultShmId(), GetResultShmOffset());
3267 WaitForCmd();
3268 if (result->success) {
3269 if (size) {
3270 *size = result->size;
3272 if (type) {
3273 *type = result->type;
3275 if (length || name) {
3276 std::vector<int8> str;
3277 GetBucketContents(kResultBucketId, &str);
3278 GLsizei max_size = std::min(bufsize, static_cast<GLsizei>(str.size()));
3279 if (max_size > 0) {
3280 --max_size;
3282 if (length) {
3283 *length = max_size;
3285 if (name) {
3286 if (max_size > 0) {
3287 memcpy(name, &str[0], max_size);
3288 name[max_size] = '\0';
3289 } else if (bufsize > 0) {
3290 name[0] = '\0';
3295 return result->success != 0;
3298 void GLES2Implementation::GetTransformFeedbackVarying(
3299 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
3300 GLenum* type, char* name) {
3301 GPU_CLIENT_SINGLE_THREAD_CHECK();
3302 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
3303 << program << ", " << index << ", " << bufsize << ", "
3304 << static_cast<const void*>(length) << ", "
3305 << static_cast<const void*>(size) << ", "
3306 << static_cast<const void*>(type) << ", "
3307 << static_cast<const void*>(name) << ", ");
3308 if (bufsize < 0) {
3309 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVarying",
3310 "bufsize < 0");
3311 return;
3313 TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
3314 bool success =
3315 share_group_->program_info_manager()->GetTransformFeedbackVarying(
3316 this, program, index, bufsize, length, size, type, name);
3317 if (success) {
3318 if (size) {
3319 GPU_CLIENT_LOG(" size: " << *size);
3321 if (type) {
3322 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
3324 if (name) {
3325 GPU_CLIENT_LOG(" name: " << name);
3328 CheckGLError();
3331 void GLES2Implementation::GetUniformfv(
3332 GLuint program, GLint location, GLfloat* params) {
3333 GPU_CLIENT_SINGLE_THREAD_CHECK();
3334 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
3335 << program << ", " << location << ", "
3336 << static_cast<const void*>(params) << ")");
3337 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
3338 typedef cmds::GetUniformfv::Result Result;
3339 Result* result = GetResultAs<Result*>();
3340 if (!result) {
3341 return;
3343 result->SetNumResults(0);
3344 helper_->GetUniformfv(
3345 program, location, GetResultShmId(), GetResultShmOffset());
3346 WaitForCmd();
3347 result->CopyResult(params);
3348 GPU_CLIENT_LOG_CODE_BLOCK({
3349 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3350 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3353 CheckGLError();
3356 void GLES2Implementation::GetUniformiv(
3357 GLuint program, GLint location, GLint* params) {
3358 GPU_CLIENT_SINGLE_THREAD_CHECK();
3359 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
3360 << program << ", " << location << ", "
3361 << static_cast<const void*>(params) << ")");
3362 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
3363 typedef cmds::GetUniformiv::Result Result;
3364 Result* result = GetResultAs<Result*>();
3365 if (!result) {
3366 return;
3368 result->SetNumResults(0);
3369 helper_->GetUniformiv(
3370 program, location, GetResultShmId(), GetResultShmOffset());
3371 WaitForCmd();
3372 GetResultAs<cmds::GetUniformiv::Result*>()->CopyResult(params);
3373 GPU_CLIENT_LOG_CODE_BLOCK({
3374 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3375 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3378 CheckGLError();
3381 void GLES2Implementation::GetUniformuiv(
3382 GLuint program, GLint location, GLuint* params) {
3383 GPU_CLIENT_SINGLE_THREAD_CHECK();
3384 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformuiv("
3385 << program << ", " << location << ", "
3386 << static_cast<const void*>(params) << ")");
3387 TRACE_EVENT0("gpu", "GLES2::GetUniformuiv");
3388 typedef cmds::GetUniformuiv::Result Result;
3389 Result* result = GetResultAs<Result*>();
3390 if (!result) {
3391 return;
3393 result->SetNumResults(0);
3394 helper_->GetUniformuiv(
3395 program, location, GetResultShmId(), GetResultShmOffset());
3396 WaitForCmd();
3397 GetResultAs<cmds::GetUniformuiv::Result*>()->CopyResult(params);
3398 GPU_CLIENT_LOG_CODE_BLOCK({
3399 for (int32 i = 0; i < result->GetNumResults(); ++i) {
3400 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
3403 CheckGLError();
3406 void GLES2Implementation::ReadPixels(
3407 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
3408 GLenum type, void* pixels) {
3409 GPU_CLIENT_SINGLE_THREAD_CHECK();
3410 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
3411 << xoffset << ", " << yoffset << ", "
3412 << width << ", " << height << ", "
3413 << GLES2Util::GetStringReadPixelFormat(format) << ", "
3414 << GLES2Util::GetStringPixelType(type) << ", "
3415 << static_cast<const void*>(pixels) << ")");
3416 if (width < 0 || height < 0) {
3417 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
3418 return;
3420 if (width == 0 || height == 0) {
3421 return;
3424 // glReadPixel pads the size of each row of pixels by an amount specified by
3425 // glPixelStorei. So, we have to take that into account both in the fact that
3426 // the pixels returned from the ReadPixel command will include that padding
3427 // and that when we copy the results to the user's buffer we need to not
3428 // write those padding bytes but leave them as they are.
3430 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
3431 typedef cmds::ReadPixels::Result Result;
3433 int8* dest = reinterpret_cast<int8*>(pixels);
3434 uint32 temp_size;
3435 uint32 unpadded_row_size;
3436 uint32 padded_row_size;
3437 if (!GLES2Util::ComputeImageDataSizes(
3438 width, 2, 1, format, type, pack_alignment_, &temp_size,
3439 &unpadded_row_size, &padded_row_size)) {
3440 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
3441 return;
3444 if (bound_pixel_pack_transfer_buffer_id_) {
3445 GLuint offset = ToGLuint(pixels);
3446 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3447 bound_pixel_pack_transfer_buffer_id_,
3448 "glReadPixels", offset, padded_row_size * height);
3449 if (buffer && buffer->shm_id() != -1) {
3450 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
3451 buffer->shm_id(), buffer->shm_offset(),
3452 0, 0, true);
3453 CheckGLError();
3455 return;
3458 if (!pixels) {
3459 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
3460 return;
3463 // Transfer by rows.
3464 // The max rows we can transfer.
3465 while (height) {
3466 GLsizei desired_size = padded_row_size * (height - 1) + unpadded_row_size;
3467 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
3468 if (!buffer.valid()) {
3469 return;
3471 GLint num_rows = ComputeNumRowsThatFitInBuffer(
3472 padded_row_size, unpadded_row_size, buffer.size(), height);
3473 num_rows = std::min(num_rows, height);
3474 // NOTE: We must look up the address of the result area AFTER allocation
3475 // of the transfer buffer since the transfer buffer may be reallocated.
3476 Result* result = GetResultAs<Result*>();
3477 if (!result) {
3478 return;
3480 *result = 0; // mark as failed.
3481 helper_->ReadPixels(
3482 xoffset, yoffset, width, num_rows, format, type,
3483 buffer.shm_id(), buffer.offset(),
3484 GetResultShmId(), GetResultShmOffset(),
3485 false);
3486 WaitForCmd();
3487 if (*result != 0) {
3488 // when doing a y-flip we have to iterate through top-to-bottom chunks
3489 // of the dst. The service side handles reversing the rows within a
3490 // chunk.
3491 int8* rows_dst;
3492 if (pack_reverse_row_order_) {
3493 rows_dst = dest + (height - num_rows) * padded_row_size;
3494 } else {
3495 rows_dst = dest;
3497 // We have to copy 1 row at a time to avoid writing pad bytes.
3498 const int8* src = static_cast<const int8*>(buffer.address());
3499 for (GLint yy = 0; yy < num_rows; ++yy) {
3500 memcpy(rows_dst, src, unpadded_row_size);
3501 rows_dst += padded_row_size;
3502 src += padded_row_size;
3504 if (!pack_reverse_row_order_) {
3505 dest = rows_dst;
3508 // If it was not marked as successful exit.
3509 if (*result == 0) {
3510 return;
3512 yoffset += num_rows;
3513 height -= num_rows;
3515 CheckGLError();
3518 void GLES2Implementation::ActiveTexture(GLenum texture) {
3519 GPU_CLIENT_SINGLE_THREAD_CHECK();
3520 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
3521 << GLES2Util::GetStringEnum(texture) << ")");
3522 GLuint texture_index = texture - GL_TEXTURE0;
3523 if (texture_index >=
3524 static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
3525 SetGLErrorInvalidEnum(
3526 "glActiveTexture", texture, "texture");
3527 return;
3530 active_texture_unit_ = texture_index;
3531 helper_->ActiveTexture(texture);
3532 CheckGLError();
3535 void GLES2Implementation::GenBuffersHelper(
3536 GLsizei /* n */, const GLuint* /* buffers */) {
3539 void GLES2Implementation::GenFramebuffersHelper(
3540 GLsizei /* n */, const GLuint* /* framebuffers */) {
3543 void GLES2Implementation::GenRenderbuffersHelper(
3544 GLsizei /* n */, const GLuint* /* renderbuffers */) {
3547 void GLES2Implementation::GenTexturesHelper(
3548 GLsizei /* n */, const GLuint* /* textures */) {
3551 void GLES2Implementation::GenVertexArraysOESHelper(
3552 GLsizei n, const GLuint* arrays) {
3553 vertex_array_object_manager_->GenVertexArrays(n, arrays);
3556 void GLES2Implementation::GenQueriesEXTHelper(
3557 GLsizei /* n */, const GLuint* /* queries */) {
3560 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
3561 GLsizei /* n */,
3562 const GLuint* /* valuebuffers */) {
3565 void GLES2Implementation::GenSamplersHelper(
3566 GLsizei /* n */, const GLuint* /* samplers */) {
3569 void GLES2Implementation::GenTransformFeedbacksHelper(
3570 GLsizei /* n */, const GLuint* /* transformfeedbacks */) {
3573 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
3574 // generates a new resource. On newer versions of OpenGL they don't. The code
3575 // related to binding below will need to change if we switch to the new OpenGL
3576 // model. Specifically it assumes a bind will succeed which is always true in
3577 // the old model but possibly not true in the new model if another context has
3578 // deleted the resource.
3580 // NOTE #2: There is a bug in some BindXXXHelpers, that IDs might be marked as
3581 // used even when Bind has failed. However, the bug is minor compared to the
3582 // overhead & duplicated checking in client side.
3584 void GLES2Implementation::BindBufferHelper(
3585 GLenum target, GLuint buffer_id) {
3586 // TODO(gman): See note #1 above.
3587 bool changed = false;
3588 switch (target) {
3589 case GL_ARRAY_BUFFER:
3590 if (bound_array_buffer_ != buffer_id) {
3591 bound_array_buffer_ = buffer_id;
3592 changed = true;
3594 break;
3595 case GL_COPY_READ_BUFFER:
3596 if (bound_copy_read_buffer_ != buffer_id) {
3597 bound_copy_read_buffer_ = buffer_id;
3598 changed = true;
3600 break;
3601 case GL_COPY_WRITE_BUFFER:
3602 if (bound_copy_write_buffer_ != buffer_id) {
3603 bound_copy_write_buffer_ = buffer_id;
3604 changed = true;
3606 break;
3607 case GL_ELEMENT_ARRAY_BUFFER:
3608 changed = vertex_array_object_manager_->BindElementArray(buffer_id);
3609 break;
3610 case GL_PIXEL_PACK_BUFFER:
3611 if (bound_pixel_pack_buffer_ != buffer_id) {
3612 bound_pixel_pack_buffer_ = buffer_id;
3613 changed = true;
3615 break;
3616 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3617 bound_pixel_pack_transfer_buffer_id_ = buffer_id;
3618 break;
3619 case GL_PIXEL_UNPACK_BUFFER:
3620 if (bound_pixel_unpack_buffer_ != buffer_id) {
3621 bound_pixel_unpack_buffer_ = buffer_id;
3622 changed = true;
3624 break;
3625 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3626 bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
3627 break;
3628 case GL_TRANSFORM_FEEDBACK_BUFFER:
3629 if (bound_transform_feedback_buffer_ != buffer_id) {
3630 bound_transform_feedback_buffer_ = buffer_id;
3631 changed = true;
3633 break;
3634 case GL_UNIFORM_BUFFER:
3635 if (bound_uniform_buffer_ != buffer_id) {
3636 bound_uniform_buffer_ = buffer_id;
3637 changed = true;
3639 break;
3640 default:
3641 changed = true;
3642 break;
3644 // TODO(gman): See note #2 above.
3645 if (changed) {
3646 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3647 this, target, buffer_id, &GLES2Implementation::BindBufferStub);
3651 void GLES2Implementation::BindBufferStub(GLenum target, GLuint buffer) {
3652 helper_->BindBuffer(target, buffer);
3653 if (share_group_->bind_generates_resource())
3654 helper_->CommandBufferHelper::OrderingBarrier();
3657 void GLES2Implementation::BindBufferBaseHelper(
3658 GLenum target, GLuint index, GLuint buffer_id) {
3659 // TODO(zmo): See note #1 above.
3660 // TODO(zmo): See note #2 above.
3661 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3662 this, target, index, buffer_id, &GLES2Implementation::BindBufferBaseStub);
3665 void GLES2Implementation::BindBufferBaseStub(
3666 GLenum target, GLuint index, GLuint buffer) {
3667 helper_->BindBufferBase(target, index, buffer);
3668 if (share_group_->bind_generates_resource())
3669 helper_->CommandBufferHelper::Flush();
3672 void GLES2Implementation::BindBufferRangeHelper(
3673 GLenum target, GLuint index, GLuint buffer_id,
3674 GLintptr offset, GLsizeiptr size) {
3675 // TODO(zmo): See note #1 above.
3676 // TODO(zmo): See note #2 above.
3677 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(
3678 this, target, index, buffer_id, offset, size,
3679 &GLES2Implementation::BindBufferRangeStub);
3682 void GLES2Implementation::BindBufferRangeStub(
3683 GLenum target, GLuint index, GLuint buffer,
3684 GLintptr offset, GLsizeiptr size) {
3685 helper_->BindBufferRange(target, index, buffer, offset, size);
3686 if (share_group_->bind_generates_resource())
3687 helper_->CommandBufferHelper::Flush();
3690 void GLES2Implementation::BindFramebufferHelper(
3691 GLenum target, GLuint framebuffer) {
3692 // TODO(gman): See note #1 above.
3693 bool changed = false;
3694 switch (target) {
3695 case GL_FRAMEBUFFER:
3696 if (bound_framebuffer_ != framebuffer ||
3697 bound_read_framebuffer_ != framebuffer) {
3698 bound_framebuffer_ = framebuffer;
3699 bound_read_framebuffer_ = framebuffer;
3700 changed = true;
3702 break;
3703 case GL_READ_FRAMEBUFFER:
3704 if (!IsChromiumFramebufferMultisampleAvailable()) {
3705 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3706 return;
3708 if (bound_read_framebuffer_ != framebuffer) {
3709 bound_read_framebuffer_ = framebuffer;
3710 changed = true;
3712 break;
3713 case GL_DRAW_FRAMEBUFFER:
3714 if (!IsChromiumFramebufferMultisampleAvailable()) {
3715 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3716 return;
3718 if (bound_framebuffer_ != framebuffer) {
3719 bound_framebuffer_ = framebuffer;
3720 changed = true;
3722 break;
3723 default:
3724 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
3725 return;
3728 if (changed) {
3729 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(
3730 this, target, framebuffer, &GLES2Implementation::BindFramebufferStub);
3734 void GLES2Implementation::BindFramebufferStub(GLenum target,
3735 GLuint framebuffer) {
3736 helper_->BindFramebuffer(target, framebuffer);
3737 if (share_group_->bind_generates_resource())
3738 helper_->CommandBufferHelper::OrderingBarrier();
3741 void GLES2Implementation::BindRenderbufferHelper(
3742 GLenum target, GLuint renderbuffer) {
3743 // TODO(gman): See note #1 above.
3744 bool changed = false;
3745 switch (target) {
3746 case GL_RENDERBUFFER:
3747 if (bound_renderbuffer_ != renderbuffer) {
3748 bound_renderbuffer_ = renderbuffer;
3749 changed = true;
3751 break;
3752 default:
3753 changed = true;
3754 break;
3756 // TODO(zmo): See note #2 above.
3757 if (changed) {
3758 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(
3759 this, target, renderbuffer,
3760 &GLES2Implementation::BindRenderbufferStub);
3764 void GLES2Implementation::BindRenderbufferStub(GLenum target,
3765 GLuint renderbuffer) {
3766 helper_->BindRenderbuffer(target, renderbuffer);
3767 if (share_group_->bind_generates_resource())
3768 helper_->CommandBufferHelper::OrderingBarrier();
3771 void GLES2Implementation::BindSamplerHelper(GLuint unit,
3772 GLuint sampler) {
3773 helper_->BindSampler(unit, sampler);
3776 void GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
3777 // TODO(gman): See note #1 above.
3778 // TODO(gman): Change this to false once we figure out why it's failing
3779 // on daisy.
3780 bool changed = true;
3781 TextureUnit& unit = texture_units_[active_texture_unit_];
3782 switch (target) {
3783 case GL_TEXTURE_2D:
3784 if (unit.bound_texture_2d != texture) {
3785 unit.bound_texture_2d = texture;
3786 changed = true;
3788 break;
3789 case GL_TEXTURE_CUBE_MAP:
3790 if (unit.bound_texture_cube_map != texture) {
3791 unit.bound_texture_cube_map = texture;
3792 changed = true;
3794 break;
3795 case GL_TEXTURE_EXTERNAL_OES:
3796 if (unit.bound_texture_external_oes != texture) {
3797 unit.bound_texture_external_oes = texture;
3798 changed = true;
3800 break;
3801 default:
3802 changed = true;
3803 break;
3805 // TODO(gman): See note #2 above.
3806 if (changed) {
3807 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(
3808 this, target, texture, &GLES2Implementation::BindTextureStub);
3812 void GLES2Implementation::BindTextureStub(GLenum target, GLuint texture) {
3813 helper_->BindTexture(target, texture);
3814 if (share_group_->bind_generates_resource())
3815 helper_->CommandBufferHelper::OrderingBarrier();
3818 void GLES2Implementation::BindTransformFeedbackHelper(
3819 GLenum target, GLuint transformfeedback) {
3820 helper_->BindTransformFeedback(target, transformfeedback);
3823 void GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
3824 bool changed = false;
3825 if (vertex_array_object_manager_->BindVertexArray(array, &changed)) {
3826 if (changed) {
3827 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
3828 // because unlike other resources VertexArrayObject ids must
3829 // be generated by GenVertexArrays. A random id to Bind will not
3830 // generate a new object.
3831 helper_->BindVertexArrayOES(array);
3833 } else {
3834 SetGLError(
3835 GL_INVALID_OPERATION, "glBindVertexArrayOES",
3836 "id was not generated with glGenVertexArrayOES");
3840 void GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
3841 GLuint valuebuffer) {
3842 bool changed = false;
3843 switch (target) {
3844 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
3845 if (bound_valuebuffer_ != valuebuffer) {
3846 bound_valuebuffer_ = valuebuffer;
3847 changed = true;
3849 break;
3850 default:
3851 changed = true;
3852 break;
3854 // TODO(gman): See note #2 above.
3855 if (changed) {
3856 GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(
3857 this, target, valuebuffer,
3858 &GLES2Implementation::BindValuebufferCHROMIUMStub);
3862 void GLES2Implementation::BindValuebufferCHROMIUMStub(GLenum target,
3863 GLuint valuebuffer) {
3864 helper_->BindValuebufferCHROMIUM(target, valuebuffer);
3865 if (share_group_->bind_generates_resource())
3866 helper_->CommandBufferHelper::OrderingBarrier();
3869 void GLES2Implementation::UseProgramHelper(GLuint program) {
3870 if (current_program_ != program) {
3871 current_program_ = program;
3872 helper_->UseProgram(program);
3876 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
3877 return vertex_array_object_manager_->IsReservedId(id);
3880 void GLES2Implementation::DeleteBuffersHelper(
3881 GLsizei n, const GLuint* buffers) {
3882 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
3883 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
3884 SetGLError(
3885 GL_INVALID_VALUE,
3886 "glDeleteBuffers", "id not created by this context.");
3887 return;
3889 for (GLsizei ii = 0; ii < n; ++ii) {
3890 if (buffers[ii] == bound_array_buffer_) {
3891 bound_array_buffer_ = 0;
3893 if (buffers[ii] == bound_copy_read_buffer_) {
3894 bound_copy_read_buffer_ = 0;
3896 if (buffers[ii] == bound_copy_write_buffer_) {
3897 bound_copy_write_buffer_ = 0;
3899 if (buffers[ii] == bound_pixel_pack_buffer_) {
3900 bound_pixel_pack_buffer_ = 0;
3902 if (buffers[ii] == bound_pixel_unpack_buffer_) {
3903 bound_pixel_unpack_buffer_ = 0;
3905 if (buffers[ii] == bound_transform_feedback_buffer_) {
3906 bound_transform_feedback_buffer_ = 0;
3908 if (buffers[ii] == bound_uniform_buffer_) {
3909 bound_uniform_buffer_ = 0;
3911 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
3913 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
3914 if (buffer)
3915 RemoveTransferBuffer(buffer);
3917 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
3918 bound_pixel_unpack_transfer_buffer_id_ = 0;
3921 RemoveMappedBufferRangeById(buffers[ii]);
3925 void GLES2Implementation::DeleteBuffersStub(
3926 GLsizei n, const GLuint* buffers) {
3927 helper_->DeleteBuffersImmediate(n, buffers);
3931 void GLES2Implementation::DeleteFramebuffersHelper(
3932 GLsizei n, const GLuint* framebuffers) {
3933 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
3934 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
3935 SetGLError(
3936 GL_INVALID_VALUE,
3937 "glDeleteFramebuffers", "id not created by this context.");
3938 return;
3940 for (GLsizei ii = 0; ii < n; ++ii) {
3941 if (framebuffers[ii] == bound_framebuffer_) {
3942 bound_framebuffer_ = 0;
3944 if (framebuffers[ii] == bound_read_framebuffer_) {
3945 bound_read_framebuffer_ = 0;
3950 void GLES2Implementation::DeleteFramebuffersStub(
3951 GLsizei n, const GLuint* framebuffers) {
3952 helper_->DeleteFramebuffersImmediate(n, framebuffers);
3955 void GLES2Implementation::DeleteRenderbuffersHelper(
3956 GLsizei n, const GLuint* renderbuffers) {
3957 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
3958 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
3959 SetGLError(
3960 GL_INVALID_VALUE,
3961 "glDeleteRenderbuffers", "id not created by this context.");
3962 return;
3964 for (GLsizei ii = 0; ii < n; ++ii) {
3965 if (renderbuffers[ii] == bound_renderbuffer_) {
3966 bound_renderbuffer_ = 0;
3971 void GLES2Implementation::DeleteRenderbuffersStub(
3972 GLsizei n, const GLuint* renderbuffers) {
3973 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
3976 void GLES2Implementation::DeleteTexturesHelper(
3977 GLsizei n, const GLuint* textures) {
3978 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
3979 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
3980 SetGLError(
3981 GL_INVALID_VALUE,
3982 "glDeleteTextures", "id not created by this context.");
3983 return;
3985 for (GLsizei ii = 0; ii < n; ++ii) {
3986 for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
3987 ++tt) {
3988 TextureUnit& unit = texture_units_[tt];
3989 if (textures[ii] == unit.bound_texture_2d) {
3990 unit.bound_texture_2d = 0;
3992 if (textures[ii] == unit.bound_texture_cube_map) {
3993 unit.bound_texture_cube_map = 0;
3995 if (textures[ii] == unit.bound_texture_external_oes) {
3996 unit.bound_texture_external_oes = 0;
4002 void GLES2Implementation::DeleteTexturesStub(GLsizei n,
4003 const GLuint* textures) {
4004 helper_->DeleteTexturesImmediate(n, textures);
4007 void GLES2Implementation::DeleteVertexArraysOESHelper(
4008 GLsizei n, const GLuint* arrays) {
4009 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
4010 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
4011 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
4012 SetGLError(
4013 GL_INVALID_VALUE,
4014 "glDeleteVertexArraysOES", "id not created by this context.");
4015 return;
4019 void GLES2Implementation::DeleteVertexArraysOESStub(
4020 GLsizei n, const GLuint* arrays) {
4021 helper_->DeleteVertexArraysOESImmediate(n, arrays);
4024 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
4025 GLsizei n,
4026 const GLuint* valuebuffers) {
4027 if (!GetIdHandler(id_namespaces::kValuebuffers)
4028 ->FreeIds(this, n, valuebuffers,
4029 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
4030 SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
4031 "id not created by this context.");
4032 return;
4034 for (GLsizei ii = 0; ii < n; ++ii) {
4035 if (valuebuffers[ii] == bound_valuebuffer_) {
4036 bound_valuebuffer_ = 0;
4041 void GLES2Implementation::DeleteSamplersStub(
4042 GLsizei n, const GLuint* samplers) {
4043 helper_->DeleteSamplersImmediate(n, samplers);
4046 void GLES2Implementation::DeleteSamplersHelper(
4047 GLsizei n, const GLuint* samplers) {
4048 if (!GetIdHandler(id_namespaces::kSamplers)->FreeIds(
4049 this, n, samplers, &GLES2Implementation::DeleteSamplersStub)) {
4050 SetGLError(
4051 GL_INVALID_VALUE,
4052 "glDeleteSamplers", "id not created by this context.");
4053 return;
4057 void GLES2Implementation::DeleteTransformFeedbacksStub(
4058 GLsizei n, const GLuint* transformfeedbacks) {
4059 helper_->DeleteTransformFeedbacksImmediate(n, transformfeedbacks);
4062 void GLES2Implementation::DeleteTransformFeedbacksHelper(
4063 GLsizei n, const GLuint* transformfeedbacks) {
4064 if (!GetIdHandler(id_namespaces::kTransformFeedbacks)->FreeIds(
4065 this, n, transformfeedbacks,
4066 &GLES2Implementation::DeleteTransformFeedbacksStub)) {
4067 SetGLError(
4068 GL_INVALID_VALUE,
4069 "glDeleteTransformFeedbacks", "id not created by this context.");
4070 return;
4074 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
4075 GLsizei n,
4076 const GLuint* valuebuffers) {
4077 helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
4080 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
4081 GPU_CLIENT_SINGLE_THREAD_CHECK();
4082 GPU_CLIENT_LOG(
4083 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
4084 vertex_array_object_manager_->SetAttribEnable(index, false);
4085 helper_->DisableVertexAttribArray(index);
4086 CheckGLError();
4089 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
4090 GPU_CLIENT_SINGLE_THREAD_CHECK();
4091 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
4092 << index << ")");
4093 vertex_array_object_manager_->SetAttribEnable(index, true);
4094 helper_->EnableVertexAttribArray(index);
4095 CheckGLError();
4098 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
4099 GPU_CLIENT_SINGLE_THREAD_CHECK();
4100 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
4101 << GLES2Util::GetStringDrawMode(mode) << ", "
4102 << first << ", " << count << ")");
4103 if (count < 0) {
4104 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
4105 return;
4107 bool simulated = false;
4108 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
4109 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
4110 return;
4112 helper_->DrawArrays(mode, first, count);
4113 RestoreArrayBuffer(simulated);
4114 CheckGLError();
4117 void GLES2Implementation::GetVertexAttribfv(
4118 GLuint index, GLenum pname, GLfloat* params) {
4119 GPU_CLIENT_SINGLE_THREAD_CHECK();
4120 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
4121 << index << ", "
4122 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4123 << static_cast<const void*>(params) << ")");
4124 uint32 value = 0;
4125 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4126 *params = static_cast<GLfloat>(value);
4127 return;
4129 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
4130 typedef cmds::GetVertexAttribfv::Result Result;
4131 Result* result = GetResultAs<Result*>();
4132 if (!result) {
4133 return;
4135 result->SetNumResults(0);
4136 helper_->GetVertexAttribfv(
4137 index, pname, GetResultShmId(), GetResultShmOffset());
4138 WaitForCmd();
4139 result->CopyResult(params);
4140 GPU_CLIENT_LOG_CODE_BLOCK({
4141 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4142 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4145 CheckGLError();
4148 void GLES2Implementation::GetVertexAttribiv(
4149 GLuint index, GLenum pname, GLint* params) {
4150 GPU_CLIENT_SINGLE_THREAD_CHECK();
4151 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
4152 << index << ", "
4153 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4154 << static_cast<const void*>(params) << ")");
4155 uint32 value = 0;
4156 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4157 *params = static_cast<GLint>(value);
4158 return;
4160 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
4161 typedef cmds::GetVertexAttribiv::Result Result;
4162 Result* result = GetResultAs<Result*>();
4163 if (!result) {
4164 return;
4166 result->SetNumResults(0);
4167 helper_->GetVertexAttribiv(
4168 index, pname, GetResultShmId(), GetResultShmOffset());
4169 WaitForCmd();
4170 result->CopyResult(params);
4171 GPU_CLIENT_LOG_CODE_BLOCK({
4172 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4173 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4176 CheckGLError();
4179 void GLES2Implementation::GetVertexAttribIiv(
4180 GLuint index, GLenum pname, GLint* params) {
4181 GPU_CLIENT_SINGLE_THREAD_CHECK();
4182 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIiv("
4183 << index << ", "
4184 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4185 << static_cast<const void*>(params) << ")");
4186 uint32 value = 0;
4187 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4188 *params = static_cast<GLint>(value);
4189 return;
4191 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIiv");
4192 typedef cmds::GetVertexAttribiv::Result Result;
4193 Result* result = GetResultAs<Result*>();
4194 if (!result) {
4195 return;
4197 result->SetNumResults(0);
4198 helper_->GetVertexAttribIiv(
4199 index, pname, GetResultShmId(), GetResultShmOffset());
4200 WaitForCmd();
4201 result->CopyResult(params);
4202 GPU_CLIENT_LOG_CODE_BLOCK({
4203 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4204 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4207 CheckGLError();
4210 void GLES2Implementation::GetVertexAttribIuiv(
4211 GLuint index, GLenum pname, GLuint* params) {
4212 GPU_CLIENT_SINGLE_THREAD_CHECK();
4213 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribIuiv("
4214 << index << ", "
4215 << GLES2Util::GetStringVertexAttribute(pname) << ", "
4216 << static_cast<const void*>(params) << ")");
4217 uint32 value = 0;
4218 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
4219 *params = static_cast<GLuint>(value);
4220 return;
4222 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribIuiv");
4223 typedef cmds::GetVertexAttribiv::Result Result;
4224 Result* result = GetResultAs<Result*>();
4225 if (!result) {
4226 return;
4228 result->SetNumResults(0);
4229 helper_->GetVertexAttribIuiv(
4230 index, pname, GetResultShmId(), GetResultShmOffset());
4231 WaitForCmd();
4232 result->CopyResult(params);
4233 GPU_CLIENT_LOG_CODE_BLOCK({
4234 for (int32 i = 0; i < result->GetNumResults(); ++i) {
4235 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
4238 CheckGLError();
4241 GLenum GLES2Implementation::GetGraphicsResetStatusKHR() {
4242 GPU_CLIENT_SINGLE_THREAD_CHECK();
4243 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetGraphicsResetStatusKHR()");
4244 // If we can't make command buffers then the context is lost.
4245 if (gpu_control_->IsGpuChannelLost())
4246 return GL_UNKNOWN_CONTEXT_RESET_KHR;
4247 // Otherwise, check the command buffer if it is lost.
4248 if (helper_->IsContextLost()) {
4249 // TODO(danakj): We could GetLastState() off the CommandBuffer and return
4250 // the actual reason here if we cared to.
4251 return GL_UNKNOWN_CONTEXT_RESET_KHR;
4253 return GL_NO_ERROR;
4256 void GLES2Implementation::Swap() {
4257 SwapBuffers();
4260 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
4261 PostSubBufferCHROMIUM(
4262 sub_buffer.x(), sub_buffer.y(), sub_buffer.width(), sub_buffer.height());
4265 static GLenum GetGLESOverlayTransform(gfx::OverlayTransform plane_transform) {
4266 switch (plane_transform) {
4267 case gfx::OVERLAY_TRANSFORM_INVALID:
4268 break;
4269 case gfx::OVERLAY_TRANSFORM_NONE:
4270 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
4271 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
4272 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM;
4273 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
4274 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM;
4275 case gfx::OVERLAY_TRANSFORM_ROTATE_90:
4276 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM;
4277 case gfx::OVERLAY_TRANSFORM_ROTATE_180:
4278 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM;
4279 case gfx::OVERLAY_TRANSFORM_ROTATE_270:
4280 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM;
4282 NOTREACHED();
4283 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
4286 void GLES2Implementation::ScheduleOverlayPlane(
4287 int plane_z_order,
4288 gfx::OverlayTransform plane_transform,
4289 unsigned overlay_texture_id,
4290 const gfx::Rect& display_bounds,
4291 const gfx::RectF& uv_rect) {
4292 ScheduleOverlayPlaneCHROMIUM(plane_z_order,
4293 GetGLESOverlayTransform(plane_transform),
4294 overlay_texture_id,
4295 display_bounds.x(),
4296 display_bounds.y(),
4297 display_bounds.width(),
4298 display_bounds.height(),
4299 uv_rect.x(),
4300 uv_rect.y(),
4301 uv_rect.width(),
4302 uv_rect.height());
4305 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
4306 const char* feature) {
4307 GPU_CLIENT_SINGLE_THREAD_CHECK();
4308 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
4309 << feature << ")");
4310 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
4311 typedef cmds::EnableFeatureCHROMIUM::Result Result;
4312 Result* result = GetResultAs<Result*>();
4313 if (!result) {
4314 return false;
4316 *result = 0;
4317 SetBucketAsCString(kResultBucketId, feature);
4318 helper_->EnableFeatureCHROMIUM(
4319 kResultBucketId, GetResultShmId(), GetResultShmOffset());
4320 WaitForCmd();
4321 helper_->SetBucketSize(kResultBucketId, 0);
4322 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
4323 return *result != 0;
4326 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
4327 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
4328 GPU_CLIENT_SINGLE_THREAD_CHECK();
4329 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
4330 << target << ", " << offset << ", " << size << ", "
4331 << GLES2Util::GetStringEnum(access) << ")");
4332 // NOTE: target is NOT checked because the service will check it
4333 // and we don't know what targets are valid.
4334 if (access != GL_WRITE_ONLY) {
4335 SetGLErrorInvalidEnum(
4336 "glMapBufferSubDataCHROMIUM", access, "access");
4337 return NULL;
4339 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
4340 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
4341 return NULL;
4344 int32 shm_id;
4345 unsigned int shm_offset;
4346 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4347 if (!mem) {
4348 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
4349 return NULL;
4352 std::pair<MappedBufferMap::iterator, bool> result =
4353 mapped_buffers_.insert(std::make_pair(
4354 mem,
4355 MappedBuffer(
4356 access, shm_id, mem, shm_offset, target, offset, size)));
4357 DCHECK(result.second);
4358 GPU_CLIENT_LOG(" returned " << mem);
4359 return mem;
4362 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
4363 GPU_CLIENT_SINGLE_THREAD_CHECK();
4364 GPU_CLIENT_LOG(
4365 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
4366 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
4367 if (it == mapped_buffers_.end()) {
4368 SetGLError(
4369 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
4370 return;
4372 const MappedBuffer& mb = it->second;
4373 helper_->BufferSubData(
4374 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
4375 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
4376 mapped_buffers_.erase(it);
4377 CheckGLError();
4380 GLuint GLES2Implementation::GetBoundBufferHelper(GLenum target) {
4381 GLenum binding = GLES2Util::MapBufferTargetToBindingEnum(target);
4382 GLint id = 0;
4383 bool cached = GetHelper(binding, &id);
4384 DCHECK(cached);
4385 return static_cast<GLuint>(id);
4388 void GLES2Implementation::RemoveMappedBufferRangeByTarget(GLenum target) {
4389 GLuint buffer = GetBoundBufferHelper(target);
4390 RemoveMappedBufferRangeById(buffer);
4393 void GLES2Implementation::RemoveMappedBufferRangeById(GLuint buffer) {
4394 if (buffer > 0) {
4395 auto iter = mapped_buffer_range_map_.find(buffer);
4396 if (iter != mapped_buffer_range_map_.end() && iter->second.shm_memory) {
4397 mapped_memory_->FreePendingToken(
4398 iter->second.shm_memory, helper_->InsertToken());
4399 mapped_buffer_range_map_.erase(iter);
4404 void GLES2Implementation::ClearMappedBufferRangeMap() {
4405 for (auto& buffer_range : mapped_buffer_range_map_) {
4406 if (buffer_range.second.shm_memory) {
4407 mapped_memory_->FreePendingToken(
4408 buffer_range.second.shm_memory, helper_->InsertToken());
4411 mapped_buffer_range_map_.clear();
4414 void* GLES2Implementation::MapBufferRange(
4415 GLenum target, GLintptr offset, GLsizeiptr size, GLbitfield access) {
4416 GPU_CLIENT_SINGLE_THREAD_CHECK();
4417 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferRange("
4418 << GLES2Util::GetStringEnum(target) << ", " << offset << ", "
4419 << size << ", " << access << ")");
4420 if (!ValidateSize("glMapBufferRange", size) ||
4421 !ValidateOffset("glMapBufferRange", offset)) {
4422 return nullptr;
4425 int32 shm_id;
4426 unsigned int shm_offset;
4427 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4428 if (!mem) {
4429 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferRange", "out of memory");
4430 return nullptr;
4433 typedef cmds::MapBufferRange::Result Result;
4434 Result* result = GetResultAs<Result*>();
4435 *result = 0;
4436 helper_->MapBufferRange(target, offset, size, access, shm_id, shm_offset,
4437 GetResultShmId(), GetResultShmOffset());
4438 // TODO(zmo): For write only mode with MAP_INVALID_*_BIT, we should
4439 // consider an early return without WaitForCmd(). crbug.com/465804.
4440 WaitForCmd();
4441 if (*result) {
4442 const GLbitfield kInvalidateBits =
4443 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
4444 if ((access & kInvalidateBits) != 0) {
4445 // We do not read back from the buffer, therefore, we set the client
4446 // side memory to zero to avoid uninitialized data.
4447 memset(mem, 0, size);
4449 GLuint buffer = GetBoundBufferHelper(target);
4450 DCHECK_NE(0u, buffer);
4451 // glMapBufferRange fails on an already mapped buffer.
4452 DCHECK(mapped_buffer_range_map_.find(buffer) ==
4453 mapped_buffer_range_map_.end());
4454 auto iter = mapped_buffer_range_map_.insert(std::make_pair(
4455 buffer,
4456 MappedBuffer(access, shm_id, mem, shm_offset, target, offset, size)));
4457 DCHECK(iter.second);
4458 } else {
4459 mapped_memory_->Free(mem);
4460 mem = nullptr;
4463 GPU_CLIENT_LOG(" returned " << mem);
4464 CheckGLError();
4465 return mem;
4468 GLboolean GLES2Implementation::UnmapBuffer(GLenum target) {
4469 GPU_CLIENT_SINGLE_THREAD_CHECK();
4470 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapBuffer("
4471 << GLES2Util::GetStringEnum(target) << ")");
4472 switch (target) {
4473 case GL_ARRAY_BUFFER:
4474 case GL_ELEMENT_ARRAY_BUFFER:
4475 case GL_COPY_READ_BUFFER:
4476 case GL_COPY_WRITE_BUFFER:
4477 case GL_PIXEL_PACK_BUFFER:
4478 case GL_PIXEL_UNPACK_BUFFER:
4479 case GL_TRANSFORM_FEEDBACK_BUFFER:
4480 case GL_UNIFORM_BUFFER:
4481 break;
4482 default:
4483 SetGLError(GL_INVALID_ENUM, "glUnmapBuffer", "invalid target");
4484 return GL_FALSE;
4486 GLuint buffer = GetBoundBufferHelper(target);
4487 if (buffer == 0) {
4488 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "no buffer bound");
4489 return GL_FALSE;
4491 auto iter = mapped_buffer_range_map_.find(buffer);
4492 if (iter == mapped_buffer_range_map_.end()) {
4493 SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "buffer is unmapped");
4494 return GL_FALSE;
4497 helper_->UnmapBuffer(target);
4498 RemoveMappedBufferRangeById(buffer);
4499 // TODO(zmo): There is a rare situation that data might be corrupted and
4500 // GL_FALSE should be returned. We lose context on that sitatuon, so we
4501 // don't have to WaitForCmd().
4502 GPU_CLIENT_LOG(" returned " << GL_TRUE);
4503 CheckGLError();
4504 return GL_TRUE;
4507 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
4508 GLenum target,
4509 GLint level,
4510 GLint xoffset,
4511 GLint yoffset,
4512 GLsizei width,
4513 GLsizei height,
4514 GLenum format,
4515 GLenum type,
4516 GLenum access) {
4517 GPU_CLIENT_SINGLE_THREAD_CHECK();
4518 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
4519 << target << ", " << level << ", "
4520 << xoffset << ", " << yoffset << ", "
4521 << width << ", " << height << ", "
4522 << GLES2Util::GetStringTextureFormat(format) << ", "
4523 << GLES2Util::GetStringPixelType(type) << ", "
4524 << GLES2Util::GetStringEnum(access) << ")");
4525 if (access != GL_WRITE_ONLY) {
4526 SetGLErrorInvalidEnum(
4527 "glMapTexSubImage2DCHROMIUM", access, "access");
4528 return NULL;
4530 // NOTE: target is NOT checked because the service will check it
4531 // and we don't know what targets are valid.
4532 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
4533 SetGLError(
4534 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
4535 return NULL;
4537 uint32 size;
4538 if (!GLES2Util::ComputeImageDataSizes(
4539 width, height, 1, format, type, unpack_alignment_, &size, NULL, NULL)) {
4540 SetGLError(
4541 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
4542 return NULL;
4544 int32 shm_id;
4545 unsigned int shm_offset;
4546 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
4547 if (!mem) {
4548 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
4549 return NULL;
4552 std::pair<MappedTextureMap::iterator, bool> result =
4553 mapped_textures_.insert(std::make_pair(
4554 mem,
4555 MappedTexture(
4556 access, shm_id, mem, shm_offset,
4557 target, level, xoffset, yoffset, width, height, format, type)));
4558 DCHECK(result.second);
4559 GPU_CLIENT_LOG(" returned " << mem);
4560 return mem;
4563 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
4564 GPU_CLIENT_SINGLE_THREAD_CHECK();
4565 GPU_CLIENT_LOG(
4566 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
4567 MappedTextureMap::iterator it = mapped_textures_.find(mem);
4568 if (it == mapped_textures_.end()) {
4569 SetGLError(
4570 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
4571 return;
4573 const MappedTexture& mt = it->second;
4574 helper_->TexSubImage2D(
4575 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
4576 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
4577 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
4578 mapped_textures_.erase(it);
4579 CheckGLError();
4582 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
4583 float scale_factor) {
4584 GPU_CLIENT_SINGLE_THREAD_CHECK();
4585 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
4586 << width << ", " << height << ", " << scale_factor << ")");
4587 helper_->ResizeCHROMIUM(width, height, scale_factor);
4588 CheckGLError();
4591 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
4592 GPU_CLIENT_SINGLE_THREAD_CHECK();
4593 GPU_CLIENT_LOG("[" << GetLogPrefix()
4594 << "] glGetRequestableExtensionsCHROMIUM()");
4595 TRACE_EVENT0("gpu",
4596 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
4597 const char* result = NULL;
4598 // Clear the bucket so if the command fails nothing will be in it.
4599 helper_->SetBucketSize(kResultBucketId, 0);
4600 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
4601 std::string str;
4602 if (GetBucketAsString(kResultBucketId, &str)) {
4603 // The set of requestable extensions shrinks as we enable
4604 // them. Because we don't know when the client will stop referring
4605 // to a previous one it queries (see GetString) we need to cache
4606 // the unique results.
4607 std::set<std::string>::const_iterator sit =
4608 requestable_extensions_set_.find(str);
4609 if (sit != requestable_extensions_set_.end()) {
4610 result = sit->c_str();
4611 } else {
4612 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
4613 requestable_extensions_set_.insert(str);
4614 DCHECK(insert_result.second);
4615 result = insert_result.first->c_str();
4618 GPU_CLIENT_LOG(" returned " << result);
4619 return reinterpret_cast<const GLchar*>(result);
4622 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
4623 // with VirtualGL contexts.
4624 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
4625 GPU_CLIENT_SINGLE_THREAD_CHECK();
4626 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
4627 << extension << ")");
4628 SetBucketAsCString(kResultBucketId, extension);
4629 helper_->RequestExtensionCHROMIUM(kResultBucketId);
4630 helper_->SetBucketSize(kResultBucketId, 0);
4632 struct ExtensionCheck {
4633 const char* extension;
4634 ExtensionStatus* status;
4636 const ExtensionCheck checks[] = {
4638 "GL_ANGLE_pack_reverse_row_order",
4639 &angle_pack_reverse_row_order_status_,
4642 "GL_CHROMIUM_framebuffer_multisample",
4643 &chromium_framebuffer_multisample_,
4646 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
4647 for (size_t ii = 0; ii < kNumChecks; ++ii) {
4648 const ExtensionCheck& check = checks[ii];
4649 if (*check.status == kUnavailableExtensionStatus &&
4650 !strcmp(extension, check.extension)) {
4651 *check.status = kUnknownExtensionStatus;
4656 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
4657 GPU_CLIENT_SINGLE_THREAD_CHECK();
4658 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
4659 // Wait if this would add too many rate limit tokens.
4660 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
4661 helper_->WaitForToken(rate_limit_tokens_.front());
4662 rate_limit_tokens_.pop();
4664 rate_limit_tokens_.push(helper_->InsertToken());
4667 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
4668 GLuint program, std::vector<int8>* result) {
4669 DCHECK(result);
4670 // Clear the bucket so if the command fails nothing will be in it.
4671 helper_->SetBucketSize(kResultBucketId, 0);
4672 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
4673 GetBucketContents(kResultBucketId, result);
4676 void GLES2Implementation::GetProgramInfoCHROMIUM(
4677 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4678 GPU_CLIENT_SINGLE_THREAD_CHECK();
4679 if (bufsize < 0) {
4680 SetGLError(
4681 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
4682 return;
4684 if (size == NULL) {
4685 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
4686 return;
4688 // Make sure they've set size to 0 else the value will be undefined on
4689 // lost context.
4690 DCHECK_EQ(0, *size);
4691 std::vector<int8> result;
4692 GetProgramInfoCHROMIUMHelper(program, &result);
4693 if (result.empty()) {
4694 return;
4696 *size = result.size();
4697 if (!info) {
4698 return;
4700 if (static_cast<size_t>(bufsize) < result.size()) {
4701 SetGLError(GL_INVALID_OPERATION,
4702 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
4703 return;
4705 memcpy(info, &result[0], result.size());
4708 void GLES2Implementation::GetUniformBlocksCHROMIUMHelper(
4709 GLuint program, std::vector<int8>* result) {
4710 DCHECK(result);
4711 // Clear the bucket so if the command fails nothing will be in it.
4712 helper_->SetBucketSize(kResultBucketId, 0);
4713 helper_->GetUniformBlocksCHROMIUM(program, kResultBucketId);
4714 GetBucketContents(kResultBucketId, result);
4717 void GLES2Implementation::GetUniformBlocksCHROMIUM(
4718 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4719 GPU_CLIENT_SINGLE_THREAD_CHECK();
4720 if (bufsize < 0) {
4721 SetGLError(
4722 GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "bufsize less than 0.");
4723 return;
4725 if (size == NULL) {
4726 SetGLError(GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "size is null.");
4727 return;
4729 // Make sure they've set size to 0 else the value will be undefined on
4730 // lost context.
4731 DCHECK_EQ(0, *size);
4732 std::vector<int8> result;
4733 GetUniformBlocksCHROMIUMHelper(program, &result);
4734 if (result.empty()) {
4735 return;
4737 *size = result.size();
4738 if (!info) {
4739 return;
4741 if (static_cast<size_t>(bufsize) < result.size()) {
4742 SetGLError(GL_INVALID_OPERATION, "glGetUniformBlocksCHROMIUM",
4743 "bufsize is too small for result.");
4744 return;
4746 memcpy(info, &result[0], result.size());
4749 void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
4750 GLuint program, std::vector<int8>* result) {
4751 DCHECK(result);
4752 // Clear the bucket so if the command fails nothing will be in it.
4753 helper_->SetBucketSize(kResultBucketId, 0);
4754 helper_->GetUniformsES3CHROMIUM(program, kResultBucketId);
4755 GetBucketContents(kResultBucketId, result);
4758 void GLES2Implementation::GetUniformsES3CHROMIUM(
4759 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4760 GPU_CLIENT_SINGLE_THREAD_CHECK();
4761 if (bufsize < 0) {
4762 SetGLError(
4763 GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "bufsize less than 0.");
4764 return;
4766 if (size == NULL) {
4767 SetGLError(GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "size is null.");
4768 return;
4770 // Make sure they've set size to 0 else the value will be undefined on
4771 // lost context.
4772 DCHECK_EQ(0, *size);
4773 std::vector<int8> result;
4774 GetUniformsES3CHROMIUMHelper(program, &result);
4775 if (result.empty()) {
4776 return;
4778 *size = result.size();
4779 if (!info) {
4780 return;
4782 if (static_cast<size_t>(bufsize) < result.size()) {
4783 SetGLError(GL_INVALID_OPERATION,
4784 "glGetUniformsES3CHROMIUM", "bufsize is too small for result.");
4785 return;
4787 memcpy(info, &result[0], result.size());
4790 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
4791 GLuint program, std::vector<int8>* result) {
4792 DCHECK(result);
4793 // Clear the bucket so if the command fails nothing will be in it.
4794 helper_->SetBucketSize(kResultBucketId, 0);
4795 helper_->GetTransformFeedbackVaryingsCHROMIUM(program, kResultBucketId);
4796 GetBucketContents(kResultBucketId, result);
4799 void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(
4800 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
4801 GPU_CLIENT_SINGLE_THREAD_CHECK();
4802 if (bufsize < 0) {
4803 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4804 "bufsize less than 0.");
4805 return;
4807 if (size == NULL) {
4808 SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
4809 "size is null.");
4810 return;
4812 // Make sure they've set size to 0 else the value will be undefined on
4813 // lost context.
4814 DCHECK_EQ(0, *size);
4815 std::vector<int8> result;
4816 GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
4817 if (result.empty()) {
4818 return;
4820 *size = result.size();
4821 if (!info) {
4822 return;
4824 if (static_cast<size_t>(bufsize) < result.size()) {
4825 SetGLError(GL_INVALID_OPERATION, "glGetTransformFeedbackVaryingsCHROMIUM",
4826 "bufsize is too small for result.");
4827 return;
4829 memcpy(info, &result[0], result.size());
4832 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
4833 GPU_CLIENT_SINGLE_THREAD_CHECK();
4834 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
4835 << texture << ")");
4836 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
4837 helper_->CommandBufferHelper::Flush();
4838 return gpu_control_->CreateStreamTexture(texture);
4841 void GLES2Implementation::PostSubBufferCHROMIUM(
4842 GLint x, GLint y, GLint width, GLint height) {
4843 GPU_CLIENT_SINGLE_THREAD_CHECK();
4844 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
4845 << x << ", " << y << ", " << width << ", " << height << ")");
4846 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
4847 "width", width, "height", height);
4849 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
4850 swap_buffers_tokens_.push(helper_->InsertToken());
4851 helper_->PostSubBufferCHROMIUM(x, y, width, height);
4852 helper_->CommandBufferHelper::Flush();
4853 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
4854 helper_->WaitForToken(swap_buffers_tokens_.front());
4855 swap_buffers_tokens_.pop();
4859 void GLES2Implementation::DeleteQueriesEXTHelper(
4860 GLsizei n, const GLuint* queries) {
4861 for (GLsizei ii = 0; ii < n; ++ii) {
4862 query_tracker_->RemoveQuery(queries[ii]);
4863 query_id_allocator_->FreeID(queries[ii]);
4866 helper_->DeleteQueriesEXTImmediate(n, queries);
4869 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
4870 GPU_CLIENT_SINGLE_THREAD_CHECK();
4871 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
4873 // TODO(gman): To be spec compliant IDs from other contexts sharing
4874 // resources need to return true here even though you can't share
4875 // queries across contexts?
4876 return query_tracker_->GetQuery(id) != NULL;
4879 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
4880 GPU_CLIENT_SINGLE_THREAD_CHECK();
4881 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
4882 << GLES2Util::GetStringQueryTarget(target)
4883 << ", " << id << ")");
4885 switch (target) {
4886 case GL_COMMANDS_ISSUED_CHROMIUM:
4887 case GL_LATENCY_QUERY_CHROMIUM:
4888 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
4889 case GL_GET_ERROR_QUERY_CHROMIUM:
4890 break;
4891 case GL_COMMANDS_COMPLETED_CHROMIUM:
4892 if (!capabilities_.sync_query) {
4893 SetGLError(
4894 GL_INVALID_OPERATION, "glBeginQueryEXT",
4895 "not enabled for commands completed queries");
4896 return;
4898 break;
4899 case GL_ANY_SAMPLES_PASSED:
4900 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
4901 if (!capabilities_.occlusion_query_boolean) {
4902 SetGLError(
4903 GL_INVALID_OPERATION, "glBeginQueryEXT",
4904 "not enabled for occlusion queries");
4905 return;
4907 break;
4908 case GL_TIME_ELAPSED_EXT:
4909 if (!capabilities_.timer_queries) {
4910 SetGLError(
4911 GL_INVALID_OPERATION, "glBeginQueryEXT",
4912 "not enabled for timing queries");
4913 return;
4915 break;
4916 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
4917 if (capabilities_.major_version >= 3)
4918 break;
4919 // Fall through
4920 default:
4921 SetGLError(
4922 GL_INVALID_ENUM, "glBeginQueryEXT", "unknown query target");
4923 return;
4926 // if any outstanding queries INV_OP
4927 if (query_tracker_->GetCurrentQuery(target)) {
4928 SetGLError(
4929 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
4930 return;
4933 if (id == 0) {
4934 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
4935 return;
4938 if (!query_id_allocator_->InUse(id)) {
4939 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "invalid id");
4940 return;
4943 // Extra setups some targets might need.
4944 switch (target) {
4945 case GL_TIME_ELAPSED_EXT:
4946 if (!query_tracker_->SetDisjointSync(this)) {
4947 SetGLError(GL_OUT_OF_MEMORY,
4948 "glBeginQueryEXT",
4949 "buffer allocation failed");
4950 return;
4952 break;
4953 default:
4954 break;
4957 if (query_tracker_->BeginQuery(id, target, this))
4958 CheckGLError();
4961 void GLES2Implementation::EndQueryEXT(GLenum target) {
4962 GPU_CLIENT_SINGLE_THREAD_CHECK();
4963 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
4964 << GLES2Util::GetStringQueryTarget(target) << ")");
4965 // Don't do anything if the context is lost.
4966 if (helper_->IsContextLost()) {
4967 return;
4970 if (query_tracker_->EndQuery(target, this))
4971 CheckGLError();
4974 void GLES2Implementation::QueryCounterEXT(GLuint id, GLenum target) {
4975 GPU_CLIENT_SINGLE_THREAD_CHECK();
4976 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] QueryCounterEXT("
4977 << id
4978 << ", " << GLES2Util::GetStringQueryTarget(target) << ")");
4980 switch (target) {
4981 case GL_TIMESTAMP_EXT:
4982 if (!capabilities_.timer_queries) {
4983 SetGLError(
4984 GL_INVALID_OPERATION, "glQueryCounterEXT",
4985 "not enabled for timing queries");
4986 return;
4988 break;
4989 default:
4990 SetGLError(
4991 GL_INVALID_ENUM, "glQueryCounterEXT", "unknown query target");
4992 return;
4995 if (id == 0) {
4996 SetGLError(GL_INVALID_OPERATION, "glQueryCounterEXT", "id is 0");
4997 return;
5000 if (!query_id_allocator_->InUse(id)) {
5001 SetGLError(GL_INVALID_OPERATION, "glQueryCounterEXT", "invalid id");
5002 return;
5005 // Extra setups some targets might need.
5006 switch (target) {
5007 case GL_TIMESTAMP_EXT:
5008 if (!query_tracker_->SetDisjointSync(this)) {
5009 SetGLError(GL_OUT_OF_MEMORY,
5010 "glQueryCounterEXT",
5011 "buffer allocation failed");
5012 return;
5014 break;
5015 default:
5016 break;
5019 if (query_tracker_->QueryCounter(id, target, this))
5020 CheckGLError();
5023 void GLES2Implementation::GetQueryivEXT(
5024 GLenum target, GLenum pname, GLint* params) {
5025 GPU_CLIENT_SINGLE_THREAD_CHECK();
5026 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
5027 << GLES2Util::GetStringQueryTarget(target) << ", "
5028 << GLES2Util::GetStringQueryParameter(pname) << ", "
5029 << static_cast<const void*>(params) << ")");
5030 if (pname == GL_QUERY_COUNTER_BITS_EXT) {
5031 // We convert all queries to CPU time so we support 64 bits.
5032 *params = 64;
5033 return;
5034 } else if (pname != GL_CURRENT_QUERY_EXT) {
5035 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
5036 return;
5038 QueryTracker::Query* query = query_tracker_->GetCurrentQuery(target);
5039 *params = query ? query->id() : 0;
5040 GPU_CLIENT_LOG(" " << *params);
5041 CheckGLError();
5044 void GLES2Implementation::GetQueryObjectivEXT(
5045 GLuint id, GLenum pname, GLint* params) {
5046 GLuint64 result = 0;
5047 if (GetQueryObjectValueHelper("glGetQueryObjectivEXT", id, pname, &result))
5048 *params = base::saturated_cast<GLint>(result);
5051 void GLES2Implementation::GetQueryObjectuivEXT(
5052 GLuint id, GLenum pname, GLuint* params) {
5053 GLuint64 result = 0;
5054 if (GetQueryObjectValueHelper("glGetQueryObjectuivEXT", id, pname, &result))
5055 *params = base::saturated_cast<GLuint>(result);
5058 void GLES2Implementation::GetQueryObjecti64vEXT(
5059 GLuint id, GLenum pname, GLint64* params) {
5060 GLuint64 result = 0;
5061 if (GetQueryObjectValueHelper("glGetQueryObjectiv64vEXT", id, pname, &result))
5062 *params = base::saturated_cast<GLint64>(result);
5065 void GLES2Implementation::GetQueryObjectui64vEXT(
5066 GLuint id, GLenum pname, GLuint64* params) {
5067 GLuint64 result = 0;
5068 if (GetQueryObjectValueHelper("glGetQueryObjectui64vEXT", id, pname, &result))
5069 *params = result;
5072 void GLES2Implementation::SetDisjointValueSyncCHROMIUM() {
5073 query_tracker_->SetDisjointSync(this);
5076 void GLES2Implementation::DrawArraysInstancedANGLE(
5077 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
5078 GPU_CLIENT_SINGLE_THREAD_CHECK();
5079 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
5080 << GLES2Util::GetStringDrawMode(mode) << ", "
5081 << first << ", " << count << ", " << primcount << ")");
5082 if (count < 0) {
5083 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
5084 return;
5086 if (primcount < 0) {
5087 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
5088 return;
5090 if (primcount == 0) {
5091 return;
5093 bool simulated = false;
5094 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
5095 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
5096 &simulated)) {
5097 return;
5099 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
5100 RestoreArrayBuffer(simulated);
5101 CheckGLError();
5104 void GLES2Implementation::DrawElementsInstancedANGLE(
5105 GLenum mode, GLsizei count, GLenum type, const void* indices,
5106 GLsizei primcount) {
5107 GPU_CLIENT_SINGLE_THREAD_CHECK();
5108 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
5109 << GLES2Util::GetStringDrawMode(mode) << ", "
5110 << count << ", "
5111 << GLES2Util::GetStringIndexType(type) << ", "
5112 << static_cast<const void*>(indices) << ", "
5113 << primcount << ")");
5114 if (count < 0) {
5115 SetGLError(GL_INVALID_VALUE,
5116 "glDrawElementsInstancedANGLE", "count less than 0.");
5117 return;
5119 if (count == 0) {
5120 return;
5122 if (primcount < 0) {
5123 SetGLError(GL_INVALID_VALUE,
5124 "glDrawElementsInstancedANGLE", "primcount < 0");
5125 return;
5127 if (primcount == 0) {
5128 return;
5130 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
5131 !ValidateOffset("glDrawElementsInstancedANGLE",
5132 reinterpret_cast<GLintptr>(indices))) {
5133 return;
5135 GLuint offset = 0;
5136 bool simulated = false;
5137 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
5138 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
5139 indices, &offset, &simulated)) {
5140 return;
5142 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
5143 RestoreElementAndArrayBuffers(simulated);
5144 CheckGLError();
5147 void GLES2Implementation::GenMailboxCHROMIUM(
5148 GLbyte* mailbox) {
5149 GPU_CLIENT_SINGLE_THREAD_CHECK();
5150 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
5151 << static_cast<const void*>(mailbox) << ")");
5152 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
5154 gpu::Mailbox result = gpu::Mailbox::Generate();
5155 memcpy(mailbox, result.name, sizeof(result.name));
5158 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target,
5159 const GLbyte* data) {
5160 GPU_CLIENT_SINGLE_THREAD_CHECK();
5161 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
5162 << static_cast<const void*>(data) << ")");
5163 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5164 DCHECK(mailbox.Verify()) << "ProduceTextureCHROMIUM was passed a "
5165 "mailbox that was not generated by "
5166 "GenMailboxCHROMIUM.";
5167 helper_->ProduceTextureCHROMIUMImmediate(target, data);
5168 CheckGLError();
5171 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
5172 GLuint texture, GLenum target, const GLbyte* data) {
5173 GPU_CLIENT_SINGLE_THREAD_CHECK();
5174 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
5175 << static_cast<const void*>(data) << ")");
5176 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5177 DCHECK(mailbox.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
5178 "mailbox that was not generated by "
5179 "GenMailboxCHROMIUM.";
5180 helper_->ProduceTextureDirectCHROMIUMImmediate(texture, target, data);
5181 CheckGLError();
5184 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target,
5185 const GLbyte* data) {
5186 GPU_CLIENT_SINGLE_THREAD_CHECK();
5187 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
5188 << static_cast<const void*>(data) << ")");
5189 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5190 DCHECK(mailbox.Verify()) << "ConsumeTextureCHROMIUM was passed a "
5191 "mailbox that was not generated by "
5192 "GenMailboxCHROMIUM.";
5193 helper_->ConsumeTextureCHROMIUMImmediate(target, data);
5194 CheckGLError();
5197 GLuint GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
5198 GLenum target, const GLbyte* data) {
5199 GPU_CLIENT_SINGLE_THREAD_CHECK();
5200 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
5201 << static_cast<const void*>(data) << ")");
5202 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
5203 DCHECK(mailbox.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
5204 "mailbox that was not generated by "
5205 "GenMailboxCHROMIUM.";
5206 GLuint client_id;
5207 GetIdHandler(id_namespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
5208 helper_->CreateAndConsumeTextureCHROMIUMImmediate(target,
5209 client_id, data);
5210 if (share_group_->bind_generates_resource())
5211 helper_->CommandBufferHelper::Flush();
5212 CheckGLError();
5213 return client_id;
5216 void GLES2Implementation::PushGroupMarkerEXT(
5217 GLsizei length, const GLchar* marker) {
5218 GPU_CLIENT_SINGLE_THREAD_CHECK();
5219 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
5220 << length << ", " << marker << ")");
5221 if (!marker) {
5222 marker = "";
5224 SetBucketAsString(
5225 kResultBucketId,
5226 (length ? std::string(marker, length) : std::string(marker)));
5227 helper_->PushGroupMarkerEXT(kResultBucketId);
5228 helper_->SetBucketSize(kResultBucketId, 0);
5229 debug_marker_manager_.PushGroup(
5230 length ? std::string(marker, length) : std::string(marker));
5233 void GLES2Implementation::InsertEventMarkerEXT(
5234 GLsizei length, const GLchar* marker) {
5235 GPU_CLIENT_SINGLE_THREAD_CHECK();
5236 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
5237 << length << ", " << marker << ")");
5238 if (!marker) {
5239 marker = "";
5241 SetBucketAsString(
5242 kResultBucketId,
5243 (length ? std::string(marker, length) : std::string(marker)));
5244 helper_->InsertEventMarkerEXT(kResultBucketId);
5245 helper_->SetBucketSize(kResultBucketId, 0);
5246 debug_marker_manager_.SetMarker(
5247 length ? std::string(marker, length) : std::string(marker));
5250 void GLES2Implementation::PopGroupMarkerEXT() {
5251 GPU_CLIENT_SINGLE_THREAD_CHECK();
5252 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
5253 helper_->PopGroupMarkerEXT();
5254 debug_marker_manager_.PopGroup();
5257 void GLES2Implementation::TraceBeginCHROMIUM(
5258 const char* category_name, const char* trace_name) {
5259 GPU_CLIENT_SINGLE_THREAD_CHECK();
5260 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
5261 << category_name << ", " << trace_name << ")");
5262 SetBucketAsCString(kResultBucketId, category_name);
5263 SetBucketAsCString(kResultBucketId + 1, trace_name);
5264 helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1);
5265 helper_->SetBucketSize(kResultBucketId, 0);
5266 helper_->SetBucketSize(kResultBucketId + 1, 0);
5267 current_trace_stack_++;
5270 void GLES2Implementation::TraceEndCHROMIUM() {
5271 GPU_CLIENT_SINGLE_THREAD_CHECK();
5272 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
5273 if (current_trace_stack_ == 0) {
5274 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
5275 "missing begin trace");
5276 return;
5278 helper_->TraceEndCHROMIUM();
5279 current_trace_stack_--;
5282 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
5283 GPU_CLIENT_SINGLE_THREAD_CHECK();
5284 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
5285 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
5286 switch (target) {
5287 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
5288 if (access != GL_READ_ONLY) {
5289 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
5290 return NULL;
5292 break;
5293 default:
5294 SetGLError(
5295 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
5296 return NULL;
5298 GLuint buffer_id;
5299 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
5300 if (!buffer_id) {
5301 return NULL;
5303 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
5304 if (!buffer) {
5305 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
5306 return NULL;
5308 if (buffer->mapped()) {
5309 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
5310 return NULL;
5312 // Here we wait for previous transfer operations to be finished.
5313 if (buffer->last_usage_token()) {
5314 helper_->WaitForToken(buffer->last_usage_token());
5315 buffer->set_last_usage_token(0);
5317 buffer->set_mapped(true);
5319 GPU_CLIENT_LOG(" returned " << buffer->address());
5320 CheckGLError();
5321 return buffer->address();
5324 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
5325 GPU_CLIENT_SINGLE_THREAD_CHECK();
5326 GPU_CLIENT_LOG(
5327 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
5328 GLuint buffer_id;
5329 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
5330 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
5332 if (!buffer_id) {
5333 return false;
5335 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
5336 if (!buffer) {
5337 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
5338 return false;
5340 if (!buffer->mapped()) {
5341 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
5342 return false;
5344 buffer->set_mapped(false);
5345 CheckGLError();
5346 return true;
5349 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
5350 GPU_CLIENT_SINGLE_THREAD_CHECK();
5351 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
5352 helper_->CommandBufferHelper::Flush();
5353 return gpu_control_->InsertSyncPoint();
5356 GLuint GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
5357 GPU_CLIENT_SINGLE_THREAD_CHECK();
5358 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
5359 DCHECK(capabilities_.future_sync_points);
5360 return gpu_control_->InsertFutureSyncPoint();
5363 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point) {
5364 GPU_CLIENT_SINGLE_THREAD_CHECK();
5365 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
5366 << sync_point << ")");
5367 DCHECK(capabilities_.future_sync_points);
5368 helper_->CommandBufferHelper::Flush();
5369 gpu_control_->RetireSyncPoint(sync_point);
5372 namespace {
5374 bool ValidImageFormat(GLenum internalformat,
5375 const Capabilities& capabilities) {
5376 switch (internalformat) {
5377 case GL_ATC_RGB_AMD:
5378 case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
5379 return capabilities.texture_format_atc;
5380 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
5381 return capabilities.texture_format_dxt1;
5382 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
5383 return capabilities.texture_format_dxt5;
5384 case GL_ETC1_RGB8_OES:
5385 return capabilities.texture_format_etc1;
5386 case GL_R8:
5387 case GL_RGB:
5388 case GL_RGBA:
5389 case GL_RGB_YCBCR_422_CHROMIUM:
5390 case GL_BGRA_EXT:
5391 return true;
5392 default:
5393 return false;
5397 bool ValidImageUsage(GLenum usage) {
5398 switch (usage) {
5399 case GL_MAP_CHROMIUM:
5400 case GL_SCANOUT_CHROMIUM:
5401 return true;
5402 default:
5403 return false;
5407 } // namespace
5409 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer,
5410 GLsizei width,
5411 GLsizei height,
5412 GLenum internalformat) {
5413 if (width <= 0) {
5414 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
5415 return 0;
5418 if (height <= 0) {
5419 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
5420 return 0;
5423 if (!ValidImageFormat(internalformat, capabilities_)) {
5424 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "invalid format");
5425 return 0;
5428 int32_t image_id =
5429 gpu_control_->CreateImage(buffer, width, height, internalformat);
5430 if (image_id < 0) {
5431 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "image_id < 0");
5432 return 0;
5434 return image_id;
5437 GLuint GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer,
5438 GLsizei width,
5439 GLsizei height,
5440 GLenum internalformat) {
5441 GPU_CLIENT_SINGLE_THREAD_CHECK();
5442 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
5443 << ", " << height << ", "
5444 << GLES2Util::GetStringImageInternalFormat(internalformat)
5445 << ")");
5446 GLuint image_id =
5447 CreateImageCHROMIUMHelper(buffer, width, height, internalformat);
5448 CheckGLError();
5449 return image_id;
5452 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
5453 // Flush the command stream to make sure all pending commands
5454 // that may refer to the image_id are executed on the service side.
5455 helper_->CommandBufferHelper::Flush();
5456 gpu_control_->DestroyImage(image_id);
5459 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
5460 GPU_CLIENT_SINGLE_THREAD_CHECK();
5461 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
5462 << image_id << ")");
5463 DestroyImageCHROMIUMHelper(image_id);
5464 CheckGLError();
5467 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
5468 GLsizei width,
5469 GLsizei height,
5470 GLenum internalformat,
5471 GLenum usage) {
5472 if (width <= 0) {
5473 SetGLError(
5474 GL_INVALID_VALUE, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
5475 return 0;
5478 if (height <= 0) {
5479 SetGLError(GL_INVALID_VALUE,
5480 "glCreateGpuMemoryBufferImageCHROMIUM",
5481 "height <= 0");
5482 return 0;
5485 if (!ValidImageFormat(internalformat, capabilities_)) {
5486 SetGLError(GL_INVALID_VALUE,
5487 "glCreateGpuMemoryBufferImageCHROMIUM",
5488 "invalid format");
5489 return 0;
5492 if (!ValidImageUsage(usage)) {
5493 SetGLError(GL_INVALID_VALUE,
5494 "glCreateGpuMemoryBufferImageCHROMIUM",
5495 "invalid usage");
5496 return 0;
5499 // Flush the command stream to ensure ordering in case the newly
5500 // returned image_id has recently been in use with a different buffer.
5501 helper_->CommandBufferHelper::Flush();
5502 int32_t image_id = gpu_control_->CreateGpuMemoryBufferImage(
5503 width, height, internalformat, usage);
5504 if (image_id < 0) {
5505 SetGLError(GL_OUT_OF_MEMORY,
5506 "glCreateGpuMemoryBufferImageCHROMIUM",
5507 "image_id < 0");
5508 return 0;
5510 return image_id;
5513 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
5514 GLsizei width,
5515 GLsizei height,
5516 GLenum internalformat,
5517 GLenum usage) {
5518 GPU_CLIENT_SINGLE_THREAD_CHECK();
5519 GPU_CLIENT_LOG("[" << GetLogPrefix()
5520 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
5521 << ", " << height << ", "
5522 << GLES2Util::GetStringImageInternalFormat(internalformat)
5523 << ", " << GLES2Util::GetStringImageUsage(usage) << ")");
5524 GLuint image_id = CreateGpuMemoryBufferImageCHROMIUMHelper(
5525 width, height, internalformat, usage);
5526 CheckGLError();
5527 return image_id;
5530 bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
5531 if (size < 0) {
5532 SetGLError(GL_INVALID_VALUE, func, "size < 0");
5533 return false;
5535 if (!base::IsValueInRangeForNumericType<int32_t>(size)) {
5536 SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
5537 return false;
5539 return true;
5542 bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
5543 if (offset < 0) {
5544 SetGLError(GL_INVALID_VALUE, func, "offset < 0");
5545 return false;
5547 if (!base::IsValueInRangeForNumericType<int32_t>(offset)) {
5548 SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
5549 return false;
5551 return true;
5554 bool GLES2Implementation::GetSamplerParameterfvHelper(
5555 GLuint /* sampler */, GLenum /* pname */, GLfloat* /* params */) {
5556 // TODO(zmo): Implement client side caching.
5557 return false;
5560 bool GLES2Implementation::GetSamplerParameterivHelper(
5561 GLuint /* sampler */, GLenum /* pname */, GLint* /* params */) {
5562 // TODO(zmo): Implement client side caching.
5563 return false;
5566 bool GLES2Implementation::PackStringsToBucket(GLsizei count,
5567 const char* const* str,
5568 const GLint* length,
5569 const char* func_name) {
5570 DCHECK_LE(0, count);
5571 // Compute the total size.
5572 base::CheckedNumeric<size_t> total_size = count;
5573 total_size += 1;
5574 total_size *= sizeof(GLint);
5575 if (!total_size.IsValid()) {
5576 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5577 return false;
5579 size_t header_size = total_size.ValueOrDefault(0);
5580 std::vector<GLint> header(count + 1);
5581 header[0] = static_cast<GLint>(count);
5582 for (GLsizei ii = 0; ii < count; ++ii) {
5583 GLint len = 0;
5584 if (str[ii]) {
5585 len = (length && length[ii] >= 0)
5586 ? length[ii]
5587 : base::checked_cast<GLint>(strlen(str[ii]));
5589 total_size += len;
5590 total_size += 1; // NULL at the end of each char array.
5591 if (!total_size.IsValid()) {
5592 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5593 return false;
5595 header[ii + 1] = len;
5597 // Pack data into a bucket on the service.
5598 helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
5599 size_t offset = 0;
5600 for (GLsizei ii = 0; ii <= count; ++ii) {
5601 const char* src =
5602 (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
5603 base::CheckedNumeric<size_t> checked_size =
5604 (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
5605 if (ii > 0) {
5606 checked_size += 1; // NULL in the end.
5608 if (!checked_size.IsValid()) {
5609 SetGLError(GL_INVALID_VALUE, func_name, "overflow");
5610 return false;
5612 size_t size = checked_size.ValueOrDefault(0);
5613 while (size) {
5614 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
5615 if (!buffer.valid() || buffer.size() == 0) {
5616 SetGLError(GL_OUT_OF_MEMORY, func_name, "too large");
5617 return false;
5619 size_t copy_size = buffer.size();
5620 if (ii > 0 && buffer.size() == size)
5621 --copy_size;
5622 if (copy_size)
5623 memcpy(buffer.address(), src, copy_size);
5624 if (copy_size < buffer.size()) {
5625 // Append NULL in the end.
5626 DCHECK(copy_size + 1 == buffer.size());
5627 char* str = reinterpret_cast<char*>(buffer.address());
5628 str[copy_size] = 0;
5630 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
5631 buffer.shm_id(), buffer.offset());
5632 offset += buffer.size();
5633 src += buffer.size();
5634 size -= buffer.size();
5637 DCHECK_EQ(total_size.ValueOrDefault(0), offset);
5638 return true;
5641 void GLES2Implementation::UniformBlockBinding(GLuint program,
5642 GLuint index,
5643 GLuint binding) {
5644 GPU_CLIENT_SINGLE_THREAD_CHECK();
5645 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
5646 << ", " << index << ", " << binding << ")");
5647 share_group_->program_info_manager()->UniformBlockBinding(
5648 this, program, index, binding);
5649 helper_->UniformBlockBinding(program, index, binding);
5650 CheckGLError();
5653 GLenum GLES2Implementation::ClientWaitSync(
5654 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5655 GPU_CLIENT_SINGLE_THREAD_CHECK();
5656 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync
5657 << ", " << flags << ", " << timeout << ")");
5658 typedef cmds::ClientWaitSync::Result Result;
5659 Result* result = GetResultAs<Result*>();
5660 if (!result) {
5661 SetGLError(GL_OUT_OF_MEMORY, "ClientWaitSync", "");
5662 return GL_WAIT_FAILED;
5664 *result = GL_WAIT_FAILED;
5665 uint32_t v32_0 = 0, v32_1 = 0;
5666 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5667 helper_->ClientWaitSync(
5668 ToGLuint(sync), flags, v32_0, v32_1,
5669 GetResultShmId(), GetResultShmOffset());
5670 WaitForCmd();
5671 GPU_CLIENT_LOG("returned " << *result);
5672 CheckGLError();
5673 return *result;
5676 void GLES2Implementation::WaitSync(
5677 GLsync sync, GLbitfield flags, GLuint64 timeout) {
5678 GPU_CLIENT_SINGLE_THREAD_CHECK();
5679 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync << ", "
5680 << flags << ", " << timeout << ")");
5681 uint32_t v32_0 = 0, v32_1 = 0;
5682 GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
5683 helper_->WaitSync(ToGLuint(sync), flags, v32_0, v32_1);
5684 CheckGLError();
5687 void GLES2Implementation::GetInternalformativ(
5688 GLenum target, GLenum format, GLenum pname,
5689 GLsizei buf_size, GLint* params) {
5690 GPU_CLIENT_SINGLE_THREAD_CHECK();
5691 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
5692 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetInternalformativ("
5693 << GLES2Util::GetStringRenderBufferTarget(target) << ", "
5694 << GLES2Util::GetStringRenderBufferFormat(format) << ", "
5695 << GLES2Util::GetStringInternalFormatParameter(pname)
5696 << ", " << buf_size << ", "
5697 << static_cast<const void*>(params) << ")");
5698 if (buf_size < 0) {
5699 SetGLError(GL_INVALID_VALUE, "glGetInternalformativ", "bufSize < 0");
5700 return;
5702 TRACE_EVENT0("gpu", "GLES2Implementation::GetInternalformativ");
5703 if (GetInternalformativHelper(target, format, pname, buf_size, params)) {
5704 return;
5706 typedef cmds::GetInternalformativ::Result Result;
5707 Result* result = GetResultAs<Result*>();
5708 if (!result) {
5709 return;
5711 result->SetNumResults(0);
5712 helper_->GetInternalformativ(target, format, pname,
5713 GetResultShmId(), GetResultShmOffset());
5714 WaitForCmd();
5715 GPU_CLIENT_LOG_CODE_BLOCK({
5716 for (int32_t i = 0; i < result->GetNumResults(); ++i) {
5717 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
5720 if (buf_size > 0 && params) {
5721 GLint* data = result->GetData();
5722 if (buf_size >= result->GetNumResults()) {
5723 buf_size = result->GetNumResults();
5725 for (GLsizei ii = 0; ii < buf_size; ++ii) {
5726 params[ii] = data[ii];
5729 CheckGLError();
5732 GLuint GLES2Implementation::GenPathsCHROMIUM(GLsizei range) {
5733 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenPathsCHROMIUM(" << range
5734 << ")");
5735 GPU_CLIENT_SINGLE_THREAD_CHECK();
5736 static const char kFunctionName[] = "glGenPathsCHROMIUM";
5737 if (range < 0) {
5738 SetGLError(GL_INVALID_VALUE, kFunctionName, "range < 0");
5739 return 0;
5741 if (!base::IsValueInRangeForNumericType<int32_t>(range)) {
5742 SetGLError(GL_INVALID_OPERATION, kFunctionName, "range more than 32-bit");
5743 return 0;
5745 if (range == 0)
5746 return 0;
5748 GLuint first_client_id = 0;
5749 GetRangeIdHandler(id_namespaces::kPaths)
5750 ->MakeIdRange(this, range, &first_client_id);
5752 if (first_client_id == 0) {
5753 // Ran out of id space. Is not specified to raise any gl errors.
5754 return 0;
5757 helper_->GenPathsCHROMIUM(first_client_id, range);
5759 GPU_CLIENT_LOG_CODE_BLOCK({
5760 for (GLsizei i = 0; i < range; ++i) {
5761 GPU_CLIENT_LOG(" " << i << ": " << (first_client_id + i));
5764 CheckGLError();
5765 return first_client_id;
5768 void GLES2Implementation::DeletePathsCHROMIUM(GLuint first_client_id,
5769 GLsizei range) {
5770 GPU_CLIENT_SINGLE_THREAD_CHECK();
5771 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeletePathsCHROMIUM("
5772 << first_client_id << ", " << range << ")");
5773 static const char kFunctionName[] = "glDeletePathsCHROMIUM";
5775 if (range < 0) {
5776 SetGLError(GL_INVALID_VALUE, kFunctionName, "range < 0");
5777 return;
5779 if (!base::IsValueInRangeForNumericType<int32_t>(range)) {
5780 SetGLError(GL_INVALID_OPERATION, kFunctionName, "range more than 32-bit");
5781 return;
5783 if (range == 0)
5784 return;
5786 GLuint last_client_id;
5787 if (!SafeAddUint32(first_client_id, range - 1, &last_client_id)) {
5788 SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow");
5789 return;
5792 GetRangeIdHandler(id_namespaces::kPaths)
5793 ->FreeIdRange(this, first_client_id, range,
5794 &GLES2Implementation::DeletePathsCHROMIUMStub);
5795 CheckGLError();
5798 void GLES2Implementation::DeletePathsCHROMIUMStub(GLuint first_client_id,
5799 GLsizei range) {
5800 helper_->DeletePathsCHROMIUM(first_client_id, range);
5803 void GLES2Implementation::PathCommandsCHROMIUM(GLuint path,
5804 GLsizei num_commands,
5805 const GLubyte* commands,
5806 GLsizei num_coords,
5807 GLenum coord_type,
5808 const void* coords) {
5809 GPU_CLIENT_SINGLE_THREAD_CHECK();
5810 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPathCommandsCHROMIUM(" << path
5811 << ", " << num_commands << ", " << commands << ", "
5812 << num_coords << ", " << coords << ")");
5813 static const char kFunctionName[] = "glPathCommandsCHROMIUM";
5814 if (path == 0) {
5815 SetGLError(GL_INVALID_VALUE, kFunctionName, "invalid path object");
5816 return;
5818 if (num_commands < 0) {
5819 SetGLError(GL_INVALID_VALUE, kFunctionName, "numCommands < 0");
5820 return;
5822 if (num_commands != 0 && !commands) {
5823 SetGLError(GL_INVALID_VALUE, kFunctionName, "missing commands");
5824 return;
5826 if (num_coords < 0) {
5827 SetGLError(GL_INVALID_VALUE, kFunctionName, "numCoords < 0");
5828 return;
5830 if (num_coords != 0 && !coords) {
5831 SetGLError(GL_INVALID_VALUE, kFunctionName, "missing coords");
5832 return;
5834 uint32 coord_type_size = GLES2Util::GetGLTypeSizeForPathCoordType(coord_type);
5835 if (coord_type_size == 0) {
5836 SetGLError(GL_INVALID_ENUM, kFunctionName, "invalid coordType");
5837 return;
5839 if (num_commands == 0) {
5840 // No commands must mean no coords, thus nothing to memcpy. Let
5841 // the service validate the call. Validate coord_type above, so
5842 // that the parameters will be checked the in the same order
5843 // regardless of num_commands.
5844 helper_->PathCommandsCHROMIUM(path, num_commands, 0, 0, num_coords,
5845 coord_type, 0, 0);
5846 CheckGLError();
5847 return;
5850 uint32 coords_size;
5851 if (!SafeMultiplyUint32(num_coords, coord_type_size, &coords_size)) {
5852 SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow");
5853 return;
5856 uint32 required_buffer_size;
5857 if (!SafeAddUint32(coords_size, num_commands, &required_buffer_size)) {
5858 SetGLError(GL_INVALID_OPERATION, kFunctionName, "overflow");
5859 return;
5862 ScopedTransferBufferPtr buffer(required_buffer_size, helper_,
5863 transfer_buffer_);
5864 if (!buffer.valid() || buffer.size() < required_buffer_size) {
5865 SetGLError(GL_OUT_OF_MEMORY, kFunctionName, "too large");
5866 return;
5869 uint32 coords_shm_id = 0;
5870 uint32 coords_shm_offset = 0;
5871 // Copy coords first because they need more strict alignment.
5872 if (coords_size > 0) {
5873 unsigned char* coords_addr = static_cast<unsigned char*>(buffer.address());
5874 memcpy(coords_addr, coords, coords_size);
5875 coords_shm_id = buffer.shm_id();
5876 coords_shm_offset = buffer.offset();
5879 DCHECK(num_commands > 0);
5880 unsigned char* commands_addr =
5881 static_cast<unsigned char*>(buffer.address()) + coords_size;
5882 memcpy(commands_addr, commands, num_commands);
5884 helper_->PathCommandsCHROMIUM(path, num_commands, buffer.shm_id(),
5885 buffer.offset() + coords_size, num_coords,
5886 coord_type, coords_shm_id, coords_shm_offset);
5887 CheckGLError();
5890 // Include the auto-generated part of this file. We split this because it means
5891 // we can easily edit the non-auto generated parts right here in this file
5892 // instead of having to edit some template or the code generator.
5893 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
5895 } // namespace gles2
5896 } // namespace gpu