Roll leveldb 3f7758:803d69 (v1.17 -> v1.18)
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blobe7118e8736a9b0c9702b79a9388f597a6845b6aa
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // A class to emulate GLES2 over command buffers.
7 #include "gpu/command_buffer/client/gles2_implementation.h"
9 #include <GLES2/gl2ext.h>
10 #include <GLES2/gl2extchromium.h>
11 #include <algorithm>
12 #include <limits>
13 #include <map>
14 #include <queue>
15 #include <set>
16 #include <sstream>
17 #include <string>
18 #include "base/bind.h"
19 #include "gpu/command_buffer/client/buffer_tracker.h"
20 #include "gpu/command_buffer/client/gpu_control.h"
21 #include "gpu/command_buffer/client/program_info_manager.h"
22 #include "gpu/command_buffer/client/query_tracker.h"
23 #include "gpu/command_buffer/client/transfer_buffer.h"
24 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
25 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
26 #include "gpu/command_buffer/common/trace_event.h"
28 #if defined(GPU_CLIENT_DEBUG)
29 #include "base/command_line.h"
30 #include "gpu/command_buffer/client/gpu_switches.h"
31 #endif
33 namespace gpu {
34 namespace gles2 {
36 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
37 static GLuint ToGLuint(const void* ptr) {
38 return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
41 #if !defined(_MSC_VER)
42 const size_t GLES2Implementation::kMaxSizeOfSimpleResult;
43 const unsigned int GLES2Implementation::kStartingOffset;
44 #endif
46 GLES2Implementation::GLStaticState::GLStaticState() {
49 GLES2Implementation::GLStaticState::~GLStaticState() {
52 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
53 GLES2Implementation* gles2_implementation)
54 : gles2_implementation_(gles2_implementation) {
55 CHECK_EQ(0, gles2_implementation_->use_count_);
56 ++gles2_implementation_->use_count_;
59 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
60 --gles2_implementation_->use_count_;
61 CHECK_EQ(0, gles2_implementation_->use_count_);
64 GLES2Implementation::GLES2Implementation(
65 GLES2CmdHelper* helper,
66 ShareGroup* share_group,
67 TransferBufferInterface* transfer_buffer,
68 bool bind_generates_resource,
69 bool lose_context_when_out_of_memory,
70 bool support_client_side_arrays,
71 GpuControl* gpu_control)
72 : helper_(helper),
73 transfer_buffer_(transfer_buffer),
74 angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
75 chromium_framebuffer_multisample_(kUnknownExtensionStatus),
76 pack_alignment_(4),
77 unpack_alignment_(4),
78 unpack_flip_y_(false),
79 unpack_row_length_(0),
80 unpack_skip_rows_(0),
81 unpack_skip_pixels_(0),
82 pack_reverse_row_order_(false),
83 active_texture_unit_(0),
84 bound_framebuffer_(0),
85 bound_read_framebuffer_(0),
86 bound_renderbuffer_(0),
87 bound_valuebuffer_(0),
88 current_program_(0),
89 bound_array_buffer_id_(0),
90 bound_pixel_pack_transfer_buffer_id_(0),
91 bound_pixel_unpack_transfer_buffer_id_(0),
92 async_upload_token_(0),
93 async_upload_sync_(NULL),
94 async_upload_sync_shm_id_(0),
95 async_upload_sync_shm_offset_(0),
96 error_bits_(0),
97 debug_(false),
98 lose_context_when_out_of_memory_(lose_context_when_out_of_memory),
99 support_client_side_arrays_(support_client_side_arrays),
100 use_count_(0),
101 error_message_callback_(NULL),
102 gpu_control_(gpu_control),
103 capabilities_(gpu_control->GetCapabilities()),
104 weak_ptr_factory_(this) {
105 DCHECK(helper);
106 DCHECK(transfer_buffer);
107 DCHECK(gpu_control);
109 std::stringstream ss;
110 ss << std::hex << this;
111 this_in_hex_ = ss.str();
113 GPU_CLIENT_LOG_CODE_BLOCK({
114 debug_ = CommandLine::ForCurrentProcess()->HasSwitch(
115 switches::kEnableGPUClientLogging);
118 share_group_ =
119 (share_group ? share_group : new ShareGroup(bind_generates_resource));
120 DCHECK(share_group_->bind_generates_resource() == bind_generates_resource);
122 memset(&reserved_ids_, 0, sizeof(reserved_ids_));
125 bool GLES2Implementation::Initialize(
126 unsigned int starting_transfer_buffer_size,
127 unsigned int min_transfer_buffer_size,
128 unsigned int max_transfer_buffer_size,
129 unsigned int mapped_memory_limit) {
130 TRACE_EVENT0("gpu", "GLES2Implementation::Initialize");
131 DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
132 DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
133 DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
135 if (!transfer_buffer_->Initialize(
136 starting_transfer_buffer_size,
137 kStartingOffset,
138 min_transfer_buffer_size,
139 max_transfer_buffer_size,
140 kAlignment,
141 kSizeToFlush)) {
142 return false;
145 mapped_memory_.reset(
146 new MappedMemoryManager(
147 helper_,
148 base::Bind(&GLES2Implementation::PollAsyncUploads,
149 // The mapped memory manager is owned by |this| here, and
150 // since its destroyed before before we destroy ourselves
151 // we don't need extra safety measures for this closure.
152 base::Unretained(this)),
153 mapped_memory_limit));
155 unsigned chunk_size = 2 * 1024 * 1024;
156 if (mapped_memory_limit != kNoLimit) {
157 // Use smaller chunks if the client is very memory conscientious.
158 chunk_size = std::min(mapped_memory_limit / 4, chunk_size);
160 mapped_memory_->set_chunk_size_multiple(chunk_size);
162 GLStaticState::ShaderPrecisionMap* shader_precisions =
163 &static_state_.shader_precisions;
164 capabilities_.VisitPrecisions([shader_precisions](
165 GLenum shader, GLenum type, Capabilities::ShaderPrecision* result) {
166 const GLStaticState::ShaderPrecisionKey key(shader, type);
167 cmds::GetShaderPrecisionFormat::Result cached_result = {
168 true, result->min_range, result->max_range, result->precision};
169 shader_precisions->insert(std::make_pair(key, cached_result));
172 util_.set_num_compressed_texture_formats(
173 capabilities_.num_compressed_texture_formats);
174 util_.set_num_shader_binary_formats(capabilities_.num_shader_binary_formats);
176 texture_units_.reset(
177 new TextureUnit[capabilities_.max_combined_texture_image_units]);
179 query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
180 buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
182 query_id_allocator_.reset(new IdAllocator());
183 if (support_client_side_arrays_) {
184 GetIdHandler(id_namespaces::kBuffers)->MakeIds(
185 this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
188 vertex_array_object_manager_.reset(new VertexArrayObjectManager(
189 capabilities_.max_vertex_attribs, reserved_ids_[0], reserved_ids_[1],
190 support_client_side_arrays_));
192 // GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
193 // on Client & Service.
194 if (capabilities_.bind_generates_resource_chromium !=
195 (share_group_->bind_generates_resource() ? 1 : 0)) {
196 SetGLError(GL_INVALID_OPERATION,
197 "Initialize",
198 "Service bind_generates_resource mismatch.");
199 return false;
202 return true;
205 GLES2Implementation::~GLES2Implementation() {
206 // Make sure the queries are finished otherwise we'll delete the
207 // shared memory (mapped_memory_) which will free the memory used
208 // by the queries. The GPU process when validating that memory is still
209 // shared will fail and abort (ie, it will stop running).
210 WaitForCmd();
211 query_tracker_.reset();
213 if (support_client_side_arrays_)
214 DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
216 // Release any per-context data in share group.
217 share_group_->FreeContext(this);
219 buffer_tracker_.reset();
221 FreeAllAsyncUploadBuffers();
223 if (async_upload_sync_) {
224 mapped_memory_->Free(async_upload_sync_);
225 async_upload_sync_ = NULL;
228 // Make sure the commands make it the service.
229 WaitForCmd();
232 GLES2CmdHelper* GLES2Implementation::helper() const {
233 return helper_;
236 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
237 return share_group_->GetIdHandler(namespace_id);
240 IdAllocator* GLES2Implementation::GetIdAllocator(int namespace_id) const {
241 if (namespace_id == id_namespaces::kQueries)
242 return query_id_allocator_.get();
243 NOTREACHED();
244 return NULL;
247 void* GLES2Implementation::GetResultBuffer() {
248 return transfer_buffer_->GetResultBuffer();
251 int32 GLES2Implementation::GetResultShmId() {
252 return transfer_buffer_->GetShmId();
255 uint32 GLES2Implementation::GetResultShmOffset() {
256 return transfer_buffer_->GetResultOffset();
259 void GLES2Implementation::FreeUnusedSharedMemory() {
260 mapped_memory_->FreeUnused();
263 void GLES2Implementation::FreeEverything() {
264 FreeAllAsyncUploadBuffers();
265 WaitForCmd();
266 query_tracker_->Shrink();
267 FreeUnusedSharedMemory();
268 transfer_buffer_->Free();
269 helper_->FreeRingBuffer();
272 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
273 if (!helper_->IsContextLost())
274 callback.Run();
277 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
278 const base::Closure& callback) {
279 gpu_control_->SignalSyncPoint(
280 sync_point,
281 base::Bind(&GLES2Implementation::RunIfContextNotLost,
282 weak_ptr_factory_.GetWeakPtr(),
283 callback));
286 void GLES2Implementation::SignalQuery(uint32 query,
287 const base::Closure& callback) {
288 // Flush previously entered commands to ensure ordering with any
289 // glBeginQueryEXT() calls that may have been put into the context.
290 ShallowFlushCHROMIUM();
291 gpu_control_->SignalQuery(
292 query,
293 base::Bind(&GLES2Implementation::RunIfContextNotLost,
294 weak_ptr_factory_.GetWeakPtr(),
295 callback));
298 void GLES2Implementation::SetSurfaceVisible(bool visible) {
299 TRACE_EVENT1(
300 "gpu", "GLES2Implementation::SetSurfaceVisible", "visible", visible);
301 // TODO(piman): This probably should be ShallowFlushCHROMIUM().
302 Flush();
303 gpu_control_->SetSurfaceVisible(visible);
304 if (!visible)
305 FreeEverything();
308 void GLES2Implementation::WaitForCmd() {
309 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
310 helper_->CommandBufferHelper::Finish();
313 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
314 const char* extensions =
315 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
316 if (!extensions)
317 return false;
319 int length = strlen(ext);
320 while (true) {
321 int n = strcspn(extensions, " ");
322 if (n == length && 0 == strncmp(ext, extensions, length)) {
323 return true;
325 if ('\0' == extensions[n]) {
326 return false;
328 extensions += n + 1;
332 bool GLES2Implementation::IsExtensionAvailableHelper(
333 const char* extension, ExtensionStatus* status) {
334 switch (*status) {
335 case kAvailableExtensionStatus:
336 return true;
337 case kUnavailableExtensionStatus:
338 return false;
339 default: {
340 bool available = IsExtensionAvailable(extension);
341 *status = available ? kAvailableExtensionStatus :
342 kUnavailableExtensionStatus;
343 return available;
348 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
349 return IsExtensionAvailableHelper(
350 "GL_ANGLE_pack_reverse_row_order",
351 &angle_pack_reverse_row_order_status_);
354 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
355 return IsExtensionAvailableHelper(
356 "GL_CHROMIUM_framebuffer_multisample",
357 &chromium_framebuffer_multisample_);
360 const std::string& GLES2Implementation::GetLogPrefix() const {
361 const std::string& prefix(debug_marker_manager_.GetMarker());
362 return prefix.empty() ? this_in_hex_ : prefix;
365 GLenum GLES2Implementation::GetError() {
366 GPU_CLIENT_SINGLE_THREAD_CHECK();
367 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
368 GLenum err = GetGLError();
369 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
370 return err;
373 GLenum GLES2Implementation::GetClientSideGLError() {
374 if (error_bits_ == 0) {
375 return GL_NO_ERROR;
378 GLenum error = GL_NO_ERROR;
379 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
380 if ((error_bits_ & mask) != 0) {
381 error = GLES2Util::GLErrorBitToGLError(mask);
382 break;
385 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
386 return error;
389 GLenum GLES2Implementation::GetGLError() {
390 TRACE_EVENT0("gpu", "GLES2::GetGLError");
391 // Check the GL error first, then our wrapped error.
392 typedef cmds::GetError::Result Result;
393 Result* result = GetResultAs<Result*>();
394 // If we couldn't allocate a result the context is lost.
395 if (!result) {
396 return GL_NO_ERROR;
398 *result = GL_NO_ERROR;
399 helper_->GetError(GetResultShmId(), GetResultShmOffset());
400 WaitForCmd();
401 GLenum error = *result;
402 if (error == GL_NO_ERROR) {
403 error = GetClientSideGLError();
404 } else {
405 // There was an error, clear the corresponding wrapped error.
406 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
408 return error;
411 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
412 void GLES2Implementation::FailGLError(GLenum error) {
413 if (error != GL_NO_ERROR) {
414 NOTREACHED() << "Error";
417 // NOTE: Calling GetGLError overwrites data in the result buffer.
418 void GLES2Implementation::CheckGLError() {
419 FailGLError(GetGLError());
421 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
423 void GLES2Implementation::SetGLError(
424 GLenum error, const char* function_name, const char* msg) {
425 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
426 << GLES2Util::GetStringError(error) << ": "
427 << function_name << ": " << msg);
428 FailGLError(error);
429 if (msg) {
430 last_error_ = msg;
432 if (error_message_callback_) {
433 std::string temp(GLES2Util::GetStringError(error) + " : " +
434 function_name + ": " + (msg ? msg : ""));
435 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
437 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
439 if (error == GL_OUT_OF_MEMORY && lose_context_when_out_of_memory_) {
440 helper_->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
441 GL_UNKNOWN_CONTEXT_RESET_ARB);
445 void GLES2Implementation::SetGLErrorInvalidEnum(
446 const char* function_name, GLenum value, const char* label) {
447 SetGLError(GL_INVALID_ENUM, function_name,
448 (std::string(label) + " was " +
449 GLES2Util::GetStringEnum(value)).c_str());
452 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
453 std::vector<int8>* data) {
454 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
455 DCHECK(data);
456 const uint32 kStartSize = 32 * 1024;
457 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
458 if (!buffer.valid()) {
459 return false;
461 typedef cmd::GetBucketStart::Result Result;
462 Result* result = GetResultAs<Result*>();
463 if (!result) {
464 return false;
466 *result = 0;
467 helper_->GetBucketStart(
468 bucket_id, GetResultShmId(), GetResultShmOffset(),
469 buffer.size(), buffer.shm_id(), buffer.offset());
470 WaitForCmd();
471 uint32 size = *result;
472 data->resize(size);
473 if (size > 0u) {
474 uint32 offset = 0;
475 while (size) {
476 if (!buffer.valid()) {
477 buffer.Reset(size);
478 if (!buffer.valid()) {
479 return false;
481 helper_->GetBucketData(
482 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
483 WaitForCmd();
485 uint32 size_to_copy = std::min(size, buffer.size());
486 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
487 offset += size_to_copy;
488 size -= size_to_copy;
489 buffer.Release();
491 // Free the bucket. This is not required but it does free up the memory.
492 // and we don't have to wait for the result so from the client's perspective
493 // it's cheap.
494 helper_->SetBucketSize(bucket_id, 0);
496 return true;
499 void GLES2Implementation::SetBucketContents(
500 uint32 bucket_id, const void* data, size_t size) {
501 DCHECK(data);
502 helper_->SetBucketSize(bucket_id, size);
503 if (size > 0u) {
504 uint32 offset = 0;
505 while (size) {
506 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
507 if (!buffer.valid()) {
508 return;
510 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
511 buffer.size());
512 helper_->SetBucketData(
513 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
514 offset += buffer.size();
515 size -= buffer.size();
520 void GLES2Implementation::SetBucketAsCString(
521 uint32 bucket_id, const char* str) {
522 // NOTE: strings are passed NULL terminated. That means the empty
523 // string will have a size of 1 and no-string will have a size of 0
524 if (str) {
525 SetBucketContents(bucket_id, str, strlen(str) + 1);
526 } else {
527 helper_->SetBucketSize(bucket_id, 0);
531 bool GLES2Implementation::GetBucketAsString(
532 uint32 bucket_id, std::string* str) {
533 DCHECK(str);
534 std::vector<int8> data;
535 // NOTE: strings are passed NULL terminated. That means the empty
536 // string will have a size of 1 and no-string will have a size of 0
537 if (!GetBucketContents(bucket_id, &data)) {
538 return false;
540 if (data.empty()) {
541 return false;
543 str->assign(&data[0], &data[0] + data.size() - 1);
544 return true;
547 void GLES2Implementation::SetBucketAsString(
548 uint32 bucket_id, const std::string& str) {
549 // NOTE: strings are passed NULL terminated. That means the empty
550 // string will have a size of 1 and no-string will have a size of 0
551 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
554 void GLES2Implementation::Disable(GLenum cap) {
555 GPU_CLIENT_SINGLE_THREAD_CHECK();
556 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
557 << GLES2Util::GetStringCapability(cap) << ")");
558 bool changed = false;
559 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
560 helper_->Disable(cap);
562 CheckGLError();
565 void GLES2Implementation::Enable(GLenum cap) {
566 GPU_CLIENT_SINGLE_THREAD_CHECK();
567 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
568 << GLES2Util::GetStringCapability(cap) << ")");
569 bool changed = false;
570 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
571 helper_->Enable(cap);
573 CheckGLError();
576 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
577 GPU_CLIENT_SINGLE_THREAD_CHECK();
578 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
579 << GLES2Util::GetStringCapability(cap) << ")");
580 bool state = false;
581 if (!state_.GetEnabled(cap, &state)) {
582 typedef cmds::IsEnabled::Result Result;
583 Result* result = GetResultAs<Result*>();
584 if (!result) {
585 return GL_FALSE;
587 *result = 0;
588 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
589 WaitForCmd();
590 state = (*result) != 0;
593 GPU_CLIENT_LOG("returned " << state);
594 CheckGLError();
595 return state;
598 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
599 switch (pname) {
600 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
601 *params = capabilities_.max_combined_texture_image_units;
602 return true;
603 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
604 *params = capabilities_.max_cube_map_texture_size;
605 return true;
606 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
607 *params = capabilities_.max_fragment_uniform_vectors;
608 return true;
609 case GL_MAX_RENDERBUFFER_SIZE:
610 *params = capabilities_.max_renderbuffer_size;
611 return true;
612 case GL_MAX_TEXTURE_IMAGE_UNITS:
613 *params = capabilities_.max_texture_image_units;
614 return true;
615 case GL_MAX_TEXTURE_SIZE:
616 *params = capabilities_.max_texture_size;
617 return true;
618 case GL_MAX_VARYING_VECTORS:
619 *params = capabilities_.max_varying_vectors;
620 return true;
621 case GL_MAX_VERTEX_ATTRIBS:
622 *params = capabilities_.max_vertex_attribs;
623 return true;
624 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
625 *params = capabilities_.max_vertex_texture_image_units;
626 return true;
627 case GL_MAX_VERTEX_UNIFORM_VECTORS:
628 *params = capabilities_.max_vertex_uniform_vectors;
629 return true;
630 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
631 *params = capabilities_.num_compressed_texture_formats;
632 return true;
633 case GL_NUM_SHADER_BINARY_FORMATS:
634 *params = capabilities_.num_shader_binary_formats;
635 return true;
636 case GL_ARRAY_BUFFER_BINDING:
637 if (share_group_->bind_generates_resource()) {
638 *params = bound_array_buffer_id_;
639 return true;
641 return false;
642 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
643 if (share_group_->bind_generates_resource()) {
644 *params =
645 vertex_array_object_manager_->bound_element_array_buffer();
646 return true;
648 return false;
649 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
650 *params = bound_pixel_pack_transfer_buffer_id_;
651 return true;
652 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
653 *params = bound_pixel_unpack_transfer_buffer_id_;
654 return true;
655 case GL_ACTIVE_TEXTURE:
656 *params = active_texture_unit_ + GL_TEXTURE0;
657 return true;
658 case GL_TEXTURE_BINDING_2D:
659 if (share_group_->bind_generates_resource()) {
660 *params = texture_units_[active_texture_unit_].bound_texture_2d;
661 return true;
663 return false;
664 case GL_TEXTURE_BINDING_CUBE_MAP:
665 if (share_group_->bind_generates_resource()) {
666 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
667 return true;
669 return false;
670 case GL_TEXTURE_BINDING_EXTERNAL_OES:
671 if (share_group_->bind_generates_resource()) {
672 *params =
673 texture_units_[active_texture_unit_].bound_texture_external_oes;
674 return true;
676 return false;
677 case GL_FRAMEBUFFER_BINDING:
678 if (share_group_->bind_generates_resource()) {
679 *params = bound_framebuffer_;
680 return true;
682 return false;
683 case GL_READ_FRAMEBUFFER_BINDING:
684 if (IsChromiumFramebufferMultisampleAvailable() &&
685 share_group_->bind_generates_resource()) {
686 *params = bound_read_framebuffer_;
687 return true;
689 return false;
690 case GL_RENDERBUFFER_BINDING:
691 if (share_group_->bind_generates_resource()) {
692 *params = bound_renderbuffer_;
693 return true;
695 return false;
696 default:
697 return false;
701 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
702 // TODO(gman): Make this handle pnames that return more than 1 value.
703 GLint value;
704 if (!GetHelper(pname, &value)) {
705 return false;
707 *params = static_cast<GLboolean>(value);
708 return true;
711 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
712 // TODO(gman): Make this handle pnames that return more than 1 value.
713 GLint value;
714 if (!GetHelper(pname, &value)) {
715 return false;
717 *params = static_cast<GLfloat>(value);
718 return true;
721 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
722 return GetHelper(pname, params);
725 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
726 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
727 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
728 Result* result = GetResultAs<Result*>();
729 if (!result) {
730 return 0;
732 *result = 0;
733 helper_->GetMaxValueInBufferCHROMIUM(
734 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
735 WaitForCmd();
736 return *result;
739 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
740 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
741 GPU_CLIENT_SINGLE_THREAD_CHECK();
742 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
743 << buffer_id << ", " << count << ", "
744 << GLES2Util::GetStringGetMaxIndexType(type)
745 << ", " << offset << ")");
746 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
747 buffer_id, count, type, offset);
748 GPU_CLIENT_LOG("returned " << result);
749 CheckGLError();
750 return result;
753 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
754 if (restore) {
755 RestoreArrayBuffer(restore);
756 // Restore the element array binding.
757 // We only need to restore it if it wasn't a client side array.
758 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
759 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
764 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
765 if (restore) {
766 // Restore the user's current binding.
767 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_);
771 void GLES2Implementation::DrawElements(
772 GLenum mode, GLsizei count, GLenum type, const void* indices) {
773 GPU_CLIENT_SINGLE_THREAD_CHECK();
774 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
775 << GLES2Util::GetStringDrawMode(mode) << ", "
776 << count << ", "
777 << GLES2Util::GetStringIndexType(type) << ", "
778 << static_cast<const void*>(indices) << ")");
779 if (count < 0) {
780 SetGLError(GL_INVALID_VALUE, "glDrawElements", "count less than 0.");
781 return;
783 if (count == 0) {
784 return;
786 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
787 !ValidateOffset("glDrawElements", reinterpret_cast<GLintptr>(indices))) {
788 return;
790 GLuint offset = 0;
791 bool simulated = false;
792 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
793 "glDrawElements", this, helper_, count, type, 0, indices,
794 &offset, &simulated)) {
795 return;
797 helper_->DrawElements(mode, count, type, offset);
798 RestoreElementAndArrayBuffers(simulated);
799 CheckGLError();
802 void GLES2Implementation::Flush() {
803 GPU_CLIENT_SINGLE_THREAD_CHECK();
804 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
805 // Insert the cmd to call glFlush
806 helper_->Flush();
807 // Flush our command buffer
808 // (tell the service to execute up to the flush cmd.)
809 helper_->CommandBufferHelper::Flush();
812 void GLES2Implementation::ShallowFlushCHROMIUM() {
813 GPU_CLIENT_SINGLE_THREAD_CHECK();
814 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
815 // Flush our command buffer
816 // (tell the service to execute up to the flush cmd.)
817 helper_->CommandBufferHelper::Flush();
818 // TODO(piman): Add the FreeEverything() logic here.
821 void GLES2Implementation::Finish() {
822 GPU_CLIENT_SINGLE_THREAD_CHECK();
823 FinishHelper();
826 void GLES2Implementation::ShallowFinishCHROMIUM() {
827 GPU_CLIENT_SINGLE_THREAD_CHECK();
828 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
829 // Flush our command buffer (tell the service to execute up to the flush cmd
830 // and don't return until it completes).
831 helper_->CommandBufferHelper::Finish();
834 void GLES2Implementation::FinishHelper() {
835 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
836 TRACE_EVENT0("gpu", "GLES2::Finish");
837 // Insert the cmd to call glFinish
838 helper_->Finish();
839 // Finish our command buffer
840 // (tell the service to execute up to the Finish cmd and wait for it to
841 // execute.)
842 helper_->CommandBufferHelper::Finish();
845 void GLES2Implementation::SwapBuffers() {
846 GPU_CLIENT_SINGLE_THREAD_CHECK();
847 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
848 // TODO(piman): Strictly speaking we'd want to insert the token after the
849 // swap, but the state update with the updated token might not have happened
850 // by the time the SwapBuffer callback gets called, forcing us to synchronize
851 // with the GPU process more than needed. So instead, make it happen before.
852 // All it means is that we could be slightly looser on the kMaxSwapBuffers
853 // semantics if the client doesn't use the callback mechanism, and by chance
854 // the scheduler yields between the InsertToken and the SwapBuffers.
855 swap_buffers_tokens_.push(helper_->InsertToken());
856 helper_->SwapBuffers();
857 helper_->CommandBufferHelper::Flush();
858 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
859 // compensate for TODO above.
860 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
861 helper_->WaitForToken(swap_buffers_tokens_.front());
862 swap_buffers_tokens_.pop();
866 void GLES2Implementation::BindAttribLocation(
867 GLuint program, GLuint index, const char* name) {
868 GPU_CLIENT_SINGLE_THREAD_CHECK();
869 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
870 << program << ", " << index << ", " << name << ")");
871 SetBucketAsString(kResultBucketId, name);
872 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
873 helper_->SetBucketSize(kResultBucketId, 0);
874 CheckGLError();
877 void GLES2Implementation::BindUniformLocationCHROMIUM(
878 GLuint program, GLint location, const char* name) {
879 GPU_CLIENT_SINGLE_THREAD_CHECK();
880 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
881 << program << ", " << location << ", " << name << ")");
882 SetBucketAsString(kResultBucketId, name);
883 helper_->BindUniformLocationCHROMIUMBucket(
884 program, location, kResultBucketId);
885 helper_->SetBucketSize(kResultBucketId, 0);
886 CheckGLError();
889 void GLES2Implementation::GetVertexAttribPointerv(
890 GLuint index, GLenum pname, void** ptr) {
891 GPU_CLIENT_SINGLE_THREAD_CHECK();
892 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
893 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
894 << static_cast<void*>(ptr) << ")");
895 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
896 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
897 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
898 typedef cmds::GetVertexAttribPointerv::Result Result;
899 Result* result = GetResultAs<Result*>();
900 if (!result) {
901 return;
903 result->SetNumResults(0);
904 helper_->GetVertexAttribPointerv(
905 index, pname, GetResultShmId(), GetResultShmOffset());
906 WaitForCmd();
907 result->CopyResult(ptr);
908 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
910 GPU_CLIENT_LOG_CODE_BLOCK({
911 for (int32 i = 0; i < num_results; ++i) {
912 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
915 CheckGLError();
918 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
919 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
920 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
921 SetGLError(
922 GL_INVALID_VALUE,
923 "glDeleteProgram", "id not created by this context.");
924 return false;
926 if (program == current_program_) {
927 current_program_ = 0;
929 return true;
932 void GLES2Implementation::DeleteProgramStub(
933 GLsizei n, const GLuint* programs) {
934 DCHECK_EQ(1, n);
935 share_group_->program_info_manager()->DeleteInfo(programs[0]);
936 helper_->DeleteProgram(programs[0]);
939 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
940 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
941 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
942 SetGLError(
943 GL_INVALID_VALUE,
944 "glDeleteShader", "id not created by this context.");
945 return false;
947 return true;
950 void GLES2Implementation::DeleteShaderStub(
951 GLsizei n, const GLuint* shaders) {
952 DCHECK_EQ(1, n);
953 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
954 helper_->DeleteShader(shaders[0]);
958 GLint GLES2Implementation::GetAttribLocationHelper(
959 GLuint program, const char* name) {
960 typedef cmds::GetAttribLocation::Result Result;
961 Result* result = GetResultAs<Result*>();
962 if (!result) {
963 return -1;
965 *result = -1;
966 SetBucketAsCString(kResultBucketId, name);
967 helper_->GetAttribLocation(
968 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
969 WaitForCmd();
970 helper_->SetBucketSize(kResultBucketId, 0);
971 return *result;
974 GLint GLES2Implementation::GetAttribLocation(
975 GLuint program, const char* name) {
976 GPU_CLIENT_SINGLE_THREAD_CHECK();
977 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
978 << ", " << name << ")");
979 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
980 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
981 this, program, name);
982 GPU_CLIENT_LOG("returned " << loc);
983 CheckGLError();
984 return loc;
987 GLint GLES2Implementation::GetUniformLocationHelper(
988 GLuint program, const char* name) {
989 typedef cmds::GetUniformLocation::Result Result;
990 Result* result = GetResultAs<Result*>();
991 if (!result) {
992 return -1;
994 *result = -1;
995 SetBucketAsCString(kResultBucketId, name);
996 helper_->GetUniformLocation(program, kResultBucketId,
997 GetResultShmId(), GetResultShmOffset());
998 WaitForCmd();
999 helper_->SetBucketSize(kResultBucketId, 0);
1000 return *result;
1003 GLint GLES2Implementation::GetUniformLocation(
1004 GLuint program, const char* name) {
1005 GPU_CLIENT_SINGLE_THREAD_CHECK();
1006 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1007 << ", " << name << ")");
1008 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1009 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1010 this, program, name);
1011 GPU_CLIENT_LOG("returned " << loc);
1012 CheckGLError();
1013 return loc;
1016 bool GLES2Implementation::GetProgramivHelper(
1017 GLuint program, GLenum pname, GLint* params) {
1018 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1019 this, program, pname, params);
1020 GPU_CLIENT_LOG_CODE_BLOCK({
1021 if (got_value) {
1022 GPU_CLIENT_LOG(" 0: " << *params);
1025 return got_value;
1028 void GLES2Implementation::LinkProgram(GLuint program) {
1029 GPU_CLIENT_SINGLE_THREAD_CHECK();
1030 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1031 helper_->LinkProgram(program);
1032 share_group_->program_info_manager()->CreateInfo(program);
1033 CheckGLError();
1036 void GLES2Implementation::ShaderBinary(
1037 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1038 GLsizei length) {
1039 GPU_CLIENT_SINGLE_THREAD_CHECK();
1040 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1041 << static_cast<const void*>(shaders) << ", "
1042 << GLES2Util::GetStringEnum(binaryformat) << ", "
1043 << static_cast<const void*>(binary) << ", "
1044 << length << ")");
1045 if (n < 0) {
1046 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1047 return;
1049 if (length < 0) {
1050 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1051 return;
1053 // TODO(gman): ShaderBinary should use buckets.
1054 unsigned int shader_id_size = n * sizeof(*shaders);
1055 ScopedTransferBufferArray<GLint> buffer(
1056 shader_id_size + length, helper_, transfer_buffer_);
1057 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1058 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1059 return;
1061 void* shader_ids = buffer.elements();
1062 void* shader_data = buffer.elements() + shader_id_size;
1063 memcpy(shader_ids, shaders, shader_id_size);
1064 memcpy(shader_data, binary, length);
1065 helper_->ShaderBinary(
1067 buffer.shm_id(),
1068 buffer.offset(),
1069 binaryformat,
1070 buffer.shm_id(),
1071 buffer.offset() + shader_id_size,
1072 length);
1073 CheckGLError();
1076 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1077 GPU_CLIENT_SINGLE_THREAD_CHECK();
1078 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1079 << GLES2Util::GetStringPixelStore(pname) << ", "
1080 << param << ")");
1081 switch (pname) {
1082 case GL_PACK_ALIGNMENT:
1083 pack_alignment_ = param;
1084 break;
1085 case GL_UNPACK_ALIGNMENT:
1086 unpack_alignment_ = param;
1087 break;
1088 case GL_UNPACK_ROW_LENGTH_EXT:
1089 unpack_row_length_ = param;
1090 return;
1091 case GL_UNPACK_SKIP_ROWS_EXT:
1092 unpack_skip_rows_ = param;
1093 return;
1094 case GL_UNPACK_SKIP_PIXELS_EXT:
1095 unpack_skip_pixels_ = param;
1096 return;
1097 case GL_UNPACK_FLIP_Y_CHROMIUM:
1098 unpack_flip_y_ = (param != 0);
1099 break;
1100 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1101 pack_reverse_row_order_ =
1102 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1103 break;
1104 default:
1105 break;
1107 helper_->PixelStorei(pname, param);
1108 CheckGLError();
1111 void GLES2Implementation::VertexAttribPointer(
1112 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1113 const void* ptr) {
1114 GPU_CLIENT_SINGLE_THREAD_CHECK();
1115 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1116 << index << ", "
1117 << size << ", "
1118 << GLES2Util::GetStringVertexAttribType(type) << ", "
1119 << GLES2Util::GetStringBool(normalized) << ", "
1120 << stride << ", "
1121 << static_cast<const void*>(ptr) << ")");
1122 // Record the info on the client side.
1123 if (!vertex_array_object_manager_->SetAttribPointer(
1124 bound_array_buffer_id_, index, size, type, normalized, stride, ptr)) {
1125 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1126 "client side arrays are not allowed in vertex array objects.");
1127 return;
1129 if (!support_client_side_arrays_ || bound_array_buffer_id_ != 0) {
1130 // Only report NON client side buffers to the service.
1131 if (!ValidateOffset("glVertexAttribPointer",
1132 reinterpret_cast<GLintptr>(ptr))) {
1133 return;
1135 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1136 ToGLuint(ptr));
1138 CheckGLError();
1141 void GLES2Implementation::VertexAttribDivisorANGLE(
1142 GLuint index, GLuint divisor) {
1143 GPU_CLIENT_SINGLE_THREAD_CHECK();
1144 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1145 << index << ", "
1146 << divisor << ") ");
1147 // Record the info on the client side.
1148 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1149 helper_->VertexAttribDivisorANGLE(index, divisor);
1150 CheckGLError();
1153 void GLES2Implementation::ShaderSource(
1154 GLuint shader,
1155 GLsizei count,
1156 const GLchar* const* source,
1157 const GLint* length) {
1158 GPU_CLIENT_SINGLE_THREAD_CHECK();
1159 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderSource("
1160 << shader << ", " << count << ", "
1161 << static_cast<const void*>(source) << ", "
1162 << static_cast<const void*>(length) << ")");
1163 GPU_CLIENT_LOG_CODE_BLOCK({
1164 for (GLsizei ii = 0; ii < count; ++ii) {
1165 if (source[ii]) {
1166 if (length && length[ii] >= 0) {
1167 std::string str(source[ii], length[ii]);
1168 GPU_CLIENT_LOG(" " << ii << ": ---\n" << str << "\n---");
1169 } else {
1170 GPU_CLIENT_LOG(" " << ii << ": ---\n" << source[ii] << "\n---");
1172 } else {
1173 GPU_CLIENT_LOG(" " << ii << ": NULL");
1177 if (count < 0) {
1178 SetGLError(GL_INVALID_VALUE, "glShaderSource", "count < 0");
1179 return;
1181 if (shader == 0) {
1182 SetGLError(GL_INVALID_VALUE, "glShaderSource", "shader == 0");
1183 return;
1186 // Compute the total size.
1187 uint32 total_size = 1;
1188 for (GLsizei ii = 0; ii < count; ++ii) {
1189 if (source[ii]) {
1190 total_size += (length && length[ii] >= 0) ?
1191 static_cast<size_t>(length[ii]) : strlen(source[ii]);
1195 // Concatenate all the strings in to a bucket on the service.
1196 helper_->SetBucketSize(kResultBucketId, total_size);
1197 uint32 offset = 0;
1198 for (GLsizei ii = 0; ii <= count; ++ii) {
1199 const char* src = ii < count ? source[ii] : "";
1200 if (src) {
1201 uint32 size = ii < count ?
1202 (length ? static_cast<size_t>(length[ii]) : strlen(src)) : 1;
1203 while (size) {
1204 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1205 if (!buffer.valid()) {
1206 return;
1208 memcpy(buffer.address(), src, buffer.size());
1209 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
1210 buffer.shm_id(), buffer.offset());
1211 offset += buffer.size();
1212 src += buffer.size();
1213 size -= buffer.size();
1218 DCHECK_EQ(total_size, offset);
1220 helper_->ShaderSourceBucket(shader, kResultBucketId);
1221 helper_->SetBucketSize(kResultBucketId, 0);
1222 CheckGLError();
1225 void GLES2Implementation::BufferDataHelper(
1226 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1227 if (!ValidateSize("glBufferData", size))
1228 return;
1230 GLuint buffer_id;
1231 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1232 if (!buffer_id) {
1233 return;
1236 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1237 if (buffer)
1238 RemoveTransferBuffer(buffer);
1240 // Create new buffer.
1241 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1242 DCHECK(buffer);
1243 if (buffer->address() && data)
1244 memcpy(buffer->address(), data, size);
1245 return;
1248 if (size == 0) {
1249 return;
1252 // If there is no data just send BufferData
1253 if (!data) {
1254 helper_->BufferData(target, size, 0, 0, usage);
1255 return;
1258 // See if we can send all at once.
1259 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1260 if (!buffer.valid()) {
1261 return;
1264 if (buffer.size() >= static_cast<unsigned int>(size)) {
1265 memcpy(buffer.address(), data, size);
1266 helper_->BufferData(
1267 target,
1268 size,
1269 buffer.shm_id(),
1270 buffer.offset(),
1271 usage);
1272 return;
1275 // Make the buffer with BufferData then send via BufferSubData
1276 helper_->BufferData(target, size, 0, 0, usage);
1277 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1278 CheckGLError();
1281 void GLES2Implementation::BufferData(
1282 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1283 GPU_CLIENT_SINGLE_THREAD_CHECK();
1284 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1285 << GLES2Util::GetStringBufferTarget(target) << ", "
1286 << size << ", "
1287 << static_cast<const void*>(data) << ", "
1288 << GLES2Util::GetStringBufferUsage(usage) << ")");
1289 BufferDataHelper(target, size, data, usage);
1290 CheckGLError();
1293 void GLES2Implementation::BufferSubDataHelper(
1294 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1295 if (size == 0) {
1296 return;
1299 if (!ValidateSize("glBufferSubData", size) ||
1300 !ValidateOffset("glBufferSubData", offset)) {
1301 return;
1304 GLuint buffer_id;
1305 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1306 if (!buffer_id) {
1307 return;
1309 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1310 if (!buffer) {
1311 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1312 return;
1315 int32 end = 0;
1316 int32 buffer_size = buffer->size();
1317 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1318 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1319 return;
1322 if (buffer->address() && data)
1323 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1324 return;
1327 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1328 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1331 void GLES2Implementation::BufferSubDataHelperImpl(
1332 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1333 ScopedTransferBufferPtr* buffer) {
1334 DCHECK(buffer);
1335 DCHECK_GT(size, 0);
1337 const int8* source = static_cast<const int8*>(data);
1338 while (size) {
1339 if (!buffer->valid() || buffer->size() == 0) {
1340 buffer->Reset(size);
1341 if (!buffer->valid()) {
1342 return;
1345 memcpy(buffer->address(), source, buffer->size());
1346 helper_->BufferSubData(
1347 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1348 offset += buffer->size();
1349 source += buffer->size();
1350 size -= buffer->size();
1351 buffer->Release();
1355 void GLES2Implementation::BufferSubData(
1356 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1357 GPU_CLIENT_SINGLE_THREAD_CHECK();
1358 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1359 << GLES2Util::GetStringBufferTarget(target) << ", "
1360 << offset << ", " << size << ", "
1361 << static_cast<const void*>(data) << ")");
1362 BufferSubDataHelper(target, offset, size, data);
1363 CheckGLError();
1366 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
1367 int32 token = buffer->last_usage_token();
1368 uint32 async_token = buffer->last_async_upload_token();
1370 if (async_token) {
1371 if (HasAsyncUploadTokenPassed(async_token)) {
1372 buffer_tracker_->Free(buffer);
1373 } else {
1374 detached_async_upload_memory_.push_back(
1375 std::make_pair(buffer->address(), async_token));
1376 buffer_tracker_->Unmanage(buffer);
1378 } else if (token) {
1379 if (helper_->HasTokenPassed(token))
1380 buffer_tracker_->Free(buffer);
1381 else
1382 buffer_tracker_->FreePendingToken(buffer, token);
1383 } else {
1384 buffer_tracker_->Free(buffer);
1387 buffer_tracker_->RemoveBuffer(buffer->id());
1390 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1391 GLenum target,
1392 const char* function_name,
1393 GLuint* buffer_id) {
1394 *buffer_id = 0;
1396 switch (target) {
1397 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1398 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1399 break;
1400 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1401 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1402 break;
1403 default:
1404 // Unknown target
1405 return false;
1407 if (!*buffer_id) {
1408 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1410 return true;
1413 BufferTracker::Buffer*
1414 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1415 GLuint buffer_id,
1416 const char* function_name,
1417 GLuint offset, GLsizei size) {
1418 DCHECK(buffer_id);
1419 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1420 if (!buffer) {
1421 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1422 return NULL;
1424 if (buffer->mapped()) {
1425 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1426 return NULL;
1428 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1429 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1430 return NULL;
1432 return buffer;
1435 void GLES2Implementation::CompressedTexImage2D(
1436 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1437 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1438 GPU_CLIENT_SINGLE_THREAD_CHECK();
1439 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1440 << GLES2Util::GetStringTextureTarget(target) << ", "
1441 << level << ", "
1442 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1443 << width << ", " << height << ", " << border << ", "
1444 << image_size << ", "
1445 << static_cast<const void*>(data) << ")");
1446 if (width < 0 || height < 0 || level < 0) {
1447 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1448 return;
1450 if (border != 0) {
1451 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "border != 0");
1452 return;
1454 if (height == 0 || width == 0) {
1455 return;
1457 // If there's a pixel unpack buffer bound use it when issuing
1458 // CompressedTexImage2D.
1459 if (bound_pixel_unpack_transfer_buffer_id_) {
1460 GLuint offset = ToGLuint(data);
1461 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1462 bound_pixel_unpack_transfer_buffer_id_,
1463 "glCompressedTexImage2D", offset, image_size);
1464 if (buffer && buffer->shm_id() != -1) {
1465 helper_->CompressedTexImage2D(
1466 target, level, internalformat, width, height, image_size,
1467 buffer->shm_id(), buffer->shm_offset() + offset);
1468 buffer->set_last_usage_token(helper_->InsertToken());
1470 return;
1472 SetBucketContents(kResultBucketId, data, image_size);
1473 helper_->CompressedTexImage2DBucket(
1474 target, level, internalformat, width, height, kResultBucketId);
1475 // Free the bucket. This is not required but it does free up the memory.
1476 // and we don't have to wait for the result so from the client's perspective
1477 // it's cheap.
1478 helper_->SetBucketSize(kResultBucketId, 0);
1479 CheckGLError();
1482 void GLES2Implementation::CompressedTexSubImage2D(
1483 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1484 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1485 GPU_CLIENT_SINGLE_THREAD_CHECK();
1486 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1487 << GLES2Util::GetStringTextureTarget(target) << ", "
1488 << level << ", "
1489 << xoffset << ", " << yoffset << ", "
1490 << width << ", " << height << ", "
1491 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1492 << image_size << ", "
1493 << static_cast<const void*>(data) << ")");
1494 if (width < 0 || height < 0 || level < 0) {
1495 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1496 return;
1498 // If there's a pixel unpack buffer bound use it when issuing
1499 // CompressedTexSubImage2D.
1500 if (bound_pixel_unpack_transfer_buffer_id_) {
1501 GLuint offset = ToGLuint(data);
1502 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1503 bound_pixel_unpack_transfer_buffer_id_,
1504 "glCompressedTexSubImage2D", offset, image_size);
1505 if (buffer && buffer->shm_id() != -1) {
1506 helper_->CompressedTexSubImage2D(
1507 target, level, xoffset, yoffset, width, height, format, image_size,
1508 buffer->shm_id(), buffer->shm_offset() + offset);
1509 buffer->set_last_usage_token(helper_->InsertToken());
1510 CheckGLError();
1512 return;
1514 SetBucketContents(kResultBucketId, data, image_size);
1515 helper_->CompressedTexSubImage2DBucket(
1516 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1517 // Free the bucket. This is not required but it does free up the memory.
1518 // and we don't have to wait for the result so from the client's perspective
1519 // it's cheap.
1520 helper_->SetBucketSize(kResultBucketId, 0);
1521 CheckGLError();
1524 namespace {
1526 void CopyRectToBuffer(
1527 const void* pixels,
1528 uint32 height,
1529 uint32 unpadded_row_size,
1530 uint32 pixels_padded_row_size,
1531 bool flip_y,
1532 void* buffer,
1533 uint32 buffer_padded_row_size) {
1534 const int8* source = static_cast<const int8*>(pixels);
1535 int8* dest = static_cast<int8*>(buffer);
1536 if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
1537 if (flip_y) {
1538 dest += buffer_padded_row_size * (height - 1);
1540 // the last row is copied unpadded at the end
1541 for (; height > 1; --height) {
1542 memcpy(dest, source, buffer_padded_row_size);
1543 if (flip_y) {
1544 dest -= buffer_padded_row_size;
1545 } else {
1546 dest += buffer_padded_row_size;
1548 source += pixels_padded_row_size;
1550 memcpy(dest, source, unpadded_row_size);
1551 } else {
1552 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
1553 memcpy(dest, source, size);
1557 } // anonymous namespace
1559 void GLES2Implementation::TexImage2D(
1560 GLenum target, GLint level, GLint internalformat, GLsizei width,
1561 GLsizei height, GLint border, GLenum format, GLenum type,
1562 const void* pixels) {
1563 GPU_CLIENT_SINGLE_THREAD_CHECK();
1564 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1565 << GLES2Util::GetStringTextureTarget(target) << ", "
1566 << level << ", "
1567 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1568 << width << ", " << height << ", " << border << ", "
1569 << GLES2Util::GetStringTextureFormat(format) << ", "
1570 << GLES2Util::GetStringPixelType(type) << ", "
1571 << static_cast<const void*>(pixels) << ")");
1572 if (level < 0 || height < 0 || width < 0) {
1573 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
1574 return;
1576 if (border != 0) {
1577 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
1578 return;
1580 uint32 size;
1581 uint32 unpadded_row_size;
1582 uint32 padded_row_size;
1583 if (!GLES2Util::ComputeImageDataSizes(
1584 width, height, format, type, unpack_alignment_, &size,
1585 &unpadded_row_size, &padded_row_size)) {
1586 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
1587 return;
1590 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1591 if (bound_pixel_unpack_transfer_buffer_id_) {
1592 GLuint offset = ToGLuint(pixels);
1593 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1594 bound_pixel_unpack_transfer_buffer_id_,
1595 "glTexImage2D", offset, size);
1596 if (buffer && buffer->shm_id() != -1) {
1597 helper_->TexImage2D(
1598 target, level, internalformat, width, height, format, type,
1599 buffer->shm_id(), buffer->shm_offset() + offset);
1600 buffer->set_last_usage_token(helper_->InsertToken());
1601 CheckGLError();
1603 return;
1606 // If there's no data just issue TexImage2D
1607 if (!pixels) {
1608 helper_->TexImage2D(
1609 target, level, internalformat, width, height, format, type,
1610 0, 0);
1611 CheckGLError();
1612 return;
1615 // compute the advance bytes per row for the src pixels
1616 uint32 src_padded_row_size;
1617 if (unpack_row_length_ > 0) {
1618 if (!GLES2Util::ComputeImagePaddedRowSize(
1619 unpack_row_length_, format, type, unpack_alignment_,
1620 &src_padded_row_size)) {
1621 SetGLError(
1622 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1623 return;
1625 } else {
1626 src_padded_row_size = padded_row_size;
1629 // advance pixels pointer past the skip rows and skip pixels
1630 pixels = reinterpret_cast<const int8*>(pixels) +
1631 unpack_skip_rows_ * src_padded_row_size;
1632 if (unpack_skip_pixels_) {
1633 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1634 pixels = reinterpret_cast<const int8*>(pixels) +
1635 unpack_skip_pixels_ * group_size;
1638 // Check if we can send it all at once.
1639 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1640 if (!buffer.valid()) {
1641 return;
1644 if (buffer.size() >= size) {
1645 CopyRectToBuffer(
1646 pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
1647 buffer.address(), padded_row_size);
1648 helper_->TexImage2D(
1649 target, level, internalformat, width, height, format, type,
1650 buffer.shm_id(), buffer.offset());
1651 CheckGLError();
1652 return;
1655 // No, so send it using TexSubImage2D.
1656 helper_->TexImage2D(
1657 target, level, internalformat, width, height, format, type,
1658 0, 0);
1659 TexSubImage2DImpl(
1660 target, level, 0, 0, width, height, format, type, unpadded_row_size,
1661 pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
1662 CheckGLError();
1665 void GLES2Implementation::TexSubImage2D(
1666 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1667 GLsizei height, GLenum format, GLenum type, const void* pixels) {
1668 GPU_CLIENT_SINGLE_THREAD_CHECK();
1669 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1670 << GLES2Util::GetStringTextureTarget(target) << ", "
1671 << level << ", "
1672 << xoffset << ", " << yoffset << ", "
1673 << width << ", " << height << ", "
1674 << GLES2Util::GetStringTextureFormat(format) << ", "
1675 << GLES2Util::GetStringPixelType(type) << ", "
1676 << static_cast<const void*>(pixels) << ")");
1678 if (level < 0 || height < 0 || width < 0) {
1679 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
1680 return;
1682 if (height == 0 || width == 0) {
1683 return;
1686 uint32 temp_size;
1687 uint32 unpadded_row_size;
1688 uint32 padded_row_size;
1689 if (!GLES2Util::ComputeImageDataSizes(
1690 width, height, format, type, unpack_alignment_, &temp_size,
1691 &unpadded_row_size, &padded_row_size)) {
1692 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
1693 return;
1696 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1697 if (bound_pixel_unpack_transfer_buffer_id_) {
1698 GLuint offset = ToGLuint(pixels);
1699 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1700 bound_pixel_unpack_transfer_buffer_id_,
1701 "glTexSubImage2D", offset, temp_size);
1702 if (buffer && buffer->shm_id() != -1) {
1703 helper_->TexSubImage2D(
1704 target, level, xoffset, yoffset, width, height, format, type,
1705 buffer->shm_id(), buffer->shm_offset() + offset, false);
1706 buffer->set_last_usage_token(helper_->InsertToken());
1707 CheckGLError();
1709 return;
1712 // compute the advance bytes per row for the src pixels
1713 uint32 src_padded_row_size;
1714 if (unpack_row_length_ > 0) {
1715 if (!GLES2Util::ComputeImagePaddedRowSize(
1716 unpack_row_length_, format, type, unpack_alignment_,
1717 &src_padded_row_size)) {
1718 SetGLError(
1719 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1720 return;
1722 } else {
1723 src_padded_row_size = padded_row_size;
1726 // advance pixels pointer past the skip rows and skip pixels
1727 pixels = reinterpret_cast<const int8*>(pixels) +
1728 unpack_skip_rows_ * src_padded_row_size;
1729 if (unpack_skip_pixels_) {
1730 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1731 pixels = reinterpret_cast<const int8*>(pixels) +
1732 unpack_skip_pixels_ * group_size;
1735 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
1736 TexSubImage2DImpl(
1737 target, level, xoffset, yoffset, width, height, format, type,
1738 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
1739 padded_row_size);
1740 CheckGLError();
1743 static GLint ComputeNumRowsThatFitInBuffer(
1744 uint32 padded_row_size, uint32 unpadded_row_size,
1745 unsigned int size) {
1746 DCHECK_GE(unpadded_row_size, 0u);
1747 if (padded_row_size == 0) {
1748 return 1;
1750 GLint num_rows = size / padded_row_size;
1751 return num_rows + (size - num_rows * padded_row_size) / unpadded_row_size;
1754 void GLES2Implementation::TexSubImage2DImpl(
1755 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1756 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
1757 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
1758 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
1759 DCHECK(buffer);
1760 DCHECK_GE(level, 0);
1761 DCHECK_GT(height, 0);
1762 DCHECK_GT(width, 0);
1764 const int8* source = reinterpret_cast<const int8*>(pixels);
1765 GLint original_yoffset = yoffset;
1766 // Transfer by rows.
1767 while (height) {
1768 unsigned int desired_size =
1769 buffer_padded_row_size * (height - 1) + unpadded_row_size;
1770 if (!buffer->valid() || buffer->size() == 0) {
1771 buffer->Reset(desired_size);
1772 if (!buffer->valid()) {
1773 return;
1777 GLint num_rows = ComputeNumRowsThatFitInBuffer(
1778 buffer_padded_row_size, unpadded_row_size, buffer->size());
1779 num_rows = std::min(num_rows, height);
1780 CopyRectToBuffer(
1781 source, num_rows, unpadded_row_size, pixels_padded_row_size,
1782 unpack_flip_y_, buffer->address(), buffer_padded_row_size);
1783 GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
1784 helper_->TexSubImage2D(
1785 target, level, xoffset, y, width, num_rows, format, type,
1786 buffer->shm_id(), buffer->offset(), internal);
1787 buffer->Release();
1788 yoffset += num_rows;
1789 source += num_rows * pixels_padded_row_size;
1790 height -= num_rows;
1794 bool GLES2Implementation::GetActiveAttribHelper(
1795 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1796 GLenum* type, char* name) {
1797 // Clear the bucket so if the command fails nothing will be in it.
1798 helper_->SetBucketSize(kResultBucketId, 0);
1799 typedef cmds::GetActiveAttrib::Result Result;
1800 Result* result = GetResultAs<Result*>();
1801 if (!result) {
1802 return false;
1804 // Set as failed so if the command fails we'll recover.
1805 result->success = false;
1806 helper_->GetActiveAttrib(program, index, kResultBucketId,
1807 GetResultShmId(), GetResultShmOffset());
1808 WaitForCmd();
1809 if (result->success) {
1810 if (size) {
1811 *size = result->size;
1813 if (type) {
1814 *type = result->type;
1816 if (length || name) {
1817 std::vector<int8> str;
1818 GetBucketContents(kResultBucketId, &str);
1819 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
1820 std::max(static_cast<size_t>(0),
1821 str.size() - 1));
1822 if (length) {
1823 *length = max_size;
1825 if (name && bufsize > 0) {
1826 memcpy(name, &str[0], max_size);
1827 name[max_size] = '\0';
1831 return result->success != 0;
1834 void GLES2Implementation::GetActiveAttrib(
1835 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1836 GLenum* type, char* name) {
1837 GPU_CLIENT_SINGLE_THREAD_CHECK();
1838 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
1839 << program << ", " << index << ", " << bufsize << ", "
1840 << static_cast<const void*>(length) << ", "
1841 << static_cast<const void*>(size) << ", "
1842 << static_cast<const void*>(type) << ", "
1843 << static_cast<const void*>(name) << ", ");
1844 if (bufsize < 0) {
1845 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
1846 return;
1848 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
1849 bool success = share_group_->program_info_manager()->GetActiveAttrib(
1850 this, program, index, bufsize, length, size, type, name);
1851 if (success) {
1852 if (size) {
1853 GPU_CLIENT_LOG(" size: " << *size);
1855 if (type) {
1856 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
1858 if (name) {
1859 GPU_CLIENT_LOG(" name: " << name);
1862 CheckGLError();
1865 bool GLES2Implementation::GetActiveUniformHelper(
1866 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1867 GLenum* type, char* name) {
1868 // Clear the bucket so if the command fails nothing will be in it.
1869 helper_->SetBucketSize(kResultBucketId, 0);
1870 typedef cmds::GetActiveUniform::Result Result;
1871 Result* result = GetResultAs<Result*>();
1872 if (!result) {
1873 return false;
1875 // Set as failed so if the command fails we'll recover.
1876 result->success = false;
1877 helper_->GetActiveUniform(program, index, kResultBucketId,
1878 GetResultShmId(), GetResultShmOffset());
1879 WaitForCmd();
1880 if (result->success) {
1881 if (size) {
1882 *size = result->size;
1884 if (type) {
1885 *type = result->type;
1887 if (length || name) {
1888 std::vector<int8> str;
1889 GetBucketContents(kResultBucketId, &str);
1890 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
1891 std::max(static_cast<size_t>(0),
1892 str.size() - 1));
1893 if (length) {
1894 *length = max_size;
1896 if (name && bufsize > 0) {
1897 memcpy(name, &str[0], max_size);
1898 name[max_size] = '\0';
1902 return result->success != 0;
1905 void GLES2Implementation::GetActiveUniform(
1906 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1907 GLenum* type, char* name) {
1908 GPU_CLIENT_SINGLE_THREAD_CHECK();
1909 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
1910 << program << ", " << index << ", " << bufsize << ", "
1911 << static_cast<const void*>(length) << ", "
1912 << static_cast<const void*>(size) << ", "
1913 << static_cast<const void*>(type) << ", "
1914 << static_cast<const void*>(name) << ", ");
1915 if (bufsize < 0) {
1916 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
1917 return;
1919 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
1920 bool success = share_group_->program_info_manager()->GetActiveUniform(
1921 this, program, index, bufsize, length, size, type, name);
1922 if (success) {
1923 if (size) {
1924 GPU_CLIENT_LOG(" size: " << *size);
1926 if (type) {
1927 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
1929 if (name) {
1930 GPU_CLIENT_LOG(" name: " << name);
1933 CheckGLError();
1936 void GLES2Implementation::GetAttachedShaders(
1937 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
1938 GPU_CLIENT_SINGLE_THREAD_CHECK();
1939 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
1940 << program << ", " << maxcount << ", "
1941 << static_cast<const void*>(count) << ", "
1942 << static_cast<const void*>(shaders) << ", ");
1943 if (maxcount < 0) {
1944 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
1945 return;
1947 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
1948 typedef cmds::GetAttachedShaders::Result Result;
1949 uint32 size = Result::ComputeSize(maxcount);
1950 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
1951 if (!result) {
1952 return;
1954 result->SetNumResults(0);
1955 helper_->GetAttachedShaders(
1956 program,
1957 transfer_buffer_->GetShmId(),
1958 transfer_buffer_->GetOffset(result),
1959 size);
1960 int32 token = helper_->InsertToken();
1961 WaitForCmd();
1962 if (count) {
1963 *count = result->GetNumResults();
1965 result->CopyResult(shaders);
1966 GPU_CLIENT_LOG_CODE_BLOCK({
1967 for (int32 i = 0; i < result->GetNumResults(); ++i) {
1968 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
1971 transfer_buffer_->FreePendingToken(result, token);
1972 CheckGLError();
1975 void GLES2Implementation::GetShaderPrecisionFormat(
1976 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
1977 GPU_CLIENT_SINGLE_THREAD_CHECK();
1978 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
1979 << GLES2Util::GetStringShaderType(shadertype) << ", "
1980 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
1981 << static_cast<const void*>(range) << ", "
1982 << static_cast<const void*>(precision) << ", ");
1983 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
1984 typedef cmds::GetShaderPrecisionFormat::Result Result;
1985 Result* result = GetResultAs<Result*>();
1986 if (!result) {
1987 return;
1990 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
1991 GLStaticState::ShaderPrecisionMap::iterator i =
1992 static_state_.shader_precisions.find(key);
1993 if (i != static_state_.shader_precisions.end()) {
1994 *result = i->second;
1995 } else {
1996 result->success = false;
1997 helper_->GetShaderPrecisionFormat(
1998 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
1999 WaitForCmd();
2000 if (result->success)
2001 static_state_.shader_precisions[key] = *result;
2004 if (result->success) {
2005 if (range) {
2006 range[0] = result->min_range;
2007 range[1] = result->max_range;
2008 GPU_CLIENT_LOG(" min_range: " << range[0]);
2009 GPU_CLIENT_LOG(" min_range: " << range[1]);
2011 if (precision) {
2012 precision[0] = result->precision;
2013 GPU_CLIENT_LOG(" min_range: " << precision[0]);
2016 CheckGLError();
2019 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
2020 const char* result = NULL;
2021 // Clears the bucket so if the command fails nothing will be in it.
2022 helper_->SetBucketSize(kResultBucketId, 0);
2023 helper_->GetString(name, kResultBucketId);
2024 std::string str;
2025 if (GetBucketAsString(kResultBucketId, &str)) {
2026 // Adds extensions implemented on client side only.
2027 switch (name) {
2028 case GL_EXTENSIONS:
2029 str += std::string(str.empty() ? "" : " ") +
2030 "GL_CHROMIUM_flipy "
2031 "GL_EXT_unpack_subimage "
2032 "GL_CHROMIUM_map_sub";
2033 if (capabilities_.image)
2034 str += " GL_CHROMIUM_image GL_CHROMIUM_gpu_memory_buffer_image";
2035 if (capabilities_.future_sync_points)
2036 str += " GL_CHROMIUM_future_sync_point";
2037 break;
2038 default:
2039 break;
2042 // Because of WebGL the extensions can change. We have to cache each unique
2043 // result since we don't know when the client will stop referring to a
2044 // previous one it queries.
2045 GLStringMap::iterator it = gl_strings_.find(name);
2046 if (it == gl_strings_.end()) {
2047 std::set<std::string> strings;
2048 std::pair<GLStringMap::iterator, bool> insert_result =
2049 gl_strings_.insert(std::make_pair(name, strings));
2050 DCHECK(insert_result.second);
2051 it = insert_result.first;
2053 std::set<std::string>& string_set = it->second;
2054 std::set<std::string>::const_iterator sit = string_set.find(str);
2055 if (sit != string_set.end()) {
2056 result = sit->c_str();
2057 } else {
2058 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2059 string_set.insert(str);
2060 DCHECK(insert_result.second);
2061 result = insert_result.first->c_str();
2064 return reinterpret_cast<const GLubyte*>(result);
2067 const GLubyte* GLES2Implementation::GetString(GLenum name) {
2068 GPU_CLIENT_SINGLE_THREAD_CHECK();
2069 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2070 << GLES2Util::GetStringStringType(name) << ")");
2071 TRACE_EVENT0("gpu", "GLES2::GetString");
2072 const GLubyte* result = GetStringHelper(name);
2073 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
2074 CheckGLError();
2075 return result;
2078 void GLES2Implementation::GetUniformfv(
2079 GLuint program, GLint location, GLfloat* params) {
2080 GPU_CLIENT_SINGLE_THREAD_CHECK();
2081 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2082 << program << ", " << location << ", "
2083 << static_cast<const void*>(params) << ")");
2084 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2085 typedef cmds::GetUniformfv::Result Result;
2086 Result* result = GetResultAs<Result*>();
2087 if (!result) {
2088 return;
2090 result->SetNumResults(0);
2091 helper_->GetUniformfv(
2092 program, location, GetResultShmId(), GetResultShmOffset());
2093 WaitForCmd();
2094 result->CopyResult(params);
2095 GPU_CLIENT_LOG_CODE_BLOCK({
2096 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2097 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2100 CheckGLError();
2103 void GLES2Implementation::GetUniformiv(
2104 GLuint program, GLint location, GLint* params) {
2105 GPU_CLIENT_SINGLE_THREAD_CHECK();
2106 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2107 << program << ", " << location << ", "
2108 << static_cast<const void*>(params) << ")");
2109 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2110 typedef cmds::GetUniformiv::Result Result;
2111 Result* result = GetResultAs<Result*>();
2112 if (!result) {
2113 return;
2115 result->SetNumResults(0);
2116 helper_->GetUniformiv(
2117 program, location, GetResultShmId(), GetResultShmOffset());
2118 WaitForCmd();
2119 GetResultAs<cmds::GetUniformfv::Result*>()->CopyResult(params);
2120 GPU_CLIENT_LOG_CODE_BLOCK({
2121 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2122 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2125 CheckGLError();
2128 void GLES2Implementation::ReadPixels(
2129 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
2130 GLenum type, void* pixels) {
2131 GPU_CLIENT_SINGLE_THREAD_CHECK();
2132 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2133 << xoffset << ", " << yoffset << ", "
2134 << width << ", " << height << ", "
2135 << GLES2Util::GetStringReadPixelFormat(format) << ", "
2136 << GLES2Util::GetStringPixelType(type) << ", "
2137 << static_cast<const void*>(pixels) << ")");
2138 if (width < 0 || height < 0) {
2139 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
2140 return;
2142 if (width == 0 || height == 0) {
2143 return;
2146 // glReadPixel pads the size of each row of pixels by an amount specified by
2147 // glPixelStorei. So, we have to take that into account both in the fact that
2148 // the pixels returned from the ReadPixel command will include that padding
2149 // and that when we copy the results to the user's buffer we need to not
2150 // write those padding bytes but leave them as they are.
2152 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2153 typedef cmds::ReadPixels::Result Result;
2155 int8* dest = reinterpret_cast<int8*>(pixels);
2156 uint32 temp_size;
2157 uint32 unpadded_row_size;
2158 uint32 padded_row_size;
2159 if (!GLES2Util::ComputeImageDataSizes(
2160 width, 2, format, type, pack_alignment_, &temp_size, &unpadded_row_size,
2161 &padded_row_size)) {
2162 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
2163 return;
2166 if (bound_pixel_pack_transfer_buffer_id_) {
2167 GLuint offset = ToGLuint(pixels);
2168 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2169 bound_pixel_pack_transfer_buffer_id_,
2170 "glReadPixels", offset, padded_row_size * height);
2171 if (buffer && buffer->shm_id() != -1) {
2172 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
2173 buffer->shm_id(), buffer->shm_offset(),
2174 0, 0, true);
2175 CheckGLError();
2177 return;
2180 if (!pixels) {
2181 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
2182 return;
2185 // Transfer by rows.
2186 // The max rows we can transfer.
2187 while (height) {
2188 GLsizei desired_size = padded_row_size * height - 1 + unpadded_row_size;
2189 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
2190 if (!buffer.valid()) {
2191 return;
2193 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2194 padded_row_size, unpadded_row_size, buffer.size());
2195 num_rows = std::min(num_rows, height);
2196 // NOTE: We must look up the address of the result area AFTER allocation
2197 // of the transfer buffer since the transfer buffer may be reallocated.
2198 Result* result = GetResultAs<Result*>();
2199 if (!result) {
2200 return;
2202 *result = 0; // mark as failed.
2203 helper_->ReadPixels(
2204 xoffset, yoffset, width, num_rows, format, type,
2205 buffer.shm_id(), buffer.offset(),
2206 GetResultShmId(), GetResultShmOffset(),
2207 false);
2208 WaitForCmd();
2209 if (*result != 0) {
2210 // when doing a y-flip we have to iterate through top-to-bottom chunks
2211 // of the dst. The service side handles reversing the rows within a
2212 // chunk.
2213 int8* rows_dst;
2214 if (pack_reverse_row_order_) {
2215 rows_dst = dest + (height - num_rows) * padded_row_size;
2216 } else {
2217 rows_dst = dest;
2219 // We have to copy 1 row at a time to avoid writing pad bytes.
2220 const int8* src = static_cast<const int8*>(buffer.address());
2221 for (GLint yy = 0; yy < num_rows; ++yy) {
2222 memcpy(rows_dst, src, unpadded_row_size);
2223 rows_dst += padded_row_size;
2224 src += padded_row_size;
2226 if (!pack_reverse_row_order_) {
2227 dest = rows_dst;
2230 // If it was not marked as successful exit.
2231 if (*result == 0) {
2232 return;
2234 yoffset += num_rows;
2235 height -= num_rows;
2237 CheckGLError();
2240 void GLES2Implementation::ActiveTexture(GLenum texture) {
2241 GPU_CLIENT_SINGLE_THREAD_CHECK();
2242 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2243 << GLES2Util::GetStringEnum(texture) << ")");
2244 GLuint texture_index = texture - GL_TEXTURE0;
2245 if (texture_index >=
2246 static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
2247 SetGLErrorInvalidEnum(
2248 "glActiveTexture", texture, "texture");
2249 return;
2252 active_texture_unit_ = texture_index;
2253 helper_->ActiveTexture(texture);
2254 CheckGLError();
2257 void GLES2Implementation::GenBuffersHelper(
2258 GLsizei /* n */, const GLuint* /* buffers */) {
2261 void GLES2Implementation::GenFramebuffersHelper(
2262 GLsizei /* n */, const GLuint* /* framebuffers */) {
2265 void GLES2Implementation::GenRenderbuffersHelper(
2266 GLsizei /* n */, const GLuint* /* renderbuffers */) {
2269 void GLES2Implementation::GenTexturesHelper(
2270 GLsizei /* n */, const GLuint* /* textures */) {
2273 void GLES2Implementation::GenVertexArraysOESHelper(
2274 GLsizei n, const GLuint* arrays) {
2275 vertex_array_object_manager_->GenVertexArrays(n, arrays);
2278 void GLES2Implementation::GenQueriesEXTHelper(
2279 GLsizei /* n */, const GLuint* /* queries */) {
2282 void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
2283 GLsizei /* n */,
2284 const GLuint* /* valuebuffers */) {
2287 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
2288 // generates a new resource. On newer versions of OpenGL they don't. The code
2289 // related to binding below will need to change if we switch to the new OpenGL
2290 // model. Specifically it assumes a bind will succeed which is always true in
2291 // the old model but possibly not true in the new model if another context has
2292 // deleted the resource.
2294 bool GLES2Implementation::BindBufferHelper(
2295 GLenum target, GLuint buffer_id) {
2296 // TODO(gman): See note #1 above.
2297 bool changed = false;
2298 switch (target) {
2299 case GL_ARRAY_BUFFER:
2300 if (bound_array_buffer_id_ != buffer_id) {
2301 bound_array_buffer_id_ = buffer_id;
2302 changed = true;
2304 break;
2305 case GL_ELEMENT_ARRAY_BUFFER:
2306 changed = vertex_array_object_manager_->BindElementArray(buffer_id);
2307 break;
2308 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
2309 bound_pixel_pack_transfer_buffer_id_ = buffer_id;
2310 break;
2311 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
2312 bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
2313 break;
2314 default:
2315 changed = true;
2316 break;
2318 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2319 // used even though it's marked it as used here.
2320 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(buffer_id);
2321 return changed;
2324 bool GLES2Implementation::BindFramebufferHelper(
2325 GLenum target, GLuint framebuffer) {
2326 // TODO(gman): See note #1 above.
2327 bool changed = false;
2328 switch (target) {
2329 case GL_FRAMEBUFFER:
2330 if (bound_framebuffer_ != framebuffer ||
2331 bound_read_framebuffer_ != framebuffer) {
2332 bound_framebuffer_ = framebuffer;
2333 bound_read_framebuffer_ = framebuffer;
2334 changed = true;
2336 break;
2337 case GL_READ_FRAMEBUFFER:
2338 if (!IsChromiumFramebufferMultisampleAvailable()) {
2339 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2340 return false;
2342 if (bound_read_framebuffer_ != framebuffer) {
2343 bound_read_framebuffer_ = framebuffer;
2344 changed = true;
2346 break;
2347 case GL_DRAW_FRAMEBUFFER:
2348 if (!IsChromiumFramebufferMultisampleAvailable()) {
2349 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2350 return false;
2352 if (bound_framebuffer_ != framebuffer) {
2353 bound_framebuffer_ = framebuffer;
2354 changed = true;
2356 break;
2357 default:
2358 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2359 return false;
2361 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(framebuffer);
2362 return changed;
2365 bool GLES2Implementation::BindRenderbufferHelper(
2366 GLenum target, GLuint renderbuffer) {
2367 // TODO(gman): See note #1 above.
2368 bool changed = false;
2369 switch (target) {
2370 case GL_RENDERBUFFER:
2371 if (bound_renderbuffer_ != renderbuffer) {
2372 bound_renderbuffer_ = renderbuffer;
2373 changed = true;
2375 break;
2376 default:
2377 changed = true;
2378 break;
2380 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2381 // used even though it's marked it as used here.
2382 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(renderbuffer);
2383 return changed;
2386 bool GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
2387 // TODO(gman): See note #1 above.
2388 // TODO(gman): Change this to false once we figure out why it's failing
2389 // on daisy.
2390 bool changed = true;
2391 TextureUnit& unit = texture_units_[active_texture_unit_];
2392 switch (target) {
2393 case GL_TEXTURE_2D:
2394 if (unit.bound_texture_2d != texture) {
2395 unit.bound_texture_2d = texture;
2396 changed = true;
2398 break;
2399 case GL_TEXTURE_CUBE_MAP:
2400 if (unit.bound_texture_cube_map != texture) {
2401 unit.bound_texture_cube_map = texture;
2402 changed = true;
2404 break;
2405 case GL_TEXTURE_EXTERNAL_OES:
2406 if (unit.bound_texture_external_oes != texture) {
2407 unit.bound_texture_external_oes = texture;
2408 changed = true;
2410 break;
2411 default:
2412 changed = true;
2413 break;
2415 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2416 // used. even though it's marked it as used here.
2417 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(texture);
2418 return changed;
2421 bool GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
2422 // TODO(gman): See note #1 above.
2423 bool changed = false;
2424 if (!vertex_array_object_manager_->BindVertexArray(array, &changed)) {
2425 SetGLError(
2426 GL_INVALID_OPERATION, "glBindVertexArrayOES",
2427 "id was not generated with glGenVertexArrayOES");
2429 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
2430 // because unlike other resources VertexArrayObject ids must
2431 // be generated by GenVertexArrays. A random id to Bind will not
2432 // generate a new object.
2433 return changed;
2436 bool GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
2437 GLuint valuebuffer) {
2438 bool changed = false;
2439 switch (target) {
2440 case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
2441 if (bound_valuebuffer_ != valuebuffer) {
2442 bound_valuebuffer_ = valuebuffer;
2443 changed = true;
2445 break;
2446 default:
2447 changed = true;
2448 break;
2450 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2451 // used even though it's marked it as used here.
2452 GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(valuebuffer);
2453 return changed;
2456 bool GLES2Implementation::UseProgramHelper(GLuint program) {
2457 bool changed = false;
2458 if (current_program_ != program) {
2459 current_program_ = program;
2460 changed = true;
2462 return changed;
2465 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
2466 return vertex_array_object_manager_->IsReservedId(id);
2469 void GLES2Implementation::DeleteBuffersHelper(
2470 GLsizei n, const GLuint* buffers) {
2471 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
2472 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
2473 SetGLError(
2474 GL_INVALID_VALUE,
2475 "glDeleteBuffers", "id not created by this context.");
2476 return;
2478 for (GLsizei ii = 0; ii < n; ++ii) {
2479 if (buffers[ii] == bound_array_buffer_id_) {
2480 bound_array_buffer_id_ = 0;
2482 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
2484 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
2485 if (buffer)
2486 RemoveTransferBuffer(buffer);
2488 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
2489 bound_pixel_unpack_transfer_buffer_id_ = 0;
2494 void GLES2Implementation::DeleteBuffersStub(
2495 GLsizei n, const GLuint* buffers) {
2496 helper_->DeleteBuffersImmediate(n, buffers);
2500 void GLES2Implementation::DeleteFramebuffersHelper(
2501 GLsizei n, const GLuint* framebuffers) {
2502 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
2503 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
2504 SetGLError(
2505 GL_INVALID_VALUE,
2506 "glDeleteFramebuffers", "id not created by this context.");
2507 return;
2509 for (GLsizei ii = 0; ii < n; ++ii) {
2510 if (framebuffers[ii] == bound_framebuffer_) {
2511 bound_framebuffer_ = 0;
2513 if (framebuffers[ii] == bound_read_framebuffer_) {
2514 bound_read_framebuffer_ = 0;
2519 void GLES2Implementation::DeleteFramebuffersStub(
2520 GLsizei n, const GLuint* framebuffers) {
2521 helper_->DeleteFramebuffersImmediate(n, framebuffers);
2524 void GLES2Implementation::DeleteRenderbuffersHelper(
2525 GLsizei n, const GLuint* renderbuffers) {
2526 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
2527 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
2528 SetGLError(
2529 GL_INVALID_VALUE,
2530 "glDeleteRenderbuffers", "id not created by this context.");
2531 return;
2533 for (GLsizei ii = 0; ii < n; ++ii) {
2534 if (renderbuffers[ii] == bound_renderbuffer_) {
2535 bound_renderbuffer_ = 0;
2540 void GLES2Implementation::DeleteRenderbuffersStub(
2541 GLsizei n, const GLuint* renderbuffers) {
2542 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
2545 void GLES2Implementation::DeleteTexturesHelper(
2546 GLsizei n, const GLuint* textures) {
2547 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
2548 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
2549 SetGLError(
2550 GL_INVALID_VALUE,
2551 "glDeleteTextures", "id not created by this context.");
2552 return;
2554 for (GLsizei ii = 0; ii < n; ++ii) {
2555 for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
2556 ++tt) {
2557 TextureUnit& unit = texture_units_[tt];
2558 if (textures[ii] == unit.bound_texture_2d) {
2559 unit.bound_texture_2d = 0;
2561 if (textures[ii] == unit.bound_texture_cube_map) {
2562 unit.bound_texture_cube_map = 0;
2564 if (textures[ii] == unit.bound_texture_external_oes) {
2565 unit.bound_texture_external_oes = 0;
2571 void GLES2Implementation::DeleteTexturesStub(GLsizei n,
2572 const GLuint* textures) {
2573 helper_->DeleteTexturesImmediate(n, textures);
2576 void GLES2Implementation::DeleteVertexArraysOESHelper(
2577 GLsizei n, const GLuint* arrays) {
2578 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
2579 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
2580 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
2581 SetGLError(
2582 GL_INVALID_VALUE,
2583 "glDeleteVertexArraysOES", "id not created by this context.");
2584 return;
2588 void GLES2Implementation::DeleteVertexArraysOESStub(
2589 GLsizei n, const GLuint* arrays) {
2590 helper_->DeleteVertexArraysOESImmediate(n, arrays);
2593 void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
2594 GLsizei n,
2595 const GLuint* valuebuffers) {
2596 if (!GetIdHandler(id_namespaces::kValuebuffers)
2597 ->FreeIds(this, n, valuebuffers,
2598 &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
2599 SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
2600 "id not created by this context.");
2601 return;
2603 for (GLsizei ii = 0; ii < n; ++ii) {
2604 if (valuebuffers[ii] == bound_valuebuffer_) {
2605 bound_valuebuffer_ = 0;
2610 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
2611 GLsizei n,
2612 const GLuint* valuebuffers) {
2613 helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
2616 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
2617 GPU_CLIENT_SINGLE_THREAD_CHECK();
2618 GPU_CLIENT_LOG(
2619 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
2620 vertex_array_object_manager_->SetAttribEnable(index, false);
2621 helper_->DisableVertexAttribArray(index);
2622 CheckGLError();
2625 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
2626 GPU_CLIENT_SINGLE_THREAD_CHECK();
2627 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
2628 << index << ")");
2629 vertex_array_object_manager_->SetAttribEnable(index, true);
2630 helper_->EnableVertexAttribArray(index);
2631 CheckGLError();
2634 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
2635 GPU_CLIENT_SINGLE_THREAD_CHECK();
2636 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
2637 << GLES2Util::GetStringDrawMode(mode) << ", "
2638 << first << ", " << count << ")");
2639 if (count < 0) {
2640 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
2641 return;
2643 bool simulated = false;
2644 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
2645 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
2646 return;
2648 helper_->DrawArrays(mode, first, count);
2649 RestoreArrayBuffer(simulated);
2650 CheckGLError();
2653 void GLES2Implementation::GetVertexAttribfv(
2654 GLuint index, GLenum pname, GLfloat* params) {
2655 GPU_CLIENT_SINGLE_THREAD_CHECK();
2656 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
2657 << index << ", "
2658 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2659 << static_cast<const void*>(params) << ")");
2660 uint32 value = 0;
2661 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2662 *params = static_cast<float>(value);
2663 return;
2665 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
2666 typedef cmds::GetVertexAttribfv::Result Result;
2667 Result* result = GetResultAs<Result*>();
2668 if (!result) {
2669 return;
2671 result->SetNumResults(0);
2672 helper_->GetVertexAttribfv(
2673 index, pname, GetResultShmId(), GetResultShmOffset());
2674 WaitForCmd();
2675 result->CopyResult(params);
2676 GPU_CLIENT_LOG_CODE_BLOCK({
2677 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2678 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2681 CheckGLError();
2684 void GLES2Implementation::GetVertexAttribiv(
2685 GLuint index, GLenum pname, GLint* params) {
2686 GPU_CLIENT_SINGLE_THREAD_CHECK();
2687 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
2688 << index << ", "
2689 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2690 << static_cast<const void*>(params) << ")");
2691 uint32 value = 0;
2692 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2693 *params = value;
2694 return;
2696 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
2697 typedef cmds::GetVertexAttribiv::Result Result;
2698 Result* result = GetResultAs<Result*>();
2699 if (!result) {
2700 return;
2702 result->SetNumResults(0);
2703 helper_->GetVertexAttribiv(
2704 index, pname, GetResultShmId(), GetResultShmOffset());
2705 WaitForCmd();
2706 result->CopyResult(params);
2707 GPU_CLIENT_LOG_CODE_BLOCK({
2708 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2709 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2712 CheckGLError();
2715 void GLES2Implementation::Swap() {
2716 SwapBuffers();
2719 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
2720 PostSubBufferCHROMIUM(
2721 sub_buffer.x(), sub_buffer.y(), sub_buffer.width(), sub_buffer.height());
2724 static GLenum GetGLESOverlayTransform(gfx::OverlayTransform plane_transform) {
2725 switch (plane_transform) {
2726 case gfx::OVERLAY_TRANSFORM_INVALID:
2727 break;
2728 case gfx::OVERLAY_TRANSFORM_NONE:
2729 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
2730 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
2731 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM;
2732 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
2733 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM;
2734 case gfx::OVERLAY_TRANSFORM_ROTATE_90:
2735 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM;
2736 case gfx::OVERLAY_TRANSFORM_ROTATE_180:
2737 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM;
2738 case gfx::OVERLAY_TRANSFORM_ROTATE_270:
2739 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM;
2741 NOTREACHED();
2742 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
2745 void GLES2Implementation::ScheduleOverlayPlane(
2746 int plane_z_order,
2747 gfx::OverlayTransform plane_transform,
2748 unsigned overlay_texture_id,
2749 const gfx::Rect& display_bounds,
2750 const gfx::RectF& uv_rect) {
2751 ScheduleOverlayPlaneCHROMIUM(plane_z_order,
2752 GetGLESOverlayTransform(plane_transform),
2753 overlay_texture_id,
2754 display_bounds.x(),
2755 display_bounds.y(),
2756 display_bounds.width(),
2757 display_bounds.height(),
2758 uv_rect.x(),
2759 uv_rect.y(),
2760 uv_rect.width(),
2761 uv_rect.height());
2764 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
2765 const char* feature) {
2766 GPU_CLIENT_SINGLE_THREAD_CHECK();
2767 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
2768 << feature << ")");
2769 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
2770 typedef cmds::EnableFeatureCHROMIUM::Result Result;
2771 Result* result = GetResultAs<Result*>();
2772 if (!result) {
2773 return false;
2775 *result = 0;
2776 SetBucketAsCString(kResultBucketId, feature);
2777 helper_->EnableFeatureCHROMIUM(
2778 kResultBucketId, GetResultShmId(), GetResultShmOffset());
2779 WaitForCmd();
2780 helper_->SetBucketSize(kResultBucketId, 0);
2781 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
2782 return *result != 0;
2785 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
2786 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
2787 GPU_CLIENT_SINGLE_THREAD_CHECK();
2788 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
2789 << target << ", " << offset << ", " << size << ", "
2790 << GLES2Util::GetStringEnum(access) << ")");
2791 // NOTE: target is NOT checked because the service will check it
2792 // and we don't know what targets are valid.
2793 if (access != GL_WRITE_ONLY) {
2794 SetGLErrorInvalidEnum(
2795 "glMapBufferSubDataCHROMIUM", access, "access");
2796 return NULL;
2798 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
2799 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
2800 return NULL;
2803 int32 shm_id;
2804 unsigned int shm_offset;
2805 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2806 if (!mem) {
2807 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
2808 return NULL;
2811 std::pair<MappedBufferMap::iterator, bool> result =
2812 mapped_buffers_.insert(std::make_pair(
2813 mem,
2814 MappedBuffer(
2815 access, shm_id, mem, shm_offset, target, offset, size)));
2816 DCHECK(result.second);
2817 GPU_CLIENT_LOG(" returned " << mem);
2818 return mem;
2821 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
2822 GPU_CLIENT_SINGLE_THREAD_CHECK();
2823 GPU_CLIENT_LOG(
2824 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
2825 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
2826 if (it == mapped_buffers_.end()) {
2827 SetGLError(
2828 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
2829 return;
2831 const MappedBuffer& mb = it->second;
2832 helper_->BufferSubData(
2833 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
2834 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
2835 mapped_buffers_.erase(it);
2836 CheckGLError();
2839 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
2840 GLenum target,
2841 GLint level,
2842 GLint xoffset,
2843 GLint yoffset,
2844 GLsizei width,
2845 GLsizei height,
2846 GLenum format,
2847 GLenum type,
2848 GLenum access) {
2849 GPU_CLIENT_SINGLE_THREAD_CHECK();
2850 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
2851 << target << ", " << level << ", "
2852 << xoffset << ", " << yoffset << ", "
2853 << width << ", " << height << ", "
2854 << GLES2Util::GetStringTextureFormat(format) << ", "
2855 << GLES2Util::GetStringPixelType(type) << ", "
2856 << GLES2Util::GetStringEnum(access) << ")");
2857 if (access != GL_WRITE_ONLY) {
2858 SetGLErrorInvalidEnum(
2859 "glMapTexSubImage2DCHROMIUM", access, "access");
2860 return NULL;
2862 // NOTE: target is NOT checked because the service will check it
2863 // and we don't know what targets are valid.
2864 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
2865 SetGLError(
2866 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
2867 return NULL;
2869 uint32 size;
2870 if (!GLES2Util::ComputeImageDataSizes(
2871 width, height, format, type, unpack_alignment_, &size, NULL, NULL)) {
2872 SetGLError(
2873 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
2874 return NULL;
2876 int32 shm_id;
2877 unsigned int shm_offset;
2878 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2879 if (!mem) {
2880 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
2881 return NULL;
2884 std::pair<MappedTextureMap::iterator, bool> result =
2885 mapped_textures_.insert(std::make_pair(
2886 mem,
2887 MappedTexture(
2888 access, shm_id, mem, shm_offset,
2889 target, level, xoffset, yoffset, width, height, format, type)));
2890 DCHECK(result.second);
2891 GPU_CLIENT_LOG(" returned " << mem);
2892 return mem;
2895 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
2896 GPU_CLIENT_SINGLE_THREAD_CHECK();
2897 GPU_CLIENT_LOG(
2898 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
2899 MappedTextureMap::iterator it = mapped_textures_.find(mem);
2900 if (it == mapped_textures_.end()) {
2901 SetGLError(
2902 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
2903 return;
2905 const MappedTexture& mt = it->second;
2906 helper_->TexSubImage2D(
2907 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
2908 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
2909 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
2910 mapped_textures_.erase(it);
2911 CheckGLError();
2914 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
2915 float scale_factor) {
2916 GPU_CLIENT_SINGLE_THREAD_CHECK();
2917 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
2918 << width << ", " << height << ", " << scale_factor << ")");
2919 helper_->ResizeCHROMIUM(width, height, scale_factor);
2920 CheckGLError();
2923 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
2924 GPU_CLIENT_SINGLE_THREAD_CHECK();
2925 GPU_CLIENT_LOG("[" << GetLogPrefix()
2926 << "] glGetRequestableExtensionsCHROMIUM()");
2927 TRACE_EVENT0("gpu",
2928 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
2929 const char* result = NULL;
2930 // Clear the bucket so if the command fails nothing will be in it.
2931 helper_->SetBucketSize(kResultBucketId, 0);
2932 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
2933 std::string str;
2934 if (GetBucketAsString(kResultBucketId, &str)) {
2935 // The set of requestable extensions shrinks as we enable
2936 // them. Because we don't know when the client will stop referring
2937 // to a previous one it queries (see GetString) we need to cache
2938 // the unique results.
2939 std::set<std::string>::const_iterator sit =
2940 requestable_extensions_set_.find(str);
2941 if (sit != requestable_extensions_set_.end()) {
2942 result = sit->c_str();
2943 } else {
2944 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2945 requestable_extensions_set_.insert(str);
2946 DCHECK(insert_result.second);
2947 result = insert_result.first->c_str();
2950 GPU_CLIENT_LOG(" returned " << result);
2951 return reinterpret_cast<const GLchar*>(result);
2954 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
2955 // with VirtualGL contexts.
2956 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
2957 GPU_CLIENT_SINGLE_THREAD_CHECK();
2958 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
2959 << extension << ")");
2960 SetBucketAsCString(kResultBucketId, extension);
2961 helper_->RequestExtensionCHROMIUM(kResultBucketId);
2962 helper_->SetBucketSize(kResultBucketId, 0);
2964 struct ExtensionCheck {
2965 const char* extension;
2966 ExtensionStatus* status;
2968 const ExtensionCheck checks[] = {
2970 "GL_ANGLE_pack_reverse_row_order",
2971 &angle_pack_reverse_row_order_status_,
2974 "GL_CHROMIUM_framebuffer_multisample",
2975 &chromium_framebuffer_multisample_,
2978 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
2979 for (size_t ii = 0; ii < kNumChecks; ++ii) {
2980 const ExtensionCheck& check = checks[ii];
2981 if (*check.status == kUnavailableExtensionStatus &&
2982 !strcmp(extension, check.extension)) {
2983 *check.status = kUnknownExtensionStatus;
2988 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
2989 GPU_CLIENT_SINGLE_THREAD_CHECK();
2990 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
2991 // Wait if this would add too many rate limit tokens.
2992 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
2993 helper_->WaitForToken(rate_limit_tokens_.front());
2994 rate_limit_tokens_.pop();
2996 rate_limit_tokens_.push(helper_->InsertToken());
2999 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3000 GLuint program, std::vector<int8>* result) {
3001 DCHECK(result);
3002 // Clear the bucket so if the command fails nothing will be in it.
3003 helper_->SetBucketSize(kResultBucketId, 0);
3004 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
3005 GetBucketContents(kResultBucketId, result);
3008 void GLES2Implementation::GetProgramInfoCHROMIUM(
3009 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3010 GPU_CLIENT_SINGLE_THREAD_CHECK();
3011 if (bufsize < 0) {
3012 SetGLError(
3013 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3014 return;
3016 if (size == NULL) {
3017 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
3018 return;
3020 // Make sure they've set size to 0 else the value will be undefined on
3021 // lost context.
3022 DCHECK_EQ(0, *size);
3023 std::vector<int8> result;
3024 GetProgramInfoCHROMIUMHelper(program, &result);
3025 if (result.empty()) {
3026 return;
3028 *size = result.size();
3029 if (!info) {
3030 return;
3032 if (static_cast<size_t>(bufsize) < result.size()) {
3033 SetGLError(GL_INVALID_OPERATION,
3034 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3035 return;
3037 memcpy(info, &result[0], result.size());
3040 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
3041 GPU_CLIENT_SINGLE_THREAD_CHECK();
3042 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
3043 << texture << ")");
3044 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
3045 helper_->CommandBufferHelper::Flush();
3046 return gpu_control_->CreateStreamTexture(texture);
3049 void GLES2Implementation::PostSubBufferCHROMIUM(
3050 GLint x, GLint y, GLint width, GLint height) {
3051 GPU_CLIENT_SINGLE_THREAD_CHECK();
3052 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
3053 << x << ", " << y << ", " << width << ", " << height << ")");
3054 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
3055 "width", width, "height", height);
3057 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
3058 swap_buffers_tokens_.push(helper_->InsertToken());
3059 helper_->PostSubBufferCHROMIUM(x, y, width, height);
3060 helper_->CommandBufferHelper::Flush();
3061 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
3062 helper_->WaitForToken(swap_buffers_tokens_.front());
3063 swap_buffers_tokens_.pop();
3067 void GLES2Implementation::DeleteQueriesEXTHelper(
3068 GLsizei n, const GLuint* queries) {
3069 for (GLsizei ii = 0; ii < n; ++ii) {
3070 query_tracker_->RemoveQuery(queries[ii]);
3071 query_id_allocator_->FreeID(queries[ii]);
3074 helper_->DeleteQueriesEXTImmediate(n, queries);
3077 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
3078 GPU_CLIENT_SINGLE_THREAD_CHECK();
3079 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
3081 // TODO(gman): To be spec compliant IDs from other contexts sharing
3082 // resources need to return true here even though you can't share
3083 // queries across contexts?
3084 return query_tracker_->GetQuery(id) != NULL;
3087 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
3088 GPU_CLIENT_SINGLE_THREAD_CHECK();
3089 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
3090 << GLES2Util::GetStringQueryTarget(target)
3091 << ", " << id << ")");
3093 // if any outstanding queries INV_OP
3094 QueryMap::iterator it = current_queries_.find(target);
3095 if (it != current_queries_.end()) {
3096 SetGLError(
3097 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
3098 return;
3101 // id = 0 INV_OP
3102 if (id == 0) {
3103 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
3104 return;
3107 // if not GENned INV_OPERATION
3108 if (!query_id_allocator_->InUse(id)) {
3109 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "invalid id");
3110 return;
3113 // if id does not have an object
3114 QueryTracker::Query* query = query_tracker_->GetQuery(id);
3115 if (!query) {
3116 query = query_tracker_->CreateQuery(id, target);
3117 if (!query) {
3118 SetGLError(GL_OUT_OF_MEMORY,
3119 "glBeginQueryEXT",
3120 "transfer buffer allocation failed");
3121 return;
3123 } else if (query->target() != target) {
3124 SetGLError(
3125 GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
3126 return;
3129 current_queries_[target] = query;
3131 query->Begin(this);
3132 CheckGLError();
3135 void GLES2Implementation::EndQueryEXT(GLenum target) {
3136 GPU_CLIENT_SINGLE_THREAD_CHECK();
3137 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
3138 << GLES2Util::GetStringQueryTarget(target) << ")");
3139 // Don't do anything if the context is lost.
3140 if (helper_->IsContextLost()) {
3141 return;
3144 QueryMap::iterator it = current_queries_.find(target);
3145 if (it == current_queries_.end()) {
3146 SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
3147 return;
3150 QueryTracker::Query* query = it->second;
3151 query->End(this);
3152 current_queries_.erase(it);
3153 CheckGLError();
3156 void GLES2Implementation::GetQueryivEXT(
3157 GLenum target, GLenum pname, GLint* params) {
3158 GPU_CLIENT_SINGLE_THREAD_CHECK();
3159 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
3160 << GLES2Util::GetStringQueryTarget(target) << ", "
3161 << GLES2Util::GetStringQueryParameter(pname) << ", "
3162 << static_cast<const void*>(params) << ")");
3164 if (pname != GL_CURRENT_QUERY_EXT) {
3165 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
3166 return;
3168 QueryMap::iterator it = current_queries_.find(target);
3169 if (it != current_queries_.end()) {
3170 QueryTracker::Query* query = it->second;
3171 *params = query->id();
3172 } else {
3173 *params = 0;
3175 GPU_CLIENT_LOG(" " << *params);
3176 CheckGLError();
3179 void GLES2Implementation::GetQueryObjectuivEXT(
3180 GLuint id, GLenum pname, GLuint* params) {
3181 GPU_CLIENT_SINGLE_THREAD_CHECK();
3182 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
3183 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
3184 << static_cast<const void*>(params) << ")");
3186 QueryTracker::Query* query = query_tracker_->GetQuery(id);
3187 if (!query) {
3188 SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
3189 return;
3192 QueryMap::iterator it = current_queries_.find(query->target());
3193 if (it != current_queries_.end()) {
3194 SetGLError(
3195 GL_INVALID_OPERATION,
3196 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
3197 return;
3200 if (query->NeverUsed()) {
3201 SetGLError(
3202 GL_INVALID_OPERATION,
3203 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
3204 return;
3207 switch (pname) {
3208 case GL_QUERY_RESULT_EXT:
3209 if (!query->CheckResultsAvailable(helper_)) {
3210 helper_->WaitForToken(query->token());
3211 if (!query->CheckResultsAvailable(helper_)) {
3212 FinishHelper();
3213 CHECK(query->CheckResultsAvailable(helper_));
3216 *params = query->GetResult();
3217 break;
3218 case GL_QUERY_RESULT_AVAILABLE_EXT:
3219 *params = query->CheckResultsAvailable(helper_);
3220 break;
3221 default:
3222 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
3223 break;
3225 GPU_CLIENT_LOG(" " << *params);
3226 CheckGLError();
3229 void GLES2Implementation::DrawArraysInstancedANGLE(
3230 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
3231 GPU_CLIENT_SINGLE_THREAD_CHECK();
3232 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
3233 << GLES2Util::GetStringDrawMode(mode) << ", "
3234 << first << ", " << count << ", " << primcount << ")");
3235 if (count < 0) {
3236 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
3237 return;
3239 if (primcount < 0) {
3240 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
3241 return;
3243 if (primcount == 0) {
3244 return;
3246 bool simulated = false;
3247 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
3248 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
3249 &simulated)) {
3250 return;
3252 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
3253 RestoreArrayBuffer(simulated);
3254 CheckGLError();
3257 void GLES2Implementation::DrawElementsInstancedANGLE(
3258 GLenum mode, GLsizei count, GLenum type, const void* indices,
3259 GLsizei primcount) {
3260 GPU_CLIENT_SINGLE_THREAD_CHECK();
3261 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
3262 << GLES2Util::GetStringDrawMode(mode) << ", "
3263 << count << ", "
3264 << GLES2Util::GetStringIndexType(type) << ", "
3265 << static_cast<const void*>(indices) << ", "
3266 << primcount << ")");
3267 if (count < 0) {
3268 SetGLError(GL_INVALID_VALUE,
3269 "glDrawElementsInstancedANGLE", "count less than 0.");
3270 return;
3272 if (count == 0) {
3273 return;
3275 if (primcount < 0) {
3276 SetGLError(GL_INVALID_VALUE,
3277 "glDrawElementsInstancedANGLE", "primcount < 0");
3278 return;
3280 if (primcount == 0) {
3281 return;
3283 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
3284 !ValidateOffset("glDrawElementsInstancedANGLE",
3285 reinterpret_cast<GLintptr>(indices))) {
3286 return;
3288 GLuint offset = 0;
3289 bool simulated = false;
3290 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
3291 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
3292 indices, &offset, &simulated)) {
3293 return;
3295 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
3296 RestoreElementAndArrayBuffers(simulated);
3297 CheckGLError();
3300 void GLES2Implementation::GenMailboxCHROMIUM(
3301 GLbyte* mailbox) {
3302 GPU_CLIENT_SINGLE_THREAD_CHECK();
3303 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
3304 << static_cast<const void*>(mailbox) << ")");
3305 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
3307 gpu::Mailbox result = gpu::Mailbox::Generate();
3308 memcpy(mailbox, result.name, sizeof(result.name));
3311 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target,
3312 const GLbyte* data) {
3313 GPU_CLIENT_SINGLE_THREAD_CHECK();
3314 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
3315 << static_cast<const void*>(data) << ")");
3316 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
3317 DCHECK(mailbox.Verify()) << "ProduceTextureCHROMIUM was passed a "
3318 "mailbox that was not generated by "
3319 "GenMailboxCHROMIUM.";
3320 helper_->ProduceTextureCHROMIUMImmediate(target, data);
3321 CheckGLError();
3324 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
3325 GLuint texture, GLenum target, const GLbyte* data) {
3326 GPU_CLIENT_SINGLE_THREAD_CHECK();
3327 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
3328 << static_cast<const void*>(data) << ")");
3329 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
3330 DCHECK(mailbox.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
3331 "mailbox that was not generated by "
3332 "GenMailboxCHROMIUM.";
3333 helper_->ProduceTextureDirectCHROMIUMImmediate(texture, target, data);
3334 CheckGLError();
3337 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target,
3338 const GLbyte* data) {
3339 GPU_CLIENT_SINGLE_THREAD_CHECK();
3340 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
3341 << static_cast<const void*>(data) << ")");
3342 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
3343 DCHECK(mailbox.Verify()) << "ConsumeTextureCHROMIUM was passed a "
3344 "mailbox that was not generated by "
3345 "GenMailboxCHROMIUM.";
3346 helper_->ConsumeTextureCHROMIUMImmediate(target, data);
3347 CheckGLError();
3350 GLuint GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
3351 GLenum target, const GLbyte* data) {
3352 GPU_CLIENT_SINGLE_THREAD_CHECK();
3353 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
3354 << static_cast<const void*>(data) << ")");
3355 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
3356 DCHECK(mailbox.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
3357 "mailbox that was not generated by "
3358 "GenMailboxCHROMIUM.";
3359 GLuint client_id;
3360 GetIdHandler(id_namespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
3361 helper_->CreateAndConsumeTextureCHROMIUMImmediate(target,
3362 client_id, data);
3363 if (share_group_->bind_generates_resource())
3364 helper_->CommandBufferHelper::Flush();
3365 CheckGLError();
3366 return client_id;
3369 void GLES2Implementation::PushGroupMarkerEXT(
3370 GLsizei length, const GLchar* marker) {
3371 GPU_CLIENT_SINGLE_THREAD_CHECK();
3372 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
3373 << length << ", " << marker << ")");
3374 if (!marker) {
3375 marker = "";
3377 SetBucketAsString(
3378 kResultBucketId,
3379 (length ? std::string(marker, length) : std::string(marker)));
3380 helper_->PushGroupMarkerEXT(kResultBucketId);
3381 helper_->SetBucketSize(kResultBucketId, 0);
3382 debug_marker_manager_.PushGroup(
3383 length ? std::string(marker, length) : std::string(marker));
3386 void GLES2Implementation::InsertEventMarkerEXT(
3387 GLsizei length, const GLchar* marker) {
3388 GPU_CLIENT_SINGLE_THREAD_CHECK();
3389 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
3390 << length << ", " << marker << ")");
3391 if (!marker) {
3392 marker = "";
3394 SetBucketAsString(
3395 kResultBucketId,
3396 (length ? std::string(marker, length) : std::string(marker)));
3397 helper_->InsertEventMarkerEXT(kResultBucketId);
3398 helper_->SetBucketSize(kResultBucketId, 0);
3399 debug_marker_manager_.SetMarker(
3400 length ? std::string(marker, length) : std::string(marker));
3403 void GLES2Implementation::PopGroupMarkerEXT() {
3404 GPU_CLIENT_SINGLE_THREAD_CHECK();
3405 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
3406 helper_->PopGroupMarkerEXT();
3407 debug_marker_manager_.PopGroup();
3410 void GLES2Implementation::TraceBeginCHROMIUM(const char* name) {
3411 GPU_CLIENT_SINGLE_THREAD_CHECK();
3412 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
3413 << name << ")");
3414 if (current_trace_name_.get()) {
3415 SetGLError(GL_INVALID_OPERATION, "glTraceBeginCHROMIUM",
3416 "trace already running");
3417 return;
3419 TRACE_EVENT_COPY_ASYNC_BEGIN0("gpu", name, this);
3420 SetBucketAsCString(kResultBucketId, name);
3421 helper_->TraceBeginCHROMIUM(kResultBucketId);
3422 helper_->SetBucketSize(kResultBucketId, 0);
3423 current_trace_name_.reset(new std::string(name));
3426 void GLES2Implementation::TraceEndCHROMIUM() {
3427 GPU_CLIENT_SINGLE_THREAD_CHECK();
3428 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
3429 if (!current_trace_name_.get()) {
3430 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
3431 "missing begin trace");
3432 return;
3434 helper_->TraceEndCHROMIUM();
3435 TRACE_EVENT_COPY_ASYNC_END0("gpu", current_trace_name_->c_str(), this);
3436 current_trace_name_.reset();
3439 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
3440 GPU_CLIENT_SINGLE_THREAD_CHECK();
3441 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
3442 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
3443 switch (target) {
3444 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3445 if (access != GL_READ_ONLY) {
3446 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3447 return NULL;
3449 break;
3450 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3451 if (access != GL_WRITE_ONLY) {
3452 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3453 return NULL;
3455 break;
3456 default:
3457 SetGLError(
3458 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
3459 return NULL;
3461 GLuint buffer_id;
3462 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
3463 if (!buffer_id) {
3464 return NULL;
3466 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3467 if (!buffer) {
3468 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
3469 return NULL;
3471 if (buffer->mapped()) {
3472 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
3473 return NULL;
3475 // Here we wait for previous transfer operations to be finished.
3476 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
3477 // with this method of synchronization. Until this is fixed,
3478 // MapBufferCHROMIUM will not block even if the transfer is not ready
3479 // for these calls.
3480 if (buffer->last_usage_token()) {
3481 helper_->WaitForToken(buffer->last_usage_token());
3482 buffer->set_last_usage_token(0);
3484 buffer->set_mapped(true);
3486 GPU_CLIENT_LOG(" returned " << buffer->address());
3487 CheckGLError();
3488 return buffer->address();
3491 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
3492 GPU_CLIENT_SINGLE_THREAD_CHECK();
3493 GPU_CLIENT_LOG(
3494 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
3495 GLuint buffer_id;
3496 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
3497 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
3499 if (!buffer_id) {
3500 return false;
3502 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3503 if (!buffer) {
3504 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
3505 return false;
3507 if (!buffer->mapped()) {
3508 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
3509 return false;
3511 buffer->set_mapped(false);
3512 CheckGLError();
3513 return true;
3516 bool GLES2Implementation::EnsureAsyncUploadSync() {
3517 if (async_upload_sync_)
3518 return true;
3520 int32 shm_id;
3521 unsigned int shm_offset;
3522 void* mem = mapped_memory_->Alloc(sizeof(AsyncUploadSync),
3523 &shm_id,
3524 &shm_offset);
3525 if (!mem)
3526 return false;
3528 async_upload_sync_shm_id_ = shm_id;
3529 async_upload_sync_shm_offset_ = shm_offset;
3530 async_upload_sync_ = static_cast<AsyncUploadSync*>(mem);
3531 async_upload_sync_->Reset();
3533 return true;
3536 uint32 GLES2Implementation::NextAsyncUploadToken() {
3537 async_upload_token_++;
3538 if (async_upload_token_ == 0)
3539 async_upload_token_++;
3540 return async_upload_token_;
3543 void GLES2Implementation::PollAsyncUploads() {
3544 if (!async_upload_sync_)
3545 return;
3547 if (helper_->IsContextLost()) {
3548 DetachedAsyncUploadMemoryList::iterator it =
3549 detached_async_upload_memory_.begin();
3550 while (it != detached_async_upload_memory_.end()) {
3551 mapped_memory_->Free(it->first);
3552 it = detached_async_upload_memory_.erase(it);
3554 return;
3557 DetachedAsyncUploadMemoryList::iterator it =
3558 detached_async_upload_memory_.begin();
3559 while (it != detached_async_upload_memory_.end()) {
3560 if (HasAsyncUploadTokenPassed(it->second)) {
3561 mapped_memory_->Free(it->first);
3562 it = detached_async_upload_memory_.erase(it);
3563 } else {
3564 break;
3569 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
3570 // Free all completed unmanaged async uploads buffers.
3571 PollAsyncUploads();
3573 // Synchronously free rest of the unmanaged async upload buffers.
3574 if (!detached_async_upload_memory_.empty()) {
3575 WaitAllAsyncTexImage2DCHROMIUM();
3576 WaitForCmd();
3577 PollAsyncUploads();
3581 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
3582 GLenum target, GLint level, GLenum internalformat, GLsizei width,
3583 GLsizei height, GLint border, GLenum format, GLenum type,
3584 const void* pixels) {
3585 GPU_CLIENT_SINGLE_THREAD_CHECK();
3586 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
3587 << GLES2Util::GetStringTextureTarget(target) << ", "
3588 << level << ", "
3589 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
3590 << width << ", " << height << ", " << border << ", "
3591 << GLES2Util::GetStringTextureFormat(format) << ", "
3592 << GLES2Util::GetStringPixelType(type) << ", "
3593 << static_cast<const void*>(pixels) << ")");
3594 if (level < 0 || height < 0 || width < 0) {
3595 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
3596 return;
3598 if (border != 0) {
3599 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
3600 return;
3602 uint32 size;
3603 uint32 unpadded_row_size;
3604 uint32 padded_row_size;
3605 if (!GLES2Util::ComputeImageDataSizes(
3606 width, height, format, type, unpack_alignment_, &size,
3607 &unpadded_row_size, &padded_row_size)) {
3608 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
3609 return;
3612 // If there's no data/buffer just issue the AsyncTexImage2D
3613 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
3614 helper_->AsyncTexImage2DCHROMIUM(
3615 target, level, internalformat, width, height, format, type,
3616 0, 0, 0, 0, 0);
3617 return;
3620 if (!EnsureAsyncUploadSync()) {
3621 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
3622 return;
3625 // Otherwise, async uploads require a transfer buffer to be bound.
3626 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3627 // the buffer before the transfer is finished. (Currently such
3628 // synchronization has to be handled manually.)
3629 GLuint offset = ToGLuint(pixels);
3630 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3631 bound_pixel_unpack_transfer_buffer_id_,
3632 "glAsyncTexImage2DCHROMIUM", offset, size);
3633 if (buffer && buffer->shm_id() != -1) {
3634 uint32 async_token = NextAsyncUploadToken();
3635 buffer->set_last_async_upload_token(async_token);
3636 helper_->AsyncTexImage2DCHROMIUM(
3637 target, level, internalformat, width, height, format, type,
3638 buffer->shm_id(), buffer->shm_offset() + offset,
3639 async_token,
3640 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
3644 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
3645 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
3646 GLsizei height, GLenum format, GLenum type, const void* pixels) {
3647 GPU_CLIENT_SINGLE_THREAD_CHECK();
3648 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
3649 << GLES2Util::GetStringTextureTarget(target) << ", "
3650 << level << ", "
3651 << xoffset << ", " << yoffset << ", "
3652 << width << ", " << height << ", "
3653 << GLES2Util::GetStringTextureFormat(format) << ", "
3654 << GLES2Util::GetStringPixelType(type) << ", "
3655 << static_cast<const void*>(pixels) << ")");
3656 if (level < 0 || height < 0 || width < 0) {
3657 SetGLError(
3658 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
3659 return;
3662 uint32 size;
3663 uint32 unpadded_row_size;
3664 uint32 padded_row_size;
3665 if (!GLES2Util::ComputeImageDataSizes(
3666 width, height, format, type, unpack_alignment_, &size,
3667 &unpadded_row_size, &padded_row_size)) {
3668 SetGLError(
3669 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
3670 return;
3673 if (!EnsureAsyncUploadSync()) {
3674 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
3675 return;
3678 // Async uploads require a transfer buffer to be bound.
3679 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3680 // the buffer before the transfer is finished. (Currently such
3681 // synchronization has to be handled manually.)
3682 GLuint offset = ToGLuint(pixels);
3683 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3684 bound_pixel_unpack_transfer_buffer_id_,
3685 "glAsyncTexSubImage2DCHROMIUM", offset, size);
3686 if (buffer && buffer->shm_id() != -1) {
3687 uint32 async_token = NextAsyncUploadToken();
3688 buffer->set_last_async_upload_token(async_token);
3689 helper_->AsyncTexSubImage2DCHROMIUM(
3690 target, level, xoffset, yoffset, width, height, format, type,
3691 buffer->shm_id(), buffer->shm_offset() + offset,
3692 async_token,
3693 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
3697 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
3698 GPU_CLIENT_SINGLE_THREAD_CHECK();
3699 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
3700 << GLES2Util::GetStringTextureTarget(target) << ")");
3701 helper_->WaitAsyncTexImage2DCHROMIUM(target);
3702 CheckGLError();
3705 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
3706 GPU_CLIENT_SINGLE_THREAD_CHECK();
3707 GPU_CLIENT_LOG("[" << GetLogPrefix()
3708 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
3709 helper_->WaitAllAsyncTexImage2DCHROMIUM();
3710 CheckGLError();
3713 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
3714 GPU_CLIENT_SINGLE_THREAD_CHECK();
3715 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
3716 helper_->CommandBufferHelper::Flush();
3717 return gpu_control_->InsertSyncPoint();
3720 GLuint GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
3721 GPU_CLIENT_SINGLE_THREAD_CHECK();
3722 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
3723 DCHECK(capabilities_.future_sync_points);
3724 return gpu_control_->InsertFutureSyncPoint();
3727 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point) {
3728 GPU_CLIENT_SINGLE_THREAD_CHECK();
3729 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
3730 << sync_point << ")");
3731 DCHECK(capabilities_.future_sync_points);
3732 helper_->CommandBufferHelper::Flush();
3733 gpu_control_->RetireSyncPoint(sync_point);
3736 namespace {
3738 bool ValidImageFormat(GLenum internalformat) {
3739 switch (internalformat) {
3740 case GL_RGB:
3741 case GL_RGBA:
3742 return true;
3743 default:
3744 return false;
3748 bool ValidImageUsage(GLenum usage) {
3749 switch (usage) {
3750 case GL_MAP_CHROMIUM:
3751 case GL_SCANOUT_CHROMIUM:
3752 return true;
3753 default:
3754 return false;
3758 } // namespace
3760 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer,
3761 GLsizei width,
3762 GLsizei height,
3763 GLenum internalformat) {
3764 if (width <= 0) {
3765 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
3766 return 0;
3769 if (height <= 0) {
3770 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
3771 return 0;
3774 if (!ValidImageFormat(internalformat)) {
3775 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "invalid format");
3776 return 0;
3779 int32_t image_id =
3780 gpu_control_->CreateImage(buffer, width, height, internalformat);
3781 if (image_id < 0) {
3782 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "image_id < 0");
3783 return 0;
3785 return image_id;
3788 GLuint GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer,
3789 GLsizei width,
3790 GLsizei height,
3791 GLenum internalformat) {
3792 GPU_CLIENT_SINGLE_THREAD_CHECK();
3793 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
3794 << ", " << height << ", "
3795 << GLES2Util::GetStringImageInternalFormat(internalformat)
3796 << ")");
3797 GLuint image_id =
3798 CreateImageCHROMIUMHelper(buffer, width, height, internalformat);
3799 CheckGLError();
3800 return image_id;
3803 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
3804 // Flush the command stream to make sure all pending commands
3805 // that may refer to the image_id are executed on the service side.
3806 helper_->CommandBufferHelper::Flush();
3807 gpu_control_->DestroyImage(image_id);
3810 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
3811 GPU_CLIENT_SINGLE_THREAD_CHECK();
3812 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
3813 << image_id << ")");
3814 DestroyImageCHROMIUMHelper(image_id);
3815 CheckGLError();
3818 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
3819 GLsizei width,
3820 GLsizei height,
3821 GLenum internalformat,
3822 GLenum usage) {
3823 if (width <= 0) {
3824 SetGLError(
3825 GL_INVALID_VALUE, "glCreateGpuMemoryBufferImageCHROMIUM", "width <= 0");
3826 return 0;
3829 if (height <= 0) {
3830 SetGLError(GL_INVALID_VALUE,
3831 "glCreateGpuMemoryBufferImageCHROMIUM",
3832 "height <= 0");
3833 return 0;
3836 if (!ValidImageFormat(internalformat)) {
3837 SetGLError(GL_INVALID_VALUE,
3838 "glCreateGpuMemoryBufferImageCHROMIUM",
3839 "invalid format");
3840 return 0;
3843 if (!ValidImageUsage(usage)) {
3844 SetGLError(GL_INVALID_VALUE,
3845 "glCreateGpuMemoryBufferImageCHROMIUM",
3846 "invalid usage");
3847 return 0;
3850 // Flush the command stream to ensure ordering in case the newly
3851 // returned image_id has recently been in use with a different buffer.
3852 helper_->CommandBufferHelper::Flush();
3853 int32_t image_id = gpu_control_->CreateGpuMemoryBufferImage(
3854 width, height, internalformat, usage);
3855 if (image_id < 0) {
3856 SetGLError(GL_OUT_OF_MEMORY,
3857 "glCreateGpuMemoryBufferImageCHROMIUM",
3858 "image_id < 0");
3859 return 0;
3861 return image_id;
3864 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
3865 GLsizei width,
3866 GLsizei height,
3867 GLenum internalformat,
3868 GLenum usage) {
3869 GPU_CLIENT_SINGLE_THREAD_CHECK();
3870 GPU_CLIENT_LOG("[" << GetLogPrefix()
3871 << "] glCreateGpuMemoryBufferImageCHROMIUM(" << width
3872 << ", " << height << ", "
3873 << GLES2Util::GetStringImageInternalFormat(internalformat)
3874 << ", " << GLES2Util::GetStringImageUsage(usage) << ")");
3875 GLuint image_id = CreateGpuMemoryBufferImageCHROMIUMHelper(
3876 width, height, internalformat, usage);
3877 CheckGLError();
3878 return image_id;
3881 bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
3882 if (size < 0) {
3883 SetGLError(GL_INVALID_VALUE, func, "size < 0");
3884 return false;
3886 if (!FitInt32NonNegative<GLsizeiptr>(size)) {
3887 SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
3888 return false;
3890 return true;
3893 bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
3894 if (offset < 0) {
3895 SetGLError(GL_INVALID_VALUE, func, "offset < 0");
3896 return false;
3898 if (!FitInt32NonNegative<GLintptr>(offset)) {
3899 SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
3900 return false;
3902 return true;
3905 // Include the auto-generated part of this file. We split this because it means
3906 // we can easily edit the non-auto generated parts right here in this file
3907 // instead of having to edit some template or the code generator.
3908 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
3910 } // namespace gles2
3911 } // namespace gpu