Handle account removal correctly on all platforms.
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blob974fd7541a84480b9cccf83206fbd0913abcd783
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/gpu_memory_buffer_tracker.h"
22 #include "gpu/command_buffer/client/program_info_manager.h"
23 #include "gpu/command_buffer/client/query_tracker.h"
24 #include "gpu/command_buffer/client/transfer_buffer.h"
25 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
26 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
27 #include "gpu/command_buffer/common/trace_event.h"
28 #include "ui/gfx/gpu_memory_buffer.h"
30 #if defined(__native_client__) && !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
31 #define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS
32 #endif
34 #if defined(GPU_CLIENT_DEBUG)
35 #include "base/command_line.h"
36 #include "ui/gl/gl_switches.h"
37 #endif
39 namespace gpu {
40 namespace gles2 {
42 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
43 static GLuint ToGLuint(const void* ptr) {
44 return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
47 #if !defined(_MSC_VER)
48 const size_t GLES2Implementation::kMaxSizeOfSimpleResult;
49 const unsigned int GLES2Implementation::kStartingOffset;
50 #endif
52 GLES2Implementation::GLStaticState::GLStaticState() {
55 GLES2Implementation::GLStaticState::~GLStaticState() {
58 GLES2Implementation::GLStaticState::IntState::IntState()
59 : max_combined_texture_image_units(0),
60 max_cube_map_texture_size(0),
61 max_fragment_uniform_vectors(0),
62 max_renderbuffer_size(0),
63 max_texture_image_units(0),
64 max_texture_size(0),
65 max_varying_vectors(0),
66 max_vertex_attribs(0),
67 max_vertex_texture_image_units(0),
68 max_vertex_uniform_vectors(0),
69 num_compressed_texture_formats(0),
70 num_shader_binary_formats(0),
71 bind_generates_resource_chromium(0) {}
73 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
74 GLES2Implementation* gles2_implementation)
75 : gles2_implementation_(gles2_implementation) {
76 CHECK_EQ(0, gles2_implementation_->use_count_);
77 ++gles2_implementation_->use_count_;
80 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
81 --gles2_implementation_->use_count_;
82 CHECK_EQ(0, gles2_implementation_->use_count_);
85 GLES2Implementation::GLES2Implementation(
86 GLES2CmdHelper* helper,
87 ShareGroup* share_group,
88 TransferBufferInterface* transfer_buffer,
89 bool bind_generates_resource,
90 bool lose_context_when_out_of_memory,
91 GpuControl* gpu_control)
92 : helper_(helper),
93 transfer_buffer_(transfer_buffer),
94 angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
95 chromium_framebuffer_multisample_(kUnknownExtensionStatus),
96 pack_alignment_(4),
97 unpack_alignment_(4),
98 unpack_flip_y_(false),
99 unpack_row_length_(0),
100 unpack_skip_rows_(0),
101 unpack_skip_pixels_(0),
102 pack_reverse_row_order_(false),
103 active_texture_unit_(0),
104 bound_framebuffer_(0),
105 bound_read_framebuffer_(0),
106 bound_renderbuffer_(0),
107 current_program_(0),
108 bound_array_buffer_id_(0),
109 bound_pixel_pack_transfer_buffer_id_(0),
110 bound_pixel_unpack_transfer_buffer_id_(0),
111 async_upload_token_(0),
112 async_upload_sync_(NULL),
113 async_upload_sync_shm_id_(0),
114 async_upload_sync_shm_offset_(0),
115 error_bits_(0),
116 debug_(false),
117 lose_context_when_out_of_memory_(lose_context_when_out_of_memory),
118 use_count_(0),
119 error_message_callback_(NULL),
120 gpu_control_(gpu_control),
121 capabilities_(gpu_control->GetCapabilities()),
122 weak_ptr_factory_(this) {
123 DCHECK(helper);
124 DCHECK(transfer_buffer);
125 DCHECK(gpu_control);
127 std::stringstream ss;
128 ss << std::hex << this;
129 this_in_hex_ = ss.str();
131 GPU_CLIENT_LOG_CODE_BLOCK({
132 debug_ = CommandLine::ForCurrentProcess()->HasSwitch(
133 switches::kEnableGPUClientLogging);
136 share_group_ =
137 (share_group ? share_group : new ShareGroup(bind_generates_resource));
138 DCHECK(share_group_->bind_generates_resource() == bind_generates_resource);
140 memset(&reserved_ids_, 0, sizeof(reserved_ids_));
143 bool GLES2Implementation::Initialize(
144 unsigned int starting_transfer_buffer_size,
145 unsigned int min_transfer_buffer_size,
146 unsigned int max_transfer_buffer_size,
147 unsigned int mapped_memory_limit) {
148 TRACE_EVENT0("gpu", "GLES2Implementation::Initialize");
149 DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
150 DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
151 DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
153 if (!transfer_buffer_->Initialize(
154 starting_transfer_buffer_size,
155 kStartingOffset,
156 min_transfer_buffer_size,
157 max_transfer_buffer_size,
158 kAlignment,
159 kSizeToFlush)) {
160 return false;
163 mapped_memory_.reset(
164 new MappedMemoryManager(
165 helper_,
166 base::Bind(&GLES2Implementation::PollAsyncUploads,
167 // The mapped memory manager is owned by |this| here, and
168 // since its destroyed before before we destroy ourselves
169 // we don't need extra safety measures for this closure.
170 base::Unretained(this)),
171 mapped_memory_limit));
173 unsigned chunk_size = 2 * 1024 * 1024;
174 if (mapped_memory_limit != kNoLimit) {
175 // Use smaller chunks if the client is very memory conscientious.
176 chunk_size = std::min(mapped_memory_limit / 4, chunk_size);
178 mapped_memory_->set_chunk_size_multiple(chunk_size);
180 if (!QueryAndCacheStaticState())
181 return false;
183 util_.set_num_compressed_texture_formats(
184 static_state_.int_state.num_compressed_texture_formats);
185 util_.set_num_shader_binary_formats(
186 static_state_.int_state.num_shader_binary_formats);
188 texture_units_.reset(
189 new TextureUnit[
190 static_state_.int_state.max_combined_texture_image_units]);
192 query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
193 buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
194 gpu_memory_buffer_tracker_.reset(new GpuMemoryBufferTracker(gpu_control_));
196 query_id_allocator_.reset(new IdAllocator());
197 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
198 GetIdHandler(id_namespaces::kBuffers)->MakeIds(
199 this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
200 #endif
202 vertex_array_object_manager_.reset(new VertexArrayObjectManager(
203 static_state_.int_state.max_vertex_attribs,
204 reserved_ids_[0],
205 reserved_ids_[1]));
207 // GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
208 // on Client & Service.
209 if (static_state_.int_state.bind_generates_resource_chromium !=
210 (share_group_->bind_generates_resource() ? 1 : 0)) {
211 SetGLError(GL_INVALID_OPERATION,
212 "Initialize",
213 "Service bind_generates_resource mismatch.");
214 return false;
217 return true;
220 bool GLES2Implementation::QueryAndCacheStaticState() {
221 TRACE_EVENT0("gpu", "GLES2Implementation::QueryAndCacheStaticState");
222 // Setup query for multiple GetIntegerv's
223 static const GLenum pnames[] = {
224 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
225 GL_MAX_CUBE_MAP_TEXTURE_SIZE,
226 GL_MAX_FRAGMENT_UNIFORM_VECTORS,
227 GL_MAX_RENDERBUFFER_SIZE,
228 GL_MAX_TEXTURE_IMAGE_UNITS,
229 GL_MAX_TEXTURE_SIZE,
230 GL_MAX_VARYING_VECTORS,
231 GL_MAX_VERTEX_ATTRIBS,
232 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
233 GL_MAX_VERTEX_UNIFORM_VECTORS,
234 GL_NUM_COMPRESSED_TEXTURE_FORMATS,
235 GL_NUM_SHADER_BINARY_FORMATS,
236 GL_BIND_GENERATES_RESOURCE_CHROMIUM,
239 GetMultipleIntegervState integerv_state(
240 pnames, arraysize(pnames),
241 &static_state_.int_state.max_combined_texture_image_units,
242 sizeof(static_state_.int_state));
243 if (!GetMultipleIntegervSetup(&integerv_state)) {
244 return false;
247 // Setup query for multiple GetShaderPrecisionFormat's
248 static const GLenum precision_params[][2] = {
249 { GL_VERTEX_SHADER, GL_LOW_INT },
250 { GL_VERTEX_SHADER, GL_MEDIUM_INT },
251 { GL_VERTEX_SHADER, GL_HIGH_INT },
252 { GL_VERTEX_SHADER, GL_LOW_FLOAT },
253 { GL_VERTEX_SHADER, GL_MEDIUM_FLOAT },
254 { GL_VERTEX_SHADER, GL_HIGH_FLOAT },
255 { GL_FRAGMENT_SHADER, GL_LOW_INT },
256 { GL_FRAGMENT_SHADER, GL_MEDIUM_INT },
257 { GL_FRAGMENT_SHADER, GL_HIGH_INT },
258 { GL_FRAGMENT_SHADER, GL_LOW_FLOAT },
259 { GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT },
260 { GL_FRAGMENT_SHADER, GL_HIGH_FLOAT },
263 GetAllShaderPrecisionFormatsState precision_state(
264 precision_params, arraysize(precision_params));
265 GetAllShaderPrecisionFormatsSetup(&precision_state);
267 // Allocate and partition transfer buffer for all requests
268 void* buffer = transfer_buffer_->Alloc(
269 integerv_state.transfer_buffer_size_needed +
270 precision_state.transfer_buffer_size_needed);
271 if (!buffer) {
272 SetGLError(GL_OUT_OF_MEMORY, "QueryAndCacheStaticState",
273 "Transfer buffer allocation failed.");
274 return false;
276 integerv_state.buffer = buffer;
277 precision_state.results_buffer =
278 static_cast<char*>(buffer) + integerv_state.transfer_buffer_size_needed;
280 // Make all the requests and wait once for all the results.
281 GetMultipleIntegervRequest(&integerv_state);
282 GetAllShaderPrecisionFormatsRequest(&precision_state);
283 WaitForCmd();
284 GetMultipleIntegervOnCompleted(&integerv_state);
285 GetAllShaderPrecisionFormatsOnCompleted(&precision_state);
287 // TODO(gman): We should be able to free without a token.
288 transfer_buffer_->FreePendingToken(buffer, helper_->InsertToken());
289 CheckGLError();
291 return true;
294 GLES2Implementation::~GLES2Implementation() {
295 // Make sure the queries are finished otherwise we'll delete the
296 // shared memory (mapped_memory_) which will free the memory used
297 // by the queries. The GPU process when validating that memory is still
298 // shared will fail and abort (ie, it will stop running).
299 WaitForCmd();
300 query_tracker_.reset();
302 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
303 DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
304 #endif
306 // Release any per-context data in share group.
307 share_group_->FreeContext(this);
309 buffer_tracker_.reset();
311 FreeAllAsyncUploadBuffers();
313 if (async_upload_sync_) {
314 mapped_memory_->Free(async_upload_sync_);
315 async_upload_sync_ = NULL;
318 // Make sure the commands make it the service.
319 WaitForCmd();
322 GLES2CmdHelper* GLES2Implementation::helper() const {
323 return helper_;
326 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
327 return share_group_->GetIdHandler(namespace_id);
330 IdAllocatorInterface* GLES2Implementation::GetIdAllocator(
331 int namespace_id) const {
332 if (namespace_id == id_namespaces::kQueries)
333 return query_id_allocator_.get();
334 NOTREACHED();
335 return NULL;
338 void* GLES2Implementation::GetResultBuffer() {
339 return transfer_buffer_->GetResultBuffer();
342 int32 GLES2Implementation::GetResultShmId() {
343 return transfer_buffer_->GetShmId();
346 uint32 GLES2Implementation::GetResultShmOffset() {
347 return transfer_buffer_->GetResultOffset();
350 void GLES2Implementation::FreeUnusedSharedMemory() {
351 mapped_memory_->FreeUnused();
354 void GLES2Implementation::FreeEverything() {
355 FreeAllAsyncUploadBuffers();
356 WaitForCmd();
357 query_tracker_->Shrink();
358 FreeUnusedSharedMemory();
359 transfer_buffer_->Free();
360 helper_->FreeRingBuffer();
363 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
364 if (!helper_->IsContextLost())
365 callback.Run();
368 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
369 const base::Closure& callback) {
370 gpu_control_->SignalSyncPoint(
371 sync_point,
372 base::Bind(&GLES2Implementation::RunIfContextNotLost,
373 weak_ptr_factory_.GetWeakPtr(),
374 callback));
377 void GLES2Implementation::SignalQuery(uint32 query,
378 const base::Closure& callback) {
379 // Flush previously entered commands to ensure ordering with any
380 // glBeginQueryEXT() calls that may have been put into the context.
381 ShallowFlushCHROMIUM();
382 gpu_control_->SignalQuery(
383 query,
384 base::Bind(&GLES2Implementation::RunIfContextNotLost,
385 weak_ptr_factory_.GetWeakPtr(),
386 callback));
389 void GLES2Implementation::SetSurfaceVisible(bool visible) {
390 TRACE_EVENT1(
391 "gpu", "GLES2Implementation::SetSurfaceVisible", "visible", visible);
392 // TODO(piman): This probably should be ShallowFlushCHROMIUM().
393 Flush();
394 gpu_control_->SetSurfaceVisible(visible);
395 if (!visible)
396 FreeEverything();
399 void GLES2Implementation::WaitForCmd() {
400 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
401 helper_->CommandBufferHelper::Finish();
404 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
405 const char* extensions =
406 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
407 if (!extensions)
408 return false;
410 int length = strlen(ext);
411 while (true) {
412 int n = strcspn(extensions, " ");
413 if (n == length && 0 == strncmp(ext, extensions, length)) {
414 return true;
416 if ('\0' == extensions[n]) {
417 return false;
419 extensions += n + 1;
423 bool GLES2Implementation::IsExtensionAvailableHelper(
424 const char* extension, ExtensionStatus* status) {
425 switch (*status) {
426 case kAvailableExtensionStatus:
427 return true;
428 case kUnavailableExtensionStatus:
429 return false;
430 default: {
431 bool available = IsExtensionAvailable(extension);
432 *status = available ? kAvailableExtensionStatus :
433 kUnavailableExtensionStatus;
434 return available;
439 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
440 return IsExtensionAvailableHelper(
441 "GL_ANGLE_pack_reverse_row_order",
442 &angle_pack_reverse_row_order_status_);
445 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
446 return IsExtensionAvailableHelper(
447 "GL_CHROMIUM_framebuffer_multisample",
448 &chromium_framebuffer_multisample_);
451 const std::string& GLES2Implementation::GetLogPrefix() const {
452 const std::string& prefix(debug_marker_manager_.GetMarker());
453 return prefix.empty() ? this_in_hex_ : prefix;
456 GLenum GLES2Implementation::GetError() {
457 GPU_CLIENT_SINGLE_THREAD_CHECK();
458 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
459 GLenum err = GetGLError();
460 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
461 return err;
464 GLenum GLES2Implementation::GetClientSideGLError() {
465 if (error_bits_ == 0) {
466 return GL_NO_ERROR;
469 GLenum error = GL_NO_ERROR;
470 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
471 if ((error_bits_ & mask) != 0) {
472 error = GLES2Util::GLErrorBitToGLError(mask);
473 break;
476 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
477 return error;
480 GLenum GLES2Implementation::GetGLError() {
481 TRACE_EVENT0("gpu", "GLES2::GetGLError");
482 // Check the GL error first, then our wrapped error.
483 typedef cmds::GetError::Result Result;
484 Result* result = GetResultAs<Result*>();
485 // If we couldn't allocate a result the context is lost.
486 if (!result) {
487 return GL_NO_ERROR;
489 *result = GL_NO_ERROR;
490 helper_->GetError(GetResultShmId(), GetResultShmOffset());
491 WaitForCmd();
492 GLenum error = *result;
493 if (error == GL_NO_ERROR) {
494 error = GetClientSideGLError();
495 } else {
496 // There was an error, clear the corresponding wrapped error.
497 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
499 return error;
502 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
503 void GLES2Implementation::FailGLError(GLenum error) {
504 if (error != GL_NO_ERROR) {
505 NOTREACHED() << "Error";
508 // NOTE: Calling GetGLError overwrites data in the result buffer.
509 void GLES2Implementation::CheckGLError() {
510 FailGLError(GetGLError());
512 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
514 void GLES2Implementation::SetGLError(
515 GLenum error, const char* function_name, const char* msg) {
516 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
517 << GLES2Util::GetStringError(error) << ": "
518 << function_name << ": " << msg);
519 FailGLError(error);
520 if (msg) {
521 last_error_ = msg;
523 if (error_message_callback_) {
524 std::string temp(GLES2Util::GetStringError(error) + " : " +
525 function_name + ": " + (msg ? msg : ""));
526 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
528 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
530 if (error == GL_OUT_OF_MEMORY && lose_context_when_out_of_memory_) {
531 helper_->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
532 GL_UNKNOWN_CONTEXT_RESET_ARB);
536 void GLES2Implementation::SetGLErrorInvalidEnum(
537 const char* function_name, GLenum value, const char* label) {
538 SetGLError(GL_INVALID_ENUM, function_name,
539 (std::string(label) + " was " +
540 GLES2Util::GetStringEnum(value)).c_str());
543 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
544 std::vector<int8>* data) {
545 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
546 DCHECK(data);
547 const uint32 kStartSize = 32 * 1024;
548 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
549 if (!buffer.valid()) {
550 return false;
552 typedef cmd::GetBucketStart::Result Result;
553 Result* result = GetResultAs<Result*>();
554 if (!result) {
555 return false;
557 *result = 0;
558 helper_->GetBucketStart(
559 bucket_id, GetResultShmId(), GetResultShmOffset(),
560 buffer.size(), buffer.shm_id(), buffer.offset());
561 WaitForCmd();
562 uint32 size = *result;
563 data->resize(size);
564 if (size > 0u) {
565 uint32 offset = 0;
566 while (size) {
567 if (!buffer.valid()) {
568 buffer.Reset(size);
569 if (!buffer.valid()) {
570 return false;
572 helper_->GetBucketData(
573 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
574 WaitForCmd();
576 uint32 size_to_copy = std::min(size, buffer.size());
577 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
578 offset += size_to_copy;
579 size -= size_to_copy;
580 buffer.Release();
582 // Free the bucket. This is not required but it does free up the memory.
583 // and we don't have to wait for the result so from the client's perspective
584 // it's cheap.
585 helper_->SetBucketSize(bucket_id, 0);
587 return true;
590 void GLES2Implementation::SetBucketContents(
591 uint32 bucket_id, const void* data, size_t size) {
592 DCHECK(data);
593 helper_->SetBucketSize(bucket_id, size);
594 if (size > 0u) {
595 uint32 offset = 0;
596 while (size) {
597 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
598 if (!buffer.valid()) {
599 return;
601 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
602 buffer.size());
603 helper_->SetBucketData(
604 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
605 offset += buffer.size();
606 size -= buffer.size();
611 void GLES2Implementation::SetBucketAsCString(
612 uint32 bucket_id, const char* str) {
613 // NOTE: strings are passed NULL terminated. That means the empty
614 // string will have a size of 1 and no-string will have a size of 0
615 if (str) {
616 SetBucketContents(bucket_id, str, strlen(str) + 1);
617 } else {
618 helper_->SetBucketSize(bucket_id, 0);
622 bool GLES2Implementation::GetBucketAsString(
623 uint32 bucket_id, std::string* str) {
624 DCHECK(str);
625 std::vector<int8> data;
626 // NOTE: strings are passed NULL terminated. That means the empty
627 // string will have a size of 1 and no-string will have a size of 0
628 if (!GetBucketContents(bucket_id, &data)) {
629 return false;
631 if (data.empty()) {
632 return false;
634 str->assign(&data[0], &data[0] + data.size() - 1);
635 return true;
638 void GLES2Implementation::SetBucketAsString(
639 uint32 bucket_id, const std::string& str) {
640 // NOTE: strings are passed NULL terminated. That means the empty
641 // string will have a size of 1 and no-string will have a size of 0
642 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
645 void GLES2Implementation::Disable(GLenum cap) {
646 GPU_CLIENT_SINGLE_THREAD_CHECK();
647 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
648 << GLES2Util::GetStringCapability(cap) << ")");
649 bool changed = false;
650 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
651 helper_->Disable(cap);
653 CheckGLError();
656 void GLES2Implementation::Enable(GLenum cap) {
657 GPU_CLIENT_SINGLE_THREAD_CHECK();
658 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
659 << GLES2Util::GetStringCapability(cap) << ")");
660 bool changed = false;
661 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
662 helper_->Enable(cap);
664 CheckGLError();
667 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
668 GPU_CLIENT_SINGLE_THREAD_CHECK();
669 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
670 << GLES2Util::GetStringCapability(cap) << ")");
671 bool state = false;
672 if (!state_.GetEnabled(cap, &state)) {
673 typedef cmds::IsEnabled::Result Result;
674 Result* result = GetResultAs<Result*>();
675 if (!result) {
676 return GL_FALSE;
678 *result = 0;
679 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
680 WaitForCmd();
681 state = (*result) != 0;
684 GPU_CLIENT_LOG("returned " << state);
685 CheckGLError();
686 return state;
689 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
690 switch (pname) {
691 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
692 *params = static_state_.int_state.max_combined_texture_image_units;
693 return true;
694 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
695 *params = static_state_.int_state.max_cube_map_texture_size;
696 return true;
697 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
698 *params = static_state_.int_state.max_fragment_uniform_vectors;
699 return true;
700 case GL_MAX_RENDERBUFFER_SIZE:
701 *params = static_state_.int_state.max_renderbuffer_size;
702 return true;
703 case GL_MAX_TEXTURE_IMAGE_UNITS:
704 *params = static_state_.int_state.max_texture_image_units;
705 return true;
706 case GL_MAX_TEXTURE_SIZE:
707 *params = static_state_.int_state.max_texture_size;
708 return true;
709 case GL_MAX_VARYING_VECTORS:
710 *params = static_state_.int_state.max_varying_vectors;
711 return true;
712 case GL_MAX_VERTEX_ATTRIBS:
713 *params = static_state_.int_state.max_vertex_attribs;
714 return true;
715 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
716 *params = static_state_.int_state.max_vertex_texture_image_units;
717 return true;
718 case GL_MAX_VERTEX_UNIFORM_VECTORS:
719 *params = static_state_.int_state.max_vertex_uniform_vectors;
720 return true;
721 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
722 *params = static_state_.int_state.num_compressed_texture_formats;
723 return true;
724 case GL_NUM_SHADER_BINARY_FORMATS:
725 *params = static_state_.int_state.num_shader_binary_formats;
726 return true;
727 case GL_ARRAY_BUFFER_BINDING:
728 if (share_group_->bind_generates_resource()) {
729 *params = bound_array_buffer_id_;
730 return true;
732 return false;
733 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
734 if (share_group_->bind_generates_resource()) {
735 *params =
736 vertex_array_object_manager_->bound_element_array_buffer();
737 return true;
739 return false;
740 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
741 *params = bound_pixel_pack_transfer_buffer_id_;
742 return true;
743 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
744 *params = bound_pixel_unpack_transfer_buffer_id_;
745 return true;
746 case GL_ACTIVE_TEXTURE:
747 *params = active_texture_unit_ + GL_TEXTURE0;
748 return true;
749 case GL_TEXTURE_BINDING_2D:
750 if (share_group_->bind_generates_resource()) {
751 *params = texture_units_[active_texture_unit_].bound_texture_2d;
752 return true;
754 return false;
755 case GL_TEXTURE_BINDING_CUBE_MAP:
756 if (share_group_->bind_generates_resource()) {
757 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
758 return true;
760 return false;
761 case GL_TEXTURE_BINDING_EXTERNAL_OES:
762 if (share_group_->bind_generates_resource()) {
763 *params =
764 texture_units_[active_texture_unit_].bound_texture_external_oes;
765 return true;
767 return false;
768 case GL_FRAMEBUFFER_BINDING:
769 if (share_group_->bind_generates_resource()) {
770 *params = bound_framebuffer_;
771 return true;
773 return false;
774 case GL_READ_FRAMEBUFFER_BINDING:
775 if (IsChromiumFramebufferMultisampleAvailable() &&
776 share_group_->bind_generates_resource()) {
777 *params = bound_read_framebuffer_;
778 return true;
780 return false;
781 case GL_RENDERBUFFER_BINDING:
782 if (share_group_->bind_generates_resource()) {
783 *params = bound_renderbuffer_;
784 return true;
786 return false;
787 default:
788 return false;
792 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
793 // TODO(gman): Make this handle pnames that return more than 1 value.
794 GLint value;
795 if (!GetHelper(pname, &value)) {
796 return false;
798 *params = static_cast<GLboolean>(value);
799 return true;
802 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
803 // TODO(gman): Make this handle pnames that return more than 1 value.
804 GLint value;
805 if (!GetHelper(pname, &value)) {
806 return false;
808 *params = static_cast<GLfloat>(value);
809 return true;
812 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
813 return GetHelper(pname, params);
816 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
817 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
818 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
819 Result* result = GetResultAs<Result*>();
820 if (!result) {
821 return 0;
823 *result = 0;
824 helper_->GetMaxValueInBufferCHROMIUM(
825 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
826 WaitForCmd();
827 return *result;
830 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
831 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
832 GPU_CLIENT_SINGLE_THREAD_CHECK();
833 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
834 << buffer_id << ", " << count << ", "
835 << GLES2Util::GetStringGetMaxIndexType(type)
836 << ", " << offset << ")");
837 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
838 buffer_id, count, type, offset);
839 GPU_CLIENT_LOG("returned " << result);
840 CheckGLError();
841 return result;
844 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
845 if (restore) {
846 RestoreArrayBuffer(restore);
847 // Restore the element array binding.
848 // We only need to restore it if it wasn't a client side array.
849 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
850 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
855 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
856 if (restore) {
857 // Restore the user's current binding.
858 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_);
862 void GLES2Implementation::DrawElements(
863 GLenum mode, GLsizei count, GLenum type, const void* indices) {
864 GPU_CLIENT_SINGLE_THREAD_CHECK();
865 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
866 << GLES2Util::GetStringDrawMode(mode) << ", "
867 << count << ", "
868 << GLES2Util::GetStringIndexType(type) << ", "
869 << static_cast<const void*>(indices) << ")");
870 if (count < 0) {
871 SetGLError(GL_INVALID_VALUE, "glDrawElements", "count less than 0.");
872 return;
874 if (count == 0) {
875 return;
877 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
878 !ValidateOffset("glDrawElements", reinterpret_cast<GLintptr>(indices))) {
879 return;
881 GLuint offset = 0;
882 bool simulated = false;
883 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
884 "glDrawElements", this, helper_, count, type, 0, indices,
885 &offset, &simulated)) {
886 return;
888 helper_->DrawElements(mode, count, type, offset);
889 RestoreElementAndArrayBuffers(simulated);
890 CheckGLError();
893 void GLES2Implementation::Flush() {
894 GPU_CLIENT_SINGLE_THREAD_CHECK();
895 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
896 // Insert the cmd to call glFlush
897 helper_->Flush();
898 // Flush our command buffer
899 // (tell the service to execute up to the flush cmd.)
900 helper_->CommandBufferHelper::Flush();
903 void GLES2Implementation::ShallowFlushCHROMIUM() {
904 GPU_CLIENT_SINGLE_THREAD_CHECK();
905 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
906 // Flush our command buffer
907 // (tell the service to execute up to the flush cmd.)
908 helper_->CommandBufferHelper::Flush();
909 // TODO(piman): Add the FreeEverything() logic here.
912 void GLES2Implementation::Finish() {
913 GPU_CLIENT_SINGLE_THREAD_CHECK();
914 FinishHelper();
917 void GLES2Implementation::ShallowFinishCHROMIUM() {
918 GPU_CLIENT_SINGLE_THREAD_CHECK();
919 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
920 // Flush our command buffer (tell the service to execute up to the flush cmd
921 // and don't return until it completes).
922 helper_->CommandBufferHelper::Finish();
925 void GLES2Implementation::FinishHelper() {
926 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
927 TRACE_EVENT0("gpu", "GLES2::Finish");
928 // Insert the cmd to call glFinish
929 helper_->Finish();
930 // Finish our command buffer
931 // (tell the service to execute up to the Finish cmd and wait for it to
932 // execute.)
933 helper_->CommandBufferHelper::Finish();
936 void GLES2Implementation::SwapBuffers() {
937 GPU_CLIENT_SINGLE_THREAD_CHECK();
938 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
939 // TODO(piman): Strictly speaking we'd want to insert the token after the
940 // swap, but the state update with the updated token might not have happened
941 // by the time the SwapBuffer callback gets called, forcing us to synchronize
942 // with the GPU process more than needed. So instead, make it happen before.
943 // All it means is that we could be slightly looser on the kMaxSwapBuffers
944 // semantics if the client doesn't use the callback mechanism, and by chance
945 // the scheduler yields between the InsertToken and the SwapBuffers.
946 swap_buffers_tokens_.push(helper_->InsertToken());
947 helper_->SwapBuffers();
948 helper_->CommandBufferHelper::Flush();
949 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
950 // compensate for TODO above.
951 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
952 helper_->WaitForToken(swap_buffers_tokens_.front());
953 swap_buffers_tokens_.pop();
957 void GLES2Implementation::GenSharedIdsCHROMIUM(
958 GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) {
959 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenSharedIdsCHROMIUM("
960 << namespace_id << ", " << id_offset << ", " << n << ", " <<
961 static_cast<void*>(ids) << ")");
962 TRACE_EVENT0("gpu", "GLES2::GenSharedIdsCHROMIUM");
963 GLsizei num = n;
964 GLuint* dst = ids;
965 while (num) {
966 ScopedTransferBufferArray<GLint> id_buffer(num, helper_, transfer_buffer_);
967 if (!id_buffer.valid()) {
968 return;
970 helper_->GenSharedIdsCHROMIUM(
971 namespace_id, id_offset, id_buffer.num_elements(),
972 id_buffer.shm_id(), id_buffer.offset());
973 WaitForCmd();
974 memcpy(dst, id_buffer.address(), sizeof(*dst) * id_buffer.num_elements());
975 num -= id_buffer.num_elements();
976 dst += id_buffer.num_elements();
978 GPU_CLIENT_LOG_CODE_BLOCK({
979 for (GLsizei i = 0; i < n; ++i) {
980 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
985 void GLES2Implementation::DeleteSharedIdsCHROMIUM(
986 GLuint namespace_id, GLsizei n, const GLuint* ids) {
987 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteSharedIdsCHROMIUM("
988 << namespace_id << ", " << n << ", "
989 << static_cast<const void*>(ids) << ")");
990 GPU_CLIENT_LOG_CODE_BLOCK({
991 for (GLsizei i = 0; i < n; ++i) {
992 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
995 TRACE_EVENT0("gpu", "GLES2::DeleteSharedIdsCHROMIUM");
996 while (n) {
997 ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
998 if (!id_buffer.valid()) {
999 return;
1001 memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
1002 helper_->DeleteSharedIdsCHROMIUM(
1003 namespace_id, id_buffer.num_elements(),
1004 id_buffer.shm_id(), id_buffer.offset());
1005 WaitForCmd();
1006 n -= id_buffer.num_elements();
1007 ids += id_buffer.num_elements();
1011 void GLES2Implementation::RegisterSharedIdsCHROMIUM(
1012 GLuint namespace_id, GLsizei n, const GLuint* ids) {
1013 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRegisterSharedIdsCHROMIUM("
1014 << namespace_id << ", " << n << ", "
1015 << static_cast<const void*>(ids) << ")");
1016 GPU_CLIENT_LOG_CODE_BLOCK({
1017 for (GLsizei i = 0; i < n; ++i) {
1018 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
1021 TRACE_EVENT0("gpu", "GLES2::RegisterSharedIdsCHROMIUM");
1022 while (n) {
1023 ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
1024 if (!id_buffer.valid()) {
1025 return;
1027 memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
1028 helper_->RegisterSharedIdsCHROMIUM(
1029 namespace_id, id_buffer.num_elements(),
1030 id_buffer.shm_id(), id_buffer.offset());
1031 WaitForCmd();
1032 n -= id_buffer.num_elements();
1033 ids += id_buffer.num_elements();
1037 void GLES2Implementation::BindAttribLocation(
1038 GLuint program, GLuint index, const char* name) {
1039 GPU_CLIENT_SINGLE_THREAD_CHECK();
1040 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
1041 << program << ", " << index << ", " << name << ")");
1042 SetBucketAsString(kResultBucketId, name);
1043 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
1044 helper_->SetBucketSize(kResultBucketId, 0);
1045 CheckGLError();
1048 void GLES2Implementation::BindUniformLocationCHROMIUM(
1049 GLuint program, GLint location, const char* name) {
1050 GPU_CLIENT_SINGLE_THREAD_CHECK();
1051 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1052 << program << ", " << location << ", " << name << ")");
1053 SetBucketAsString(kResultBucketId, name);
1054 helper_->BindUniformLocationCHROMIUMBucket(
1055 program, location, kResultBucketId);
1056 helper_->SetBucketSize(kResultBucketId, 0);
1057 CheckGLError();
1060 void GLES2Implementation::GetVertexAttribPointerv(
1061 GLuint index, GLenum pname, void** ptr) {
1062 GPU_CLIENT_SINGLE_THREAD_CHECK();
1063 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1064 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1065 << static_cast<void*>(ptr) << ")");
1066 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
1067 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1068 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1069 typedef cmds::GetVertexAttribPointerv::Result Result;
1070 Result* result = GetResultAs<Result*>();
1071 if (!result) {
1072 return;
1074 result->SetNumResults(0);
1075 helper_->GetVertexAttribPointerv(
1076 index, pname, GetResultShmId(), GetResultShmOffset());
1077 WaitForCmd();
1078 result->CopyResult(ptr);
1079 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1081 GPU_CLIENT_LOG_CODE_BLOCK({
1082 for (int32 i = 0; i < num_results; ++i) {
1083 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
1086 CheckGLError();
1089 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1090 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1091 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
1092 SetGLError(
1093 GL_INVALID_VALUE,
1094 "glDeleteProgram", "id not created by this context.");
1095 return false;
1097 if (program == current_program_) {
1098 current_program_ = 0;
1100 return true;
1103 void GLES2Implementation::DeleteProgramStub(
1104 GLsizei n, const GLuint* programs) {
1105 DCHECK_EQ(1, n);
1106 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1107 helper_->DeleteProgram(programs[0]);
1110 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1111 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1112 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1113 SetGLError(
1114 GL_INVALID_VALUE,
1115 "glDeleteShader", "id not created by this context.");
1116 return false;
1118 return true;
1121 void GLES2Implementation::DeleteShaderStub(
1122 GLsizei n, const GLuint* shaders) {
1123 DCHECK_EQ(1, n);
1124 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1125 helper_->DeleteShader(shaders[0]);
1129 GLint GLES2Implementation::GetAttribLocationHelper(
1130 GLuint program, const char* name) {
1131 typedef cmds::GetAttribLocation::Result Result;
1132 Result* result = GetResultAs<Result*>();
1133 if (!result) {
1134 return -1;
1136 *result = -1;
1137 SetBucketAsCString(kResultBucketId, name);
1138 helper_->GetAttribLocation(
1139 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1140 WaitForCmd();
1141 helper_->SetBucketSize(kResultBucketId, 0);
1142 return *result;
1145 GLint GLES2Implementation::GetAttribLocation(
1146 GLuint program, const char* name) {
1147 GPU_CLIENT_SINGLE_THREAD_CHECK();
1148 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1149 << ", " << name << ")");
1150 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1151 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1152 this, program, name);
1153 GPU_CLIENT_LOG("returned " << loc);
1154 CheckGLError();
1155 return loc;
1158 GLint GLES2Implementation::GetUniformLocationHelper(
1159 GLuint program, const char* name) {
1160 typedef cmds::GetUniformLocation::Result Result;
1161 Result* result = GetResultAs<Result*>();
1162 if (!result) {
1163 return -1;
1165 *result = -1;
1166 SetBucketAsCString(kResultBucketId, name);
1167 helper_->GetUniformLocation(program, kResultBucketId,
1168 GetResultShmId(), GetResultShmOffset());
1169 WaitForCmd();
1170 helper_->SetBucketSize(kResultBucketId, 0);
1171 return *result;
1174 GLint GLES2Implementation::GetUniformLocation(
1175 GLuint program, const char* name) {
1176 GPU_CLIENT_SINGLE_THREAD_CHECK();
1177 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1178 << ", " << name << ")");
1179 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1180 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1181 this, program, name);
1182 GPU_CLIENT_LOG("returned " << loc);
1183 CheckGLError();
1184 return loc;
1187 bool GLES2Implementation::GetProgramivHelper(
1188 GLuint program, GLenum pname, GLint* params) {
1189 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1190 this, program, pname, params);
1191 GPU_CLIENT_LOG_CODE_BLOCK({
1192 if (got_value) {
1193 GPU_CLIENT_LOG(" 0: " << *params);
1196 return got_value;
1199 void GLES2Implementation::LinkProgram(GLuint program) {
1200 GPU_CLIENT_SINGLE_THREAD_CHECK();
1201 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1202 helper_->LinkProgram(program);
1203 share_group_->program_info_manager()->CreateInfo(program);
1204 CheckGLError();
1207 void GLES2Implementation::ShaderBinary(
1208 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1209 GLsizei length) {
1210 GPU_CLIENT_SINGLE_THREAD_CHECK();
1211 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1212 << static_cast<const void*>(shaders) << ", "
1213 << GLES2Util::GetStringEnum(binaryformat) << ", "
1214 << static_cast<const void*>(binary) << ", "
1215 << length << ")");
1216 if (n < 0) {
1217 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1218 return;
1220 if (length < 0) {
1221 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1222 return;
1224 // TODO(gman): ShaderBinary should use buckets.
1225 unsigned int shader_id_size = n * sizeof(*shaders);
1226 ScopedTransferBufferArray<GLint> buffer(
1227 shader_id_size + length, helper_, transfer_buffer_);
1228 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1229 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1230 return;
1232 void* shader_ids = buffer.elements();
1233 void* shader_data = buffer.elements() + shader_id_size;
1234 memcpy(shader_ids, shaders, shader_id_size);
1235 memcpy(shader_data, binary, length);
1236 helper_->ShaderBinary(
1238 buffer.shm_id(),
1239 buffer.offset(),
1240 binaryformat,
1241 buffer.shm_id(),
1242 buffer.offset() + shader_id_size,
1243 length);
1244 CheckGLError();
1247 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1248 GPU_CLIENT_SINGLE_THREAD_CHECK();
1249 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1250 << GLES2Util::GetStringPixelStore(pname) << ", "
1251 << param << ")");
1252 switch (pname) {
1253 case GL_PACK_ALIGNMENT:
1254 pack_alignment_ = param;
1255 break;
1256 case GL_UNPACK_ALIGNMENT:
1257 unpack_alignment_ = param;
1258 break;
1259 case GL_UNPACK_ROW_LENGTH_EXT:
1260 unpack_row_length_ = param;
1261 return;
1262 case GL_UNPACK_SKIP_ROWS_EXT:
1263 unpack_skip_rows_ = param;
1264 return;
1265 case GL_UNPACK_SKIP_PIXELS_EXT:
1266 unpack_skip_pixels_ = param;
1267 return;
1268 case GL_UNPACK_FLIP_Y_CHROMIUM:
1269 unpack_flip_y_ = (param != 0);
1270 break;
1271 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1272 pack_reverse_row_order_ =
1273 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1274 break;
1275 default:
1276 break;
1278 helper_->PixelStorei(pname, param);
1279 CheckGLError();
1282 void GLES2Implementation::VertexAttribPointer(
1283 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1284 const void* ptr) {
1285 GPU_CLIENT_SINGLE_THREAD_CHECK();
1286 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1287 << index << ", "
1288 << size << ", "
1289 << GLES2Util::GetStringVertexAttribType(type) << ", "
1290 << GLES2Util::GetStringBool(normalized) << ", "
1291 << stride << ", "
1292 << static_cast<const void*>(ptr) << ")");
1293 // Record the info on the client side.
1294 if (!vertex_array_object_manager_->SetAttribPointer(
1295 bound_array_buffer_id_, index, size, type, normalized, stride, ptr)) {
1296 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1297 "client side arrays are not allowed in vertex array objects.");
1298 return;
1300 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1301 if (bound_array_buffer_id_ != 0) {
1302 // Only report NON client side buffers to the service.
1303 if (!ValidateOffset("glVertexAttribPointer",
1304 reinterpret_cast<GLintptr>(ptr))) {
1305 return;
1307 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1308 ToGLuint(ptr));
1310 #else // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1311 if (!ValidateOffset("glVertexAttribPointer",
1312 reinterpret_cast<GLintptr>(ptr))) {
1313 return;
1315 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1316 ToGLuint(ptr));
1317 #endif // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1318 CheckGLError();
1321 void GLES2Implementation::VertexAttribDivisorANGLE(
1322 GLuint index, GLuint divisor) {
1323 GPU_CLIENT_SINGLE_THREAD_CHECK();
1324 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1325 << index << ", "
1326 << divisor << ") ");
1327 // Record the info on the client side.
1328 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1329 helper_->VertexAttribDivisorANGLE(index, divisor);
1330 CheckGLError();
1333 void GLES2Implementation::ShaderSource(
1334 GLuint shader,
1335 GLsizei count,
1336 const GLchar* const* source,
1337 const GLint* length) {
1338 GPU_CLIENT_SINGLE_THREAD_CHECK();
1339 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderSource("
1340 << shader << ", " << count << ", "
1341 << static_cast<const void*>(source) << ", "
1342 << static_cast<const void*>(length) << ")");
1343 GPU_CLIENT_LOG_CODE_BLOCK({
1344 for (GLsizei ii = 0; ii < count; ++ii) {
1345 if (source[ii]) {
1346 if (length && length[ii] >= 0) {
1347 std::string str(source[ii], length[ii]);
1348 GPU_CLIENT_LOG(" " << ii << ": ---\n" << str << "\n---");
1349 } else {
1350 GPU_CLIENT_LOG(" " << ii << ": ---\n" << source[ii] << "\n---");
1352 } else {
1353 GPU_CLIENT_LOG(" " << ii << ": NULL");
1357 if (count < 0) {
1358 SetGLError(GL_INVALID_VALUE, "glShaderSource", "count < 0");
1359 return;
1361 if (shader == 0) {
1362 SetGLError(GL_INVALID_VALUE, "glShaderSource", "shader == 0");
1363 return;
1366 // Compute the total size.
1367 uint32 total_size = 1;
1368 for (GLsizei ii = 0; ii < count; ++ii) {
1369 if (source[ii]) {
1370 total_size += (length && length[ii] >= 0) ?
1371 static_cast<size_t>(length[ii]) : strlen(source[ii]);
1375 // Concatenate all the strings in to a bucket on the service.
1376 helper_->SetBucketSize(kResultBucketId, total_size);
1377 uint32 offset = 0;
1378 for (GLsizei ii = 0; ii <= count; ++ii) {
1379 const char* src = ii < count ? source[ii] : "";
1380 if (src) {
1381 uint32 size = ii < count ?
1382 (length ? static_cast<size_t>(length[ii]) : strlen(src)) : 1;
1383 while (size) {
1384 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1385 if (!buffer.valid()) {
1386 return;
1388 memcpy(buffer.address(), src, buffer.size());
1389 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
1390 buffer.shm_id(), buffer.offset());
1391 offset += buffer.size();
1392 src += buffer.size();
1393 size -= buffer.size();
1398 DCHECK_EQ(total_size, offset);
1400 helper_->ShaderSourceBucket(shader, kResultBucketId);
1401 helper_->SetBucketSize(kResultBucketId, 0);
1402 CheckGLError();
1405 void GLES2Implementation::BufferDataHelper(
1406 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1407 if (!ValidateSize("glBufferData", size))
1408 return;
1410 GLuint buffer_id;
1411 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1412 if (!buffer_id) {
1413 return;
1416 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1417 if (buffer)
1418 RemoveTransferBuffer(buffer);
1420 // Create new buffer.
1421 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1422 DCHECK(buffer);
1423 if (buffer->address() && data)
1424 memcpy(buffer->address(), data, size);
1425 return;
1428 if (size == 0) {
1429 return;
1432 // If there is no data just send BufferData
1433 if (!data) {
1434 helper_->BufferData(target, size, 0, 0, usage);
1435 return;
1438 // See if we can send all at once.
1439 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1440 if (!buffer.valid()) {
1441 return;
1444 if (buffer.size() >= static_cast<unsigned int>(size)) {
1445 memcpy(buffer.address(), data, size);
1446 helper_->BufferData(
1447 target,
1448 size,
1449 buffer.shm_id(),
1450 buffer.offset(),
1451 usage);
1452 return;
1455 // Make the buffer with BufferData then send via BufferSubData
1456 helper_->BufferData(target, size, 0, 0, usage);
1457 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1458 CheckGLError();
1461 void GLES2Implementation::BufferData(
1462 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1463 GPU_CLIENT_SINGLE_THREAD_CHECK();
1464 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1465 << GLES2Util::GetStringBufferTarget(target) << ", "
1466 << size << ", "
1467 << static_cast<const void*>(data) << ", "
1468 << GLES2Util::GetStringBufferUsage(usage) << ")");
1469 BufferDataHelper(target, size, data, usage);
1470 CheckGLError();
1473 void GLES2Implementation::BufferSubDataHelper(
1474 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1475 if (size == 0) {
1476 return;
1479 if (!ValidateSize("glBufferSubData", size) ||
1480 !ValidateOffset("glBufferSubData", offset)) {
1481 return;
1484 GLuint buffer_id;
1485 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1486 if (!buffer_id) {
1487 return;
1489 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1490 if (!buffer) {
1491 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1492 return;
1495 int32 end = 0;
1496 int32 buffer_size = buffer->size();
1497 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1498 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1499 return;
1502 if (buffer->address() && data)
1503 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1504 return;
1507 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1508 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1511 void GLES2Implementation::BufferSubDataHelperImpl(
1512 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1513 ScopedTransferBufferPtr* buffer) {
1514 DCHECK(buffer);
1515 DCHECK_GT(size, 0);
1517 const int8* source = static_cast<const int8*>(data);
1518 while (size) {
1519 if (!buffer->valid() || buffer->size() == 0) {
1520 buffer->Reset(size);
1521 if (!buffer->valid()) {
1522 return;
1525 memcpy(buffer->address(), source, buffer->size());
1526 helper_->BufferSubData(
1527 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1528 offset += buffer->size();
1529 source += buffer->size();
1530 size -= buffer->size();
1531 buffer->Release();
1535 void GLES2Implementation::BufferSubData(
1536 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1537 GPU_CLIENT_SINGLE_THREAD_CHECK();
1538 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1539 << GLES2Util::GetStringBufferTarget(target) << ", "
1540 << offset << ", " << size << ", "
1541 << static_cast<const void*>(data) << ")");
1542 BufferSubDataHelper(target, offset, size, data);
1543 CheckGLError();
1546 void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
1547 int32 token = buffer->last_usage_token();
1548 uint32 async_token = buffer->last_async_upload_token();
1550 if (async_token) {
1551 if (HasAsyncUploadTokenPassed(async_token)) {
1552 buffer_tracker_->Free(buffer);
1553 } else {
1554 detached_async_upload_memory_.push_back(
1555 std::make_pair(buffer->address(), async_token));
1556 buffer_tracker_->Unmanage(buffer);
1558 } else if (token) {
1559 if (helper_->HasTokenPassed(token))
1560 buffer_tracker_->Free(buffer);
1561 else
1562 buffer_tracker_->FreePendingToken(buffer, token);
1563 } else {
1564 buffer_tracker_->Free(buffer);
1567 buffer_tracker_->RemoveBuffer(buffer->id());
1570 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1571 GLenum target,
1572 const char* function_name,
1573 GLuint* buffer_id) {
1574 *buffer_id = 0;
1576 switch (target) {
1577 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1578 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1579 break;
1580 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1581 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1582 break;
1583 default:
1584 // Unknown target
1585 return false;
1587 if (!*buffer_id) {
1588 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1590 return true;
1593 BufferTracker::Buffer*
1594 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1595 GLuint buffer_id,
1596 const char* function_name,
1597 GLuint offset, GLsizei size) {
1598 DCHECK(buffer_id);
1599 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1600 if (!buffer) {
1601 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1602 return NULL;
1604 if (buffer->mapped()) {
1605 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1606 return NULL;
1608 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1609 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1610 return NULL;
1612 return buffer;
1615 void GLES2Implementation::CompressedTexImage2D(
1616 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1617 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1618 GPU_CLIENT_SINGLE_THREAD_CHECK();
1619 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1620 << GLES2Util::GetStringTextureTarget(target) << ", "
1621 << level << ", "
1622 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1623 << width << ", " << height << ", " << border << ", "
1624 << image_size << ", "
1625 << static_cast<const void*>(data) << ")");
1626 if (width < 0 || height < 0 || level < 0) {
1627 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1628 return;
1630 if (border != 0) {
1631 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "border != 0");
1632 return;
1634 if (height == 0 || width == 0) {
1635 return;
1637 // If there's a pixel unpack buffer bound use it when issuing
1638 // CompressedTexImage2D.
1639 if (bound_pixel_unpack_transfer_buffer_id_) {
1640 GLuint offset = ToGLuint(data);
1641 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1642 bound_pixel_unpack_transfer_buffer_id_,
1643 "glCompressedTexImage2D", offset, image_size);
1644 if (buffer && buffer->shm_id() != -1) {
1645 helper_->CompressedTexImage2D(
1646 target, level, internalformat, width, height, image_size,
1647 buffer->shm_id(), buffer->shm_offset() + offset);
1648 buffer->set_last_usage_token(helper_->InsertToken());
1650 return;
1652 SetBucketContents(kResultBucketId, data, image_size);
1653 helper_->CompressedTexImage2DBucket(
1654 target, level, internalformat, width, height, kResultBucketId);
1655 // Free the bucket. This is not required but it does free up the memory.
1656 // and we don't have to wait for the result so from the client's perspective
1657 // it's cheap.
1658 helper_->SetBucketSize(kResultBucketId, 0);
1659 CheckGLError();
1662 void GLES2Implementation::CompressedTexSubImage2D(
1663 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1664 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1665 GPU_CLIENT_SINGLE_THREAD_CHECK();
1666 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1667 << GLES2Util::GetStringTextureTarget(target) << ", "
1668 << level << ", "
1669 << xoffset << ", " << yoffset << ", "
1670 << width << ", " << height << ", "
1671 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1672 << image_size << ", "
1673 << static_cast<const void*>(data) << ")");
1674 if (width < 0 || height < 0 || level < 0) {
1675 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1676 return;
1678 // If there's a pixel unpack buffer bound use it when issuing
1679 // CompressedTexSubImage2D.
1680 if (bound_pixel_unpack_transfer_buffer_id_) {
1681 GLuint offset = ToGLuint(data);
1682 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1683 bound_pixel_unpack_transfer_buffer_id_,
1684 "glCompressedTexSubImage2D", offset, image_size);
1685 if (buffer && buffer->shm_id() != -1) {
1686 helper_->CompressedTexSubImage2D(
1687 target, level, xoffset, yoffset, width, height, format, image_size,
1688 buffer->shm_id(), buffer->shm_offset() + offset);
1689 buffer->set_last_usage_token(helper_->InsertToken());
1690 CheckGLError();
1692 return;
1694 SetBucketContents(kResultBucketId, data, image_size);
1695 helper_->CompressedTexSubImage2DBucket(
1696 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1697 // Free the bucket. This is not required but it does free up the memory.
1698 // and we don't have to wait for the result so from the client's perspective
1699 // it's cheap.
1700 helper_->SetBucketSize(kResultBucketId, 0);
1701 CheckGLError();
1704 namespace {
1706 void CopyRectToBuffer(
1707 const void* pixels,
1708 uint32 height,
1709 uint32 unpadded_row_size,
1710 uint32 pixels_padded_row_size,
1711 bool flip_y,
1712 void* buffer,
1713 uint32 buffer_padded_row_size) {
1714 const int8* source = static_cast<const int8*>(pixels);
1715 int8* dest = static_cast<int8*>(buffer);
1716 if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
1717 if (flip_y) {
1718 dest += buffer_padded_row_size * (height - 1);
1720 // the last row is copied unpadded at the end
1721 for (; height > 1; --height) {
1722 memcpy(dest, source, buffer_padded_row_size);
1723 if (flip_y) {
1724 dest -= buffer_padded_row_size;
1725 } else {
1726 dest += buffer_padded_row_size;
1728 source += pixels_padded_row_size;
1730 memcpy(dest, source, unpadded_row_size);
1731 } else {
1732 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
1733 memcpy(dest, source, size);
1737 } // anonymous namespace
1739 void GLES2Implementation::TexImage2D(
1740 GLenum target, GLint level, GLint internalformat, GLsizei width,
1741 GLsizei height, GLint border, GLenum format, GLenum type,
1742 const void* pixels) {
1743 GPU_CLIENT_SINGLE_THREAD_CHECK();
1744 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1745 << GLES2Util::GetStringTextureTarget(target) << ", "
1746 << level << ", "
1747 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1748 << width << ", " << height << ", " << border << ", "
1749 << GLES2Util::GetStringTextureFormat(format) << ", "
1750 << GLES2Util::GetStringPixelType(type) << ", "
1751 << static_cast<const void*>(pixels) << ")");
1752 if (level < 0 || height < 0 || width < 0) {
1753 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
1754 return;
1756 if (border != 0) {
1757 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
1758 return;
1760 uint32 size;
1761 uint32 unpadded_row_size;
1762 uint32 padded_row_size;
1763 if (!GLES2Util::ComputeImageDataSizes(
1764 width, height, format, type, unpack_alignment_, &size,
1765 &unpadded_row_size, &padded_row_size)) {
1766 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
1767 return;
1770 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1771 if (bound_pixel_unpack_transfer_buffer_id_) {
1772 GLuint offset = ToGLuint(pixels);
1773 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1774 bound_pixel_unpack_transfer_buffer_id_,
1775 "glTexImage2D", offset, size);
1776 if (buffer && buffer->shm_id() != -1) {
1777 helper_->TexImage2D(
1778 target, level, internalformat, width, height, format, type,
1779 buffer->shm_id(), buffer->shm_offset() + offset);
1780 buffer->set_last_usage_token(helper_->InsertToken());
1781 CheckGLError();
1783 return;
1786 // If there's no data just issue TexImage2D
1787 if (!pixels) {
1788 helper_->TexImage2D(
1789 target, level, internalformat, width, height, format, type,
1790 0, 0);
1791 CheckGLError();
1792 return;
1795 // compute the advance bytes per row for the src pixels
1796 uint32 src_padded_row_size;
1797 if (unpack_row_length_ > 0) {
1798 if (!GLES2Util::ComputeImagePaddedRowSize(
1799 unpack_row_length_, format, type, unpack_alignment_,
1800 &src_padded_row_size)) {
1801 SetGLError(
1802 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1803 return;
1805 } else {
1806 src_padded_row_size = padded_row_size;
1809 // advance pixels pointer past the skip rows and skip pixels
1810 pixels = reinterpret_cast<const int8*>(pixels) +
1811 unpack_skip_rows_ * src_padded_row_size;
1812 if (unpack_skip_pixels_) {
1813 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1814 pixels = reinterpret_cast<const int8*>(pixels) +
1815 unpack_skip_pixels_ * group_size;
1818 // Check if we can send it all at once.
1819 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1820 if (!buffer.valid()) {
1821 return;
1824 if (buffer.size() >= size) {
1825 CopyRectToBuffer(
1826 pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
1827 buffer.address(), padded_row_size);
1828 helper_->TexImage2D(
1829 target, level, internalformat, width, height, format, type,
1830 buffer.shm_id(), buffer.offset());
1831 CheckGLError();
1832 return;
1835 // No, so send it using TexSubImage2D.
1836 helper_->TexImage2D(
1837 target, level, internalformat, width, height, format, type,
1838 0, 0);
1839 TexSubImage2DImpl(
1840 target, level, 0, 0, width, height, format, type, unpadded_row_size,
1841 pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
1842 CheckGLError();
1845 void GLES2Implementation::TexSubImage2D(
1846 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1847 GLsizei height, GLenum format, GLenum type, const void* pixels) {
1848 GPU_CLIENT_SINGLE_THREAD_CHECK();
1849 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1850 << GLES2Util::GetStringTextureTarget(target) << ", "
1851 << level << ", "
1852 << xoffset << ", " << yoffset << ", "
1853 << width << ", " << height << ", "
1854 << GLES2Util::GetStringTextureFormat(format) << ", "
1855 << GLES2Util::GetStringPixelType(type) << ", "
1856 << static_cast<const void*>(pixels) << ")");
1858 if (level < 0 || height < 0 || width < 0) {
1859 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
1860 return;
1862 if (height == 0 || width == 0) {
1863 return;
1866 uint32 temp_size;
1867 uint32 unpadded_row_size;
1868 uint32 padded_row_size;
1869 if (!GLES2Util::ComputeImageDataSizes(
1870 width, height, format, type, unpack_alignment_, &temp_size,
1871 &unpadded_row_size, &padded_row_size)) {
1872 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
1873 return;
1876 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1877 if (bound_pixel_unpack_transfer_buffer_id_) {
1878 GLuint offset = ToGLuint(pixels);
1879 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1880 bound_pixel_unpack_transfer_buffer_id_,
1881 "glTexSubImage2D", offset, temp_size);
1882 if (buffer && buffer->shm_id() != -1) {
1883 helper_->TexSubImage2D(
1884 target, level, xoffset, yoffset, width, height, format, type,
1885 buffer->shm_id(), buffer->shm_offset() + offset, false);
1886 buffer->set_last_usage_token(helper_->InsertToken());
1887 CheckGLError();
1889 return;
1892 // compute the advance bytes per row for the src pixels
1893 uint32 src_padded_row_size;
1894 if (unpack_row_length_ > 0) {
1895 if (!GLES2Util::ComputeImagePaddedRowSize(
1896 unpack_row_length_, format, type, unpack_alignment_,
1897 &src_padded_row_size)) {
1898 SetGLError(
1899 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1900 return;
1902 } else {
1903 src_padded_row_size = padded_row_size;
1906 // advance pixels pointer past the skip rows and skip pixels
1907 pixels = reinterpret_cast<const int8*>(pixels) +
1908 unpack_skip_rows_ * src_padded_row_size;
1909 if (unpack_skip_pixels_) {
1910 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1911 pixels = reinterpret_cast<const int8*>(pixels) +
1912 unpack_skip_pixels_ * group_size;
1915 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
1916 TexSubImage2DImpl(
1917 target, level, xoffset, yoffset, width, height, format, type,
1918 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
1919 padded_row_size);
1920 CheckGLError();
1923 static GLint ComputeNumRowsThatFitInBuffer(
1924 uint32 padded_row_size, uint32 unpadded_row_size,
1925 unsigned int size) {
1926 DCHECK_GE(unpadded_row_size, 0u);
1927 if (padded_row_size == 0) {
1928 return 1;
1930 GLint num_rows = size / padded_row_size;
1931 return num_rows + (size - num_rows * padded_row_size) / unpadded_row_size;
1934 void GLES2Implementation::TexSubImage2DImpl(
1935 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1936 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
1937 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
1938 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
1939 DCHECK(buffer);
1940 DCHECK_GE(level, 0);
1941 DCHECK_GT(height, 0);
1942 DCHECK_GT(width, 0);
1944 const int8* source = reinterpret_cast<const int8*>(pixels);
1945 GLint original_yoffset = yoffset;
1946 // Transfer by rows.
1947 while (height) {
1948 unsigned int desired_size =
1949 buffer_padded_row_size * (height - 1) + unpadded_row_size;
1950 if (!buffer->valid() || buffer->size() == 0) {
1951 buffer->Reset(desired_size);
1952 if (!buffer->valid()) {
1953 return;
1957 GLint num_rows = ComputeNumRowsThatFitInBuffer(
1958 buffer_padded_row_size, unpadded_row_size, buffer->size());
1959 num_rows = std::min(num_rows, height);
1960 CopyRectToBuffer(
1961 source, num_rows, unpadded_row_size, pixels_padded_row_size,
1962 unpack_flip_y_, buffer->address(), buffer_padded_row_size);
1963 GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
1964 helper_->TexSubImage2D(
1965 target, level, xoffset, y, width, num_rows, format, type,
1966 buffer->shm_id(), buffer->offset(), internal);
1967 buffer->Release();
1968 yoffset += num_rows;
1969 source += num_rows * pixels_padded_row_size;
1970 height -= num_rows;
1974 bool GLES2Implementation::GetActiveAttribHelper(
1975 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1976 GLenum* type, char* name) {
1977 // Clear the bucket so if the command fails nothing will be in it.
1978 helper_->SetBucketSize(kResultBucketId, 0);
1979 typedef cmds::GetActiveAttrib::Result Result;
1980 Result* result = GetResultAs<Result*>();
1981 if (!result) {
1982 return false;
1984 // Set as failed so if the command fails we'll recover.
1985 result->success = false;
1986 helper_->GetActiveAttrib(program, index, kResultBucketId,
1987 GetResultShmId(), GetResultShmOffset());
1988 WaitForCmd();
1989 if (result->success) {
1990 if (size) {
1991 *size = result->size;
1993 if (type) {
1994 *type = result->type;
1996 if (length || name) {
1997 std::vector<int8> str;
1998 GetBucketContents(kResultBucketId, &str);
1999 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2000 std::max(static_cast<size_t>(0),
2001 str.size() - 1));
2002 if (length) {
2003 *length = max_size;
2005 if (name && bufsize > 0) {
2006 memcpy(name, &str[0], max_size);
2007 name[max_size] = '\0';
2011 return result->success != 0;
2014 void GLES2Implementation::GetActiveAttrib(
2015 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2016 GLenum* type, char* name) {
2017 GPU_CLIENT_SINGLE_THREAD_CHECK();
2018 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
2019 << program << ", " << index << ", " << bufsize << ", "
2020 << static_cast<const void*>(length) << ", "
2021 << static_cast<const void*>(size) << ", "
2022 << static_cast<const void*>(type) << ", "
2023 << static_cast<const void*>(name) << ", ");
2024 if (bufsize < 0) {
2025 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
2026 return;
2028 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
2029 bool success = share_group_->program_info_manager()->GetActiveAttrib(
2030 this, program, index, bufsize, length, size, type, name);
2031 if (success) {
2032 if (size) {
2033 GPU_CLIENT_LOG(" size: " << *size);
2035 if (type) {
2036 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2038 if (name) {
2039 GPU_CLIENT_LOG(" name: " << name);
2042 CheckGLError();
2045 bool GLES2Implementation::GetActiveUniformHelper(
2046 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2047 GLenum* type, char* name) {
2048 // Clear the bucket so if the command fails nothing will be in it.
2049 helper_->SetBucketSize(kResultBucketId, 0);
2050 typedef cmds::GetActiveUniform::Result Result;
2051 Result* result = GetResultAs<Result*>();
2052 if (!result) {
2053 return false;
2055 // Set as failed so if the command fails we'll recover.
2056 result->success = false;
2057 helper_->GetActiveUniform(program, index, kResultBucketId,
2058 GetResultShmId(), GetResultShmOffset());
2059 WaitForCmd();
2060 if (result->success) {
2061 if (size) {
2062 *size = result->size;
2064 if (type) {
2065 *type = result->type;
2067 if (length || name) {
2068 std::vector<int8> str;
2069 GetBucketContents(kResultBucketId, &str);
2070 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2071 std::max(static_cast<size_t>(0),
2072 str.size() - 1));
2073 if (length) {
2074 *length = max_size;
2076 if (name && bufsize > 0) {
2077 memcpy(name, &str[0], max_size);
2078 name[max_size] = '\0';
2082 return result->success != 0;
2085 void GLES2Implementation::GetActiveUniform(
2086 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2087 GLenum* type, char* name) {
2088 GPU_CLIENT_SINGLE_THREAD_CHECK();
2089 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2090 << program << ", " << index << ", " << bufsize << ", "
2091 << static_cast<const void*>(length) << ", "
2092 << static_cast<const void*>(size) << ", "
2093 << static_cast<const void*>(type) << ", "
2094 << static_cast<const void*>(name) << ", ");
2095 if (bufsize < 0) {
2096 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2097 return;
2099 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2100 bool success = share_group_->program_info_manager()->GetActiveUniform(
2101 this, program, index, bufsize, length, size, type, name);
2102 if (success) {
2103 if (size) {
2104 GPU_CLIENT_LOG(" size: " << *size);
2106 if (type) {
2107 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2109 if (name) {
2110 GPU_CLIENT_LOG(" name: " << name);
2113 CheckGLError();
2116 void GLES2Implementation::GetAttachedShaders(
2117 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
2118 GPU_CLIENT_SINGLE_THREAD_CHECK();
2119 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2120 << program << ", " << maxcount << ", "
2121 << static_cast<const void*>(count) << ", "
2122 << static_cast<const void*>(shaders) << ", ");
2123 if (maxcount < 0) {
2124 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
2125 return;
2127 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2128 typedef cmds::GetAttachedShaders::Result Result;
2129 uint32 size = Result::ComputeSize(maxcount);
2130 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
2131 if (!result) {
2132 return;
2134 result->SetNumResults(0);
2135 helper_->GetAttachedShaders(
2136 program,
2137 transfer_buffer_->GetShmId(),
2138 transfer_buffer_->GetOffset(result),
2139 size);
2140 int32 token = helper_->InsertToken();
2141 WaitForCmd();
2142 if (count) {
2143 *count = result->GetNumResults();
2145 result->CopyResult(shaders);
2146 GPU_CLIENT_LOG_CODE_BLOCK({
2147 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2148 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2151 transfer_buffer_->FreePendingToken(result, token);
2152 CheckGLError();
2155 void GLES2Implementation::GetShaderPrecisionFormat(
2156 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
2157 GPU_CLIENT_SINGLE_THREAD_CHECK();
2158 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2159 << GLES2Util::GetStringShaderType(shadertype) << ", "
2160 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
2161 << static_cast<const void*>(range) << ", "
2162 << static_cast<const void*>(precision) << ", ");
2163 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2164 typedef cmds::GetShaderPrecisionFormat::Result Result;
2165 Result* result = GetResultAs<Result*>();
2166 if (!result) {
2167 return;
2170 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
2171 GLStaticState::ShaderPrecisionMap::iterator i =
2172 static_state_.shader_precisions.find(key);
2173 if (i != static_state_.shader_precisions.end()) {
2174 *result = i->second;
2175 } else {
2176 result->success = false;
2177 helper_->GetShaderPrecisionFormat(
2178 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
2179 WaitForCmd();
2180 if (result->success)
2181 static_state_.shader_precisions[key] = *result;
2184 if (result->success) {
2185 if (range) {
2186 range[0] = result->min_range;
2187 range[1] = result->max_range;
2188 GPU_CLIENT_LOG(" min_range: " << range[0]);
2189 GPU_CLIENT_LOG(" min_range: " << range[1]);
2191 if (precision) {
2192 precision[0] = result->precision;
2193 GPU_CLIENT_LOG(" min_range: " << precision[0]);
2196 CheckGLError();
2199 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
2200 const char* result = NULL;
2201 // Clears the bucket so if the command fails nothing will be in it.
2202 helper_->SetBucketSize(kResultBucketId, 0);
2203 helper_->GetString(name, kResultBucketId);
2204 std::string str;
2205 if (GetBucketAsString(kResultBucketId, &str)) {
2206 // Adds extensions implemented on client side only.
2207 switch (name) {
2208 case GL_EXTENSIONS:
2209 str += std::string(str.empty() ? "" : " ") +
2210 "GL_CHROMIUM_flipy "
2211 "GL_EXT_unpack_subimage "
2212 "GL_CHROMIUM_map_sub";
2213 if (capabilities_.map_image) {
2214 // The first space character is intentional.
2215 str += " GL_CHROMIUM_map_image";
2217 if (capabilities_.future_sync_points)
2218 str += " GL_CHROMIUM_future_sync_point";
2219 break;
2220 default:
2221 break;
2224 // Because of WebGL the extensions can change. We have to cache each unique
2225 // result since we don't know when the client will stop referring to a
2226 // previous one it queries.
2227 GLStringMap::iterator it = gl_strings_.find(name);
2228 if (it == gl_strings_.end()) {
2229 std::set<std::string> strings;
2230 std::pair<GLStringMap::iterator, bool> insert_result =
2231 gl_strings_.insert(std::make_pair(name, strings));
2232 DCHECK(insert_result.second);
2233 it = insert_result.first;
2235 std::set<std::string>& string_set = it->second;
2236 std::set<std::string>::const_iterator sit = string_set.find(str);
2237 if (sit != string_set.end()) {
2238 result = sit->c_str();
2239 } else {
2240 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2241 string_set.insert(str);
2242 DCHECK(insert_result.second);
2243 result = insert_result.first->c_str();
2246 return reinterpret_cast<const GLubyte*>(result);
2249 const GLubyte* GLES2Implementation::GetString(GLenum name) {
2250 GPU_CLIENT_SINGLE_THREAD_CHECK();
2251 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2252 << GLES2Util::GetStringStringType(name) << ")");
2253 TRACE_EVENT0("gpu", "GLES2::GetString");
2254 const GLubyte* result = GetStringHelper(name);
2255 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
2256 CheckGLError();
2257 return result;
2260 void GLES2Implementation::GetUniformfv(
2261 GLuint program, GLint location, GLfloat* params) {
2262 GPU_CLIENT_SINGLE_THREAD_CHECK();
2263 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2264 << program << ", " << location << ", "
2265 << static_cast<const void*>(params) << ")");
2266 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2267 typedef cmds::GetUniformfv::Result Result;
2268 Result* result = GetResultAs<Result*>();
2269 if (!result) {
2270 return;
2272 result->SetNumResults(0);
2273 helper_->GetUniformfv(
2274 program, location, GetResultShmId(), GetResultShmOffset());
2275 WaitForCmd();
2276 result->CopyResult(params);
2277 GPU_CLIENT_LOG_CODE_BLOCK({
2278 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2279 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2282 CheckGLError();
2285 void GLES2Implementation::GetUniformiv(
2286 GLuint program, GLint location, GLint* params) {
2287 GPU_CLIENT_SINGLE_THREAD_CHECK();
2288 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2289 << program << ", " << location << ", "
2290 << static_cast<const void*>(params) << ")");
2291 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2292 typedef cmds::GetUniformiv::Result Result;
2293 Result* result = GetResultAs<Result*>();
2294 if (!result) {
2295 return;
2297 result->SetNumResults(0);
2298 helper_->GetUniformiv(
2299 program, location, GetResultShmId(), GetResultShmOffset());
2300 WaitForCmd();
2301 GetResultAs<cmds::GetUniformfv::Result*>()->CopyResult(params);
2302 GPU_CLIENT_LOG_CODE_BLOCK({
2303 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2304 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2307 CheckGLError();
2310 void GLES2Implementation::ReadPixels(
2311 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
2312 GLenum type, void* pixels) {
2313 GPU_CLIENT_SINGLE_THREAD_CHECK();
2314 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2315 << xoffset << ", " << yoffset << ", "
2316 << width << ", " << height << ", "
2317 << GLES2Util::GetStringReadPixelFormat(format) << ", "
2318 << GLES2Util::GetStringPixelType(type) << ", "
2319 << static_cast<const void*>(pixels) << ")");
2320 if (width < 0 || height < 0) {
2321 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
2322 return;
2324 if (width == 0 || height == 0) {
2325 return;
2328 // glReadPixel pads the size of each row of pixels by an amount specified by
2329 // glPixelStorei. So, we have to take that into account both in the fact that
2330 // the pixels returned from the ReadPixel command will include that padding
2331 // and that when we copy the results to the user's buffer we need to not
2332 // write those padding bytes but leave them as they are.
2334 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2335 typedef cmds::ReadPixels::Result Result;
2337 int8* dest = reinterpret_cast<int8*>(pixels);
2338 uint32 temp_size;
2339 uint32 unpadded_row_size;
2340 uint32 padded_row_size;
2341 if (!GLES2Util::ComputeImageDataSizes(
2342 width, 2, format, type, pack_alignment_, &temp_size, &unpadded_row_size,
2343 &padded_row_size)) {
2344 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
2345 return;
2348 if (bound_pixel_pack_transfer_buffer_id_) {
2349 GLuint offset = ToGLuint(pixels);
2350 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2351 bound_pixel_pack_transfer_buffer_id_,
2352 "glReadPixels", offset, padded_row_size * height);
2353 if (buffer && buffer->shm_id() != -1) {
2354 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
2355 buffer->shm_id(), buffer->shm_offset(),
2356 0, 0, true);
2357 CheckGLError();
2359 return;
2362 if (!pixels) {
2363 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
2364 return;
2367 // Transfer by rows.
2368 // The max rows we can transfer.
2369 while (height) {
2370 GLsizei desired_size = padded_row_size * height - 1 + unpadded_row_size;
2371 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
2372 if (!buffer.valid()) {
2373 return;
2375 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2376 padded_row_size, unpadded_row_size, buffer.size());
2377 num_rows = std::min(num_rows, height);
2378 // NOTE: We must look up the address of the result area AFTER allocation
2379 // of the transfer buffer since the transfer buffer may be reallocated.
2380 Result* result = GetResultAs<Result*>();
2381 if (!result) {
2382 return;
2384 *result = 0; // mark as failed.
2385 helper_->ReadPixels(
2386 xoffset, yoffset, width, num_rows, format, type,
2387 buffer.shm_id(), buffer.offset(),
2388 GetResultShmId(), GetResultShmOffset(),
2389 false);
2390 WaitForCmd();
2391 if (*result != 0) {
2392 // when doing a y-flip we have to iterate through top-to-bottom chunks
2393 // of the dst. The service side handles reversing the rows within a
2394 // chunk.
2395 int8* rows_dst;
2396 if (pack_reverse_row_order_) {
2397 rows_dst = dest + (height - num_rows) * padded_row_size;
2398 } else {
2399 rows_dst = dest;
2401 // We have to copy 1 row at a time to avoid writing pad bytes.
2402 const int8* src = static_cast<const int8*>(buffer.address());
2403 for (GLint yy = 0; yy < num_rows; ++yy) {
2404 memcpy(rows_dst, src, unpadded_row_size);
2405 rows_dst += padded_row_size;
2406 src += padded_row_size;
2408 if (!pack_reverse_row_order_) {
2409 dest = rows_dst;
2412 // If it was not marked as successful exit.
2413 if (*result == 0) {
2414 return;
2416 yoffset += num_rows;
2417 height -= num_rows;
2419 CheckGLError();
2422 void GLES2Implementation::ActiveTexture(GLenum texture) {
2423 GPU_CLIENT_SINGLE_THREAD_CHECK();
2424 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2425 << GLES2Util::GetStringEnum(texture) << ")");
2426 GLuint texture_index = texture - GL_TEXTURE0;
2427 if (texture_index >= static_cast<GLuint>(
2428 static_state_.int_state.max_combined_texture_image_units)) {
2429 SetGLErrorInvalidEnum(
2430 "glActiveTexture", texture, "texture");
2431 return;
2434 active_texture_unit_ = texture_index;
2435 helper_->ActiveTexture(texture);
2436 CheckGLError();
2439 void GLES2Implementation::GenBuffersHelper(
2440 GLsizei /* n */, const GLuint* /* buffers */) {
2443 void GLES2Implementation::GenFramebuffersHelper(
2444 GLsizei /* n */, const GLuint* /* framebuffers */) {
2447 void GLES2Implementation::GenRenderbuffersHelper(
2448 GLsizei /* n */, const GLuint* /* renderbuffers */) {
2451 void GLES2Implementation::GenTexturesHelper(
2452 GLsizei /* n */, const GLuint* /* textures */) {
2455 void GLES2Implementation::GenVertexArraysOESHelper(
2456 GLsizei n, const GLuint* arrays) {
2457 vertex_array_object_manager_->GenVertexArrays(n, arrays);
2460 void GLES2Implementation::GenQueriesEXTHelper(
2461 GLsizei /* n */, const GLuint* /* queries */) {
2464 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
2465 // generates a new resource. On newer versions of OpenGL they don't. The code
2466 // related to binding below will need to change if we switch to the new OpenGL
2467 // model. Specifically it assumes a bind will succeed which is always true in
2468 // the old model but possibly not true in the new model if another context has
2469 // deleted the resource.
2471 bool GLES2Implementation::BindBufferHelper(
2472 GLenum target, GLuint buffer_id) {
2473 // TODO(gman): See note #1 above.
2474 bool changed = false;
2475 switch (target) {
2476 case GL_ARRAY_BUFFER:
2477 if (bound_array_buffer_id_ != buffer_id) {
2478 bound_array_buffer_id_ = buffer_id;
2479 changed = true;
2481 break;
2482 case GL_ELEMENT_ARRAY_BUFFER:
2483 changed = vertex_array_object_manager_->BindElementArray(buffer_id);
2484 break;
2485 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
2486 bound_pixel_pack_transfer_buffer_id_ = buffer_id;
2487 break;
2488 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
2489 bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
2490 break;
2491 default:
2492 changed = true;
2493 break;
2495 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2496 // used even though it's marked it as used here.
2497 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(buffer_id);
2498 return changed;
2501 bool GLES2Implementation::BindFramebufferHelper(
2502 GLenum target, GLuint framebuffer) {
2503 // TODO(gman): See note #1 above.
2504 bool changed = false;
2505 switch (target) {
2506 case GL_FRAMEBUFFER:
2507 if (bound_framebuffer_ != framebuffer ||
2508 bound_read_framebuffer_ != framebuffer) {
2509 bound_framebuffer_ = framebuffer;
2510 bound_read_framebuffer_ = framebuffer;
2511 changed = true;
2513 break;
2514 case GL_READ_FRAMEBUFFER:
2515 if (!IsChromiumFramebufferMultisampleAvailable()) {
2516 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2517 return false;
2519 if (bound_read_framebuffer_ != framebuffer) {
2520 bound_read_framebuffer_ = framebuffer;
2521 changed = true;
2523 break;
2524 case GL_DRAW_FRAMEBUFFER:
2525 if (!IsChromiumFramebufferMultisampleAvailable()) {
2526 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2527 return false;
2529 if (bound_framebuffer_ != framebuffer) {
2530 bound_framebuffer_ = framebuffer;
2531 changed = true;
2533 break;
2534 default:
2535 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2536 return false;
2538 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(framebuffer);
2539 return changed;
2542 bool GLES2Implementation::BindRenderbufferHelper(
2543 GLenum target, GLuint renderbuffer) {
2544 // TODO(gman): See note #1 above.
2545 bool changed = false;
2546 switch (target) {
2547 case GL_RENDERBUFFER:
2548 if (bound_renderbuffer_ != renderbuffer) {
2549 bound_renderbuffer_ = renderbuffer;
2550 changed = true;
2552 break;
2553 default:
2554 changed = true;
2555 break;
2557 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2558 // used even though it's marked it as used here.
2559 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(renderbuffer);
2560 return changed;
2563 bool GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
2564 // TODO(gman): See note #1 above.
2565 // TODO(gman): Change this to false once we figure out why it's failing
2566 // on daisy.
2567 bool changed = true;
2568 TextureUnit& unit = texture_units_[active_texture_unit_];
2569 switch (target) {
2570 case GL_TEXTURE_2D:
2571 if (unit.bound_texture_2d != texture) {
2572 unit.bound_texture_2d = texture;
2573 changed = true;
2575 break;
2576 case GL_TEXTURE_CUBE_MAP:
2577 if (unit.bound_texture_cube_map != texture) {
2578 unit.bound_texture_cube_map = texture;
2579 changed = true;
2581 break;
2582 case GL_TEXTURE_EXTERNAL_OES:
2583 if (unit.bound_texture_external_oes != texture) {
2584 unit.bound_texture_external_oes = texture;
2585 changed = true;
2587 break;
2588 default:
2589 changed = true;
2590 break;
2592 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2593 // used. even though it's marked it as used here.
2594 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(texture);
2595 return changed;
2598 bool GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
2599 // TODO(gman): See note #1 above.
2600 bool changed = false;
2601 if (!vertex_array_object_manager_->BindVertexArray(array, &changed)) {
2602 SetGLError(
2603 GL_INVALID_OPERATION, "glBindVertexArrayOES",
2604 "id was not generated with glGenVertexArrayOES");
2606 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
2607 // because unlike other resources VertexArrayObject ids must
2608 // be generated by GenVertexArrays. A random id to Bind will not
2609 // generate a new object.
2610 return changed;
2613 bool GLES2Implementation::UseProgramHelper(GLuint program) {
2614 bool changed = false;
2615 if (current_program_ != program) {
2616 current_program_ = program;
2617 changed = true;
2619 return changed;
2622 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
2623 return vertex_array_object_manager_->IsReservedId(id);
2626 void GLES2Implementation::DeleteBuffersHelper(
2627 GLsizei n, const GLuint* buffers) {
2628 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
2629 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
2630 SetGLError(
2631 GL_INVALID_VALUE,
2632 "glDeleteBuffers", "id not created by this context.");
2633 return;
2635 for (GLsizei ii = 0; ii < n; ++ii) {
2636 if (buffers[ii] == bound_array_buffer_id_) {
2637 bound_array_buffer_id_ = 0;
2639 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
2641 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
2642 if (buffer)
2643 RemoveTransferBuffer(buffer);
2645 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
2646 bound_pixel_unpack_transfer_buffer_id_ = 0;
2651 void GLES2Implementation::DeleteBuffersStub(
2652 GLsizei n, const GLuint* buffers) {
2653 helper_->DeleteBuffersImmediate(n, buffers);
2657 void GLES2Implementation::DeleteFramebuffersHelper(
2658 GLsizei n, const GLuint* framebuffers) {
2659 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
2660 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
2661 SetGLError(
2662 GL_INVALID_VALUE,
2663 "glDeleteFramebuffers", "id not created by this context.");
2664 return;
2666 for (GLsizei ii = 0; ii < n; ++ii) {
2667 if (framebuffers[ii] == bound_framebuffer_) {
2668 bound_framebuffer_ = 0;
2670 if (framebuffers[ii] == bound_read_framebuffer_) {
2671 bound_read_framebuffer_ = 0;
2676 void GLES2Implementation::DeleteFramebuffersStub(
2677 GLsizei n, const GLuint* framebuffers) {
2678 helper_->DeleteFramebuffersImmediate(n, framebuffers);
2681 void GLES2Implementation::DeleteRenderbuffersHelper(
2682 GLsizei n, const GLuint* renderbuffers) {
2683 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
2684 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
2685 SetGLError(
2686 GL_INVALID_VALUE,
2687 "glDeleteRenderbuffers", "id not created by this context.");
2688 return;
2690 for (GLsizei ii = 0; ii < n; ++ii) {
2691 if (renderbuffers[ii] == bound_renderbuffer_) {
2692 bound_renderbuffer_ = 0;
2697 void GLES2Implementation::DeleteRenderbuffersStub(
2698 GLsizei n, const GLuint* renderbuffers) {
2699 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
2702 void GLES2Implementation::DeleteTexturesHelper(
2703 GLsizei n, const GLuint* textures) {
2704 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
2705 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
2706 SetGLError(
2707 GL_INVALID_VALUE,
2708 "glDeleteTextures", "id not created by this context.");
2709 return;
2711 for (GLsizei ii = 0; ii < n; ++ii) {
2712 for (GLint tt = 0;
2713 tt < static_state_.int_state.max_combined_texture_image_units;
2714 ++tt) {
2715 TextureUnit& unit = texture_units_[tt];
2716 if (textures[ii] == unit.bound_texture_2d) {
2717 unit.bound_texture_2d = 0;
2719 if (textures[ii] == unit.bound_texture_cube_map) {
2720 unit.bound_texture_cube_map = 0;
2722 if (textures[ii] == unit.bound_texture_external_oes) {
2723 unit.bound_texture_external_oes = 0;
2729 void GLES2Implementation::DeleteVertexArraysOESHelper(
2730 GLsizei n, const GLuint* arrays) {
2731 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
2732 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
2733 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
2734 SetGLError(
2735 GL_INVALID_VALUE,
2736 "glDeleteVertexArraysOES", "id not created by this context.");
2737 return;
2741 void GLES2Implementation::DeleteVertexArraysOESStub(
2742 GLsizei n, const GLuint* arrays) {
2743 helper_->DeleteVertexArraysOESImmediate(n, arrays);
2746 void GLES2Implementation::DeleteTexturesStub(
2747 GLsizei n, const GLuint* textures) {
2748 helper_->DeleteTexturesImmediate(n, textures);
2751 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
2752 GPU_CLIENT_SINGLE_THREAD_CHECK();
2753 GPU_CLIENT_LOG(
2754 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
2755 vertex_array_object_manager_->SetAttribEnable(index, false);
2756 helper_->DisableVertexAttribArray(index);
2757 CheckGLError();
2760 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
2761 GPU_CLIENT_SINGLE_THREAD_CHECK();
2762 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
2763 << index << ")");
2764 vertex_array_object_manager_->SetAttribEnable(index, true);
2765 helper_->EnableVertexAttribArray(index);
2766 CheckGLError();
2769 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
2770 GPU_CLIENT_SINGLE_THREAD_CHECK();
2771 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
2772 << GLES2Util::GetStringDrawMode(mode) << ", "
2773 << first << ", " << count << ")");
2774 if (count < 0) {
2775 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
2776 return;
2778 bool simulated = false;
2779 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
2780 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
2781 return;
2783 helper_->DrawArrays(mode, first, count);
2784 RestoreArrayBuffer(simulated);
2785 CheckGLError();
2788 void GLES2Implementation::GetVertexAttribfv(
2789 GLuint index, GLenum pname, GLfloat* params) {
2790 GPU_CLIENT_SINGLE_THREAD_CHECK();
2791 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
2792 << index << ", "
2793 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2794 << static_cast<const void*>(params) << ")");
2795 uint32 value = 0;
2796 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2797 *params = static_cast<float>(value);
2798 return;
2800 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
2801 typedef cmds::GetVertexAttribfv::Result Result;
2802 Result* result = GetResultAs<Result*>();
2803 if (!result) {
2804 return;
2806 result->SetNumResults(0);
2807 helper_->GetVertexAttribfv(
2808 index, pname, GetResultShmId(), GetResultShmOffset());
2809 WaitForCmd();
2810 result->CopyResult(params);
2811 GPU_CLIENT_LOG_CODE_BLOCK({
2812 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2813 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2816 CheckGLError();
2819 void GLES2Implementation::GetVertexAttribiv(
2820 GLuint index, GLenum pname, GLint* params) {
2821 GPU_CLIENT_SINGLE_THREAD_CHECK();
2822 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
2823 << index << ", "
2824 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2825 << static_cast<const void*>(params) << ")");
2826 uint32 value = 0;
2827 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2828 *params = value;
2829 return;
2831 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
2832 typedef cmds::GetVertexAttribiv::Result Result;
2833 Result* result = GetResultAs<Result*>();
2834 if (!result) {
2835 return;
2837 result->SetNumResults(0);
2838 helper_->GetVertexAttribiv(
2839 index, pname, GetResultShmId(), GetResultShmOffset());
2840 WaitForCmd();
2841 result->CopyResult(params);
2842 GPU_CLIENT_LOG_CODE_BLOCK({
2843 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2844 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2847 CheckGLError();
2850 void GLES2Implementation::Swap() {
2851 SwapBuffers();
2852 gpu_control_->Echo(
2853 base::Bind(&GLES2Implementation::OnSwapBuffersComplete,
2854 weak_ptr_factory_.GetWeakPtr()));
2857 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
2858 PostSubBufferCHROMIUM(sub_buffer.x(),
2859 sub_buffer.y(),
2860 sub_buffer.width(),
2861 sub_buffer.height());
2862 gpu_control_->Echo(base::Bind(&GLES2Implementation::OnSwapBuffersComplete,
2863 weak_ptr_factory_.GetWeakPtr()));
2866 void GLES2Implementation::SetSwapBuffersCompleteCallback(
2867 const base::Closure& swap_buffers_complete_callback) {
2868 swap_buffers_complete_callback_ = swap_buffers_complete_callback;
2871 static GLenum GetGLESOverlayTransform(gfx::OverlayTransform plane_transform) {
2872 switch (plane_transform) {
2873 case gfx::OVERLAY_TRANSFORM_INVALID:
2874 break;
2875 case gfx::OVERLAY_TRANSFORM_NONE:
2876 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
2877 case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
2878 return GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM;
2879 case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
2880 return GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM;
2881 case gfx::OVERLAY_TRANSFORM_ROTATE_90:
2882 return GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM;
2883 case gfx::OVERLAY_TRANSFORM_ROTATE_180:
2884 return GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM;
2885 case gfx::OVERLAY_TRANSFORM_ROTATE_270:
2886 return GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM;
2888 NOTREACHED();
2889 return GL_OVERLAY_TRANSFORM_NONE_CHROMIUM;
2892 void GLES2Implementation::ScheduleOverlayPlane(
2893 int plane_z_order,
2894 gfx::OverlayTransform plane_transform,
2895 unsigned overlay_texture_id,
2896 const gfx::Rect& display_bounds,
2897 const gfx::RectF& uv_rect) {
2898 ScheduleOverlayPlaneCHROMIUM(plane_z_order,
2899 GetGLESOverlayTransform(plane_transform),
2900 overlay_texture_id,
2901 display_bounds.x(),
2902 display_bounds.y(),
2903 display_bounds.width(),
2904 display_bounds.height(),
2905 uv_rect.x(),
2906 uv_rect.y(),
2907 uv_rect.width(),
2908 uv_rect.height());
2911 void GLES2Implementation::OnSwapBuffersComplete() {
2912 if (!swap_buffers_complete_callback_.is_null())
2913 swap_buffers_complete_callback_.Run();
2916 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
2917 const char* feature) {
2918 GPU_CLIENT_SINGLE_THREAD_CHECK();
2919 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
2920 << feature << ")");
2921 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
2922 typedef cmds::EnableFeatureCHROMIUM::Result Result;
2923 Result* result = GetResultAs<Result*>();
2924 if (!result) {
2925 return false;
2927 *result = 0;
2928 SetBucketAsCString(kResultBucketId, feature);
2929 helper_->EnableFeatureCHROMIUM(
2930 kResultBucketId, GetResultShmId(), GetResultShmOffset());
2931 WaitForCmd();
2932 helper_->SetBucketSize(kResultBucketId, 0);
2933 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
2934 return *result;
2937 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
2938 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
2939 GPU_CLIENT_SINGLE_THREAD_CHECK();
2940 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
2941 << target << ", " << offset << ", " << size << ", "
2942 << GLES2Util::GetStringEnum(access) << ")");
2943 // NOTE: target is NOT checked because the service will check it
2944 // and we don't know what targets are valid.
2945 if (access != GL_WRITE_ONLY) {
2946 SetGLErrorInvalidEnum(
2947 "glMapBufferSubDataCHROMIUM", access, "access");
2948 return NULL;
2950 if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
2951 !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
2952 return NULL;
2955 int32 shm_id;
2956 unsigned int shm_offset;
2957 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2958 if (!mem) {
2959 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
2960 return NULL;
2963 std::pair<MappedBufferMap::iterator, bool> result =
2964 mapped_buffers_.insert(std::make_pair(
2965 mem,
2966 MappedBuffer(
2967 access, shm_id, mem, shm_offset, target, offset, size)));
2968 DCHECK(result.second);
2969 GPU_CLIENT_LOG(" returned " << mem);
2970 return mem;
2973 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
2974 GPU_CLIENT_SINGLE_THREAD_CHECK();
2975 GPU_CLIENT_LOG(
2976 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
2977 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
2978 if (it == mapped_buffers_.end()) {
2979 SetGLError(
2980 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
2981 return;
2983 const MappedBuffer& mb = it->second;
2984 helper_->BufferSubData(
2985 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
2986 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
2987 mapped_buffers_.erase(it);
2988 CheckGLError();
2991 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
2992 GLenum target,
2993 GLint level,
2994 GLint xoffset,
2995 GLint yoffset,
2996 GLsizei width,
2997 GLsizei height,
2998 GLenum format,
2999 GLenum type,
3000 GLenum access) {
3001 GPU_CLIENT_SINGLE_THREAD_CHECK();
3002 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
3003 << target << ", " << level << ", "
3004 << xoffset << ", " << yoffset << ", "
3005 << width << ", " << height << ", "
3006 << GLES2Util::GetStringTextureFormat(format) << ", "
3007 << GLES2Util::GetStringPixelType(type) << ", "
3008 << GLES2Util::GetStringEnum(access) << ")");
3009 if (access != GL_WRITE_ONLY) {
3010 SetGLErrorInvalidEnum(
3011 "glMapTexSubImage2DCHROMIUM", access, "access");
3012 return NULL;
3014 // NOTE: target is NOT checked because the service will check it
3015 // and we don't know what targets are valid.
3016 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
3017 SetGLError(
3018 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
3019 return NULL;
3021 uint32 size;
3022 if (!GLES2Util::ComputeImageDataSizes(
3023 width, height, format, type, unpack_alignment_, &size, NULL, NULL)) {
3024 SetGLError(
3025 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
3026 return NULL;
3028 int32 shm_id;
3029 unsigned int shm_offset;
3030 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
3031 if (!mem) {
3032 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
3033 return NULL;
3036 std::pair<MappedTextureMap::iterator, bool> result =
3037 mapped_textures_.insert(std::make_pair(
3038 mem,
3039 MappedTexture(
3040 access, shm_id, mem, shm_offset,
3041 target, level, xoffset, yoffset, width, height, format, type)));
3042 DCHECK(result.second);
3043 GPU_CLIENT_LOG(" returned " << mem);
3044 return mem;
3047 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
3048 GPU_CLIENT_SINGLE_THREAD_CHECK();
3049 GPU_CLIENT_LOG(
3050 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
3051 MappedTextureMap::iterator it = mapped_textures_.find(mem);
3052 if (it == mapped_textures_.end()) {
3053 SetGLError(
3054 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
3055 return;
3057 const MappedTexture& mt = it->second;
3058 helper_->TexSubImage2D(
3059 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
3060 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
3061 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
3062 mapped_textures_.erase(it);
3063 CheckGLError();
3066 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
3067 float scale_factor) {
3068 GPU_CLIENT_SINGLE_THREAD_CHECK();
3069 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
3070 << width << ", " << height << ", " << scale_factor << ")");
3071 helper_->ResizeCHROMIUM(width, height, scale_factor);
3072 CheckGLError();
3075 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
3076 GPU_CLIENT_SINGLE_THREAD_CHECK();
3077 GPU_CLIENT_LOG("[" << GetLogPrefix()
3078 << "] glGetRequestableExtensionsCHROMIUM()");
3079 TRACE_EVENT0("gpu",
3080 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
3081 const char* result = NULL;
3082 // Clear the bucket so if the command fails nothing will be in it.
3083 helper_->SetBucketSize(kResultBucketId, 0);
3084 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
3085 std::string str;
3086 if (GetBucketAsString(kResultBucketId, &str)) {
3087 // The set of requestable extensions shrinks as we enable
3088 // them. Because we don't know when the client will stop referring
3089 // to a previous one it queries (see GetString) we need to cache
3090 // the unique results.
3091 std::set<std::string>::const_iterator sit =
3092 requestable_extensions_set_.find(str);
3093 if (sit != requestable_extensions_set_.end()) {
3094 result = sit->c_str();
3095 } else {
3096 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
3097 requestable_extensions_set_.insert(str);
3098 DCHECK(insert_result.second);
3099 result = insert_result.first->c_str();
3102 GPU_CLIENT_LOG(" returned " << result);
3103 return reinterpret_cast<const GLchar*>(result);
3106 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
3107 // with VirtualGL contexts.
3108 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
3109 GPU_CLIENT_SINGLE_THREAD_CHECK();
3110 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
3111 << extension << ")");
3112 SetBucketAsCString(kResultBucketId, extension);
3113 helper_->RequestExtensionCHROMIUM(kResultBucketId);
3114 helper_->SetBucketSize(kResultBucketId, 0);
3116 struct ExtensionCheck {
3117 const char* extension;
3118 ExtensionStatus* status;
3120 const ExtensionCheck checks[] = {
3122 "GL_ANGLE_pack_reverse_row_order",
3123 &angle_pack_reverse_row_order_status_,
3126 "GL_CHROMIUM_framebuffer_multisample",
3127 &chromium_framebuffer_multisample_,
3130 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
3131 for (size_t ii = 0; ii < kNumChecks; ++ii) {
3132 const ExtensionCheck& check = checks[ii];
3133 if (*check.status == kUnavailableExtensionStatus &&
3134 !strcmp(extension, check.extension)) {
3135 *check.status = kUnknownExtensionStatus;
3140 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
3141 GPU_CLIENT_SINGLE_THREAD_CHECK();
3142 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
3143 // Wait if this would add too many rate limit tokens.
3144 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
3145 helper_->WaitForToken(rate_limit_tokens_.front());
3146 rate_limit_tokens_.pop();
3148 rate_limit_tokens_.push(helper_->InsertToken());
3151 void GLES2Implementation::GetMultipleIntegervCHROMIUM(
3152 const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size) {
3153 GPU_CLIENT_SINGLE_THREAD_CHECK();
3154 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMultipleIntegervCHROMIUM("
3155 << static_cast<const void*>(pnames) << ", "
3156 << count << ", " << results << ", "
3157 << size << ")");
3158 GPU_CLIENT_LOG_CODE_BLOCK({
3159 for (GLuint i = 0; i < count; ++i) {
3160 GPU_CLIENT_LOG(
3161 " " << i << ": " << GLES2Util::GetStringGLState(pnames[i]));
3164 DCHECK(size >= 0 && FitInt32NonNegative<GLsizeiptr>(size));
3166 GetMultipleIntegervState state(pnames, count, results, size);
3167 if (!GetMultipleIntegervSetup(&state)) {
3168 return;
3170 state.buffer = transfer_buffer_->Alloc(state.transfer_buffer_size_needed);
3171 if (!state.buffer) {
3172 SetGLError(GL_OUT_OF_MEMORY, "glGetMultipleIntegervCHROMIUM",
3173 "Transfer buffer allocation failed.");
3174 return;
3176 GetMultipleIntegervRequest(&state);
3177 WaitForCmd();
3178 GetMultipleIntegervOnCompleted(&state);
3180 GPU_CLIENT_LOG(" returned");
3181 GPU_CLIENT_LOG_CODE_BLOCK({
3182 for (int i = 0; i < state.num_results; ++i) {
3183 GPU_CLIENT_LOG(" " << i << ": " << (results[i]));
3187 // TODO(gman): We should be able to free without a token.
3188 transfer_buffer_->FreePendingToken(state.buffer, helper_->InsertToken());
3189 CheckGLError();
3192 bool GLES2Implementation::GetMultipleIntegervSetup(
3193 GetMultipleIntegervState* state) {
3194 state->num_results = 0;
3195 for (GLuint ii = 0; ii < state->pnames_count; ++ii) {
3196 int num = util_.GLGetNumValuesReturned(state->pnames[ii]);
3197 if (!num) {
3198 SetGLErrorInvalidEnum(
3199 "glGetMultipleIntegervCHROMIUM", state->pnames[ii], "pname");
3200 return false;
3202 state->num_results += num;
3204 if (static_cast<size_t>(state->results_size) !=
3205 state->num_results * sizeof(GLint)) {
3206 SetGLError(GL_INVALID_VALUE, "glGetMultipleIntegervCHROMIUM", "bad size");
3207 return false;
3209 for (int ii = 0; ii < state->num_results; ++ii) {
3210 if (state->results[ii] != 0) {
3211 SetGLError(GL_INVALID_VALUE,
3212 "glGetMultipleIntegervCHROMIUM", "results not set to zero.");
3213 return false;
3216 state->transfer_buffer_size_needed =
3217 state->pnames_count * sizeof(state->pnames[0]) +
3218 state->num_results * sizeof(state->results[0]);
3219 return true;
3222 void GLES2Implementation::GetMultipleIntegervRequest(
3223 GetMultipleIntegervState* state) {
3224 GLenum* pnames_buffer = static_cast<GLenum*>(state->buffer);
3225 state->results_buffer = pnames_buffer + state->pnames_count;
3226 memcpy(pnames_buffer, state->pnames, state->pnames_count * sizeof(GLenum));
3227 memset(state->results_buffer, 0, state->num_results * sizeof(GLint));
3228 helper_->GetMultipleIntegervCHROMIUM(
3229 transfer_buffer_->GetShmId(),
3230 transfer_buffer_->GetOffset(pnames_buffer),
3231 state->pnames_count,
3232 transfer_buffer_->GetShmId(),
3233 transfer_buffer_->GetOffset(state->results_buffer),
3234 state->results_size);
3237 void GLES2Implementation::GetMultipleIntegervOnCompleted(
3238 GetMultipleIntegervState* state) {
3239 memcpy(state->results, state->results_buffer, state->results_size);;
3242 void GLES2Implementation::GetAllShaderPrecisionFormatsSetup(
3243 GetAllShaderPrecisionFormatsState* state) {
3244 state->transfer_buffer_size_needed =
3245 state->precision_params_count *
3246 sizeof(cmds::GetShaderPrecisionFormat::Result);
3249 void GLES2Implementation::GetAllShaderPrecisionFormatsRequest(
3250 GetAllShaderPrecisionFormatsState* state) {
3251 typedef cmds::GetShaderPrecisionFormat::Result Result;
3252 Result* result = static_cast<Result*>(state->results_buffer);
3254 for (int i = 0; i < state->precision_params_count; i++) {
3255 result->success = false;
3256 helper_->GetShaderPrecisionFormat(state->precision_params[i][0],
3257 state->precision_params[i][1],
3258 transfer_buffer_->GetShmId(),
3259 transfer_buffer_->GetOffset(result));
3260 result++;
3264 void GLES2Implementation::GetAllShaderPrecisionFormatsOnCompleted(
3265 GetAllShaderPrecisionFormatsState* state) {
3266 typedef cmds::GetShaderPrecisionFormat::Result Result;
3267 Result* result = static_cast<Result*>(state->results_buffer);
3269 for (int i = 0; i < state->precision_params_count; i++) {
3270 if (result->success) {
3271 const GLStaticState::ShaderPrecisionKey key(
3272 state->precision_params[i][0], state->precision_params[i][1]);
3273 static_state_.shader_precisions[key] = *result;
3275 result++;
3279 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3280 GLuint program, std::vector<int8>* result) {
3281 DCHECK(result);
3282 // Clear the bucket so if the command fails nothing will be in it.
3283 helper_->SetBucketSize(kResultBucketId, 0);
3284 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
3285 GetBucketContents(kResultBucketId, result);
3288 void GLES2Implementation::GetProgramInfoCHROMIUM(
3289 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3290 GPU_CLIENT_SINGLE_THREAD_CHECK();
3291 if (bufsize < 0) {
3292 SetGLError(
3293 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3294 return;
3296 if (size == NULL) {
3297 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
3298 return;
3300 // Make sure they've set size to 0 else the value will be undefined on
3301 // lost context.
3302 DCHECK_EQ(0, *size);
3303 std::vector<int8> result;
3304 GetProgramInfoCHROMIUMHelper(program, &result);
3305 if (result.empty()) {
3306 return;
3308 *size = result.size();
3309 if (!info) {
3310 return;
3312 if (static_cast<size_t>(bufsize) < result.size()) {
3313 SetGLError(GL_INVALID_OPERATION,
3314 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3315 return;
3317 memcpy(info, &result[0], result.size());
3320 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
3321 GPU_CLIENT_SINGLE_THREAD_CHECK();
3322 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
3323 << texture << ")");
3324 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
3325 helper_->CommandBufferHelper::Flush();
3326 return gpu_control_->CreateStreamTexture(texture);
3329 void GLES2Implementation::PostSubBufferCHROMIUM(
3330 GLint x, GLint y, GLint width, GLint height) {
3331 GPU_CLIENT_SINGLE_THREAD_CHECK();
3332 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
3333 << x << ", " << y << ", " << width << ", " << height << ")");
3334 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
3335 "width", width, "height", height);
3337 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
3338 swap_buffers_tokens_.push(helper_->InsertToken());
3339 helper_->PostSubBufferCHROMIUM(x, y, width, height);
3340 helper_->CommandBufferHelper::Flush();
3341 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
3342 helper_->WaitForToken(swap_buffers_tokens_.front());
3343 swap_buffers_tokens_.pop();
3347 void GLES2Implementation::DeleteQueriesEXTHelper(
3348 GLsizei n, const GLuint* queries) {
3349 for (GLsizei ii = 0; ii < n; ++ii) {
3350 query_tracker_->RemoveQuery(queries[ii]);
3351 query_id_allocator_->FreeID(queries[ii]);
3354 helper_->DeleteQueriesEXTImmediate(n, queries);
3357 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
3358 GPU_CLIENT_SINGLE_THREAD_CHECK();
3359 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
3361 // TODO(gman): To be spec compliant IDs from other contexts sharing
3362 // resources need to return true here even though you can't share
3363 // queries across contexts?
3364 return query_tracker_->GetQuery(id) != NULL;
3367 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
3368 GPU_CLIENT_SINGLE_THREAD_CHECK();
3369 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
3370 << GLES2Util::GetStringQueryTarget(target)
3371 << ", " << id << ")");
3373 // if any outstanding queries INV_OP
3374 QueryMap::iterator it = current_queries_.find(target);
3375 if (it != current_queries_.end()) {
3376 SetGLError(
3377 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
3378 return;
3381 // id = 0 INV_OP
3382 if (id == 0) {
3383 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
3384 return;
3387 // if not GENned INV_OPERATION
3388 if (!query_id_allocator_->InUse(id)) {
3389 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "invalid id");
3390 return;
3393 // if id does not have an object
3394 QueryTracker::Query* query = query_tracker_->GetQuery(id);
3395 if (!query) {
3396 query = query_tracker_->CreateQuery(id, target);
3397 if (!query) {
3398 SetGLError(GL_OUT_OF_MEMORY,
3399 "glBeginQueryEXT",
3400 "transfer buffer allocation failed");
3401 return;
3403 } else if (query->target() != target) {
3404 SetGLError(
3405 GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
3406 return;
3409 current_queries_[target] = query;
3411 query->Begin(this);
3412 CheckGLError();
3415 void GLES2Implementation::EndQueryEXT(GLenum target) {
3416 GPU_CLIENT_SINGLE_THREAD_CHECK();
3417 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
3418 << GLES2Util::GetStringQueryTarget(target) << ")");
3419 // Don't do anything if the context is lost.
3420 if (helper_->IsContextLost()) {
3421 return;
3424 QueryMap::iterator it = current_queries_.find(target);
3425 if (it == current_queries_.end()) {
3426 SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
3427 return;
3430 QueryTracker::Query* query = it->second;
3431 query->End(this);
3432 current_queries_.erase(it);
3433 CheckGLError();
3436 void GLES2Implementation::GetQueryivEXT(
3437 GLenum target, GLenum pname, GLint* params) {
3438 GPU_CLIENT_SINGLE_THREAD_CHECK();
3439 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
3440 << GLES2Util::GetStringQueryTarget(target) << ", "
3441 << GLES2Util::GetStringQueryParameter(pname) << ", "
3442 << static_cast<const void*>(params) << ")");
3444 if (pname != GL_CURRENT_QUERY_EXT) {
3445 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
3446 return;
3448 QueryMap::iterator it = current_queries_.find(target);
3449 if (it != current_queries_.end()) {
3450 QueryTracker::Query* query = it->second;
3451 *params = query->id();
3452 } else {
3453 *params = 0;
3455 GPU_CLIENT_LOG(" " << *params);
3456 CheckGLError();
3459 void GLES2Implementation::GetQueryObjectuivEXT(
3460 GLuint id, GLenum pname, GLuint* params) {
3461 GPU_CLIENT_SINGLE_THREAD_CHECK();
3462 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
3463 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
3464 << static_cast<const void*>(params) << ")");
3466 QueryTracker::Query* query = query_tracker_->GetQuery(id);
3467 if (!query) {
3468 SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
3469 return;
3472 QueryMap::iterator it = current_queries_.find(query->target());
3473 if (it != current_queries_.end()) {
3474 SetGLError(
3475 GL_INVALID_OPERATION,
3476 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
3477 return;
3480 if (query->NeverUsed()) {
3481 SetGLError(
3482 GL_INVALID_OPERATION,
3483 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
3484 return;
3487 switch (pname) {
3488 case GL_QUERY_RESULT_EXT:
3489 if (!query->CheckResultsAvailable(helper_)) {
3490 helper_->WaitForToken(query->token());
3491 if (!query->CheckResultsAvailable(helper_)) {
3492 FinishHelper();
3493 CHECK(query->CheckResultsAvailable(helper_));
3496 *params = query->GetResult();
3497 break;
3498 case GL_QUERY_RESULT_AVAILABLE_EXT:
3499 *params = query->CheckResultsAvailable(helper_);
3500 break;
3501 default:
3502 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
3503 break;
3505 GPU_CLIENT_LOG(" " << *params);
3506 CheckGLError();
3509 void GLES2Implementation::DrawArraysInstancedANGLE(
3510 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
3511 GPU_CLIENT_SINGLE_THREAD_CHECK();
3512 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
3513 << GLES2Util::GetStringDrawMode(mode) << ", "
3514 << first << ", " << count << ", " << primcount << ")");
3515 if (count < 0) {
3516 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
3517 return;
3519 if (primcount < 0) {
3520 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
3521 return;
3523 if (primcount == 0) {
3524 return;
3526 bool simulated = false;
3527 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
3528 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
3529 &simulated)) {
3530 return;
3532 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
3533 RestoreArrayBuffer(simulated);
3534 CheckGLError();
3537 void GLES2Implementation::DrawElementsInstancedANGLE(
3538 GLenum mode, GLsizei count, GLenum type, const void* indices,
3539 GLsizei primcount) {
3540 GPU_CLIENT_SINGLE_THREAD_CHECK();
3541 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
3542 << GLES2Util::GetStringDrawMode(mode) << ", "
3543 << count << ", "
3544 << GLES2Util::GetStringIndexType(type) << ", "
3545 << static_cast<const void*>(indices) << ", "
3546 << primcount << ")");
3547 if (count < 0) {
3548 SetGLError(GL_INVALID_VALUE,
3549 "glDrawElementsInstancedANGLE", "count less than 0.");
3550 return;
3552 if (count == 0) {
3553 return;
3555 if (primcount < 0) {
3556 SetGLError(GL_INVALID_VALUE,
3557 "glDrawElementsInstancedANGLE", "primcount < 0");
3558 return;
3560 if (primcount == 0) {
3561 return;
3563 if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
3564 !ValidateOffset("glDrawElementsInstancedANGLE",
3565 reinterpret_cast<GLintptr>(indices))) {
3566 return;
3568 GLuint offset = 0;
3569 bool simulated = false;
3570 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
3571 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
3572 indices, &offset, &simulated)) {
3573 return;
3575 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
3576 RestoreElementAndArrayBuffers(simulated);
3577 CheckGLError();
3580 void GLES2Implementation::GenMailboxCHROMIUM(
3581 GLbyte* mailbox) {
3582 GPU_CLIENT_SINGLE_THREAD_CHECK();
3583 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
3584 << static_cast<const void*>(mailbox) << ")");
3585 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
3587 gpu::Mailbox result = gpu::Mailbox::Generate();
3588 memcpy(mailbox, result.name, sizeof(result.name));
3591 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target,
3592 const GLbyte* data) {
3593 GPU_CLIENT_SINGLE_THREAD_CHECK();
3594 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
3595 << static_cast<const void*>(data) << ")");
3596 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
3597 DCHECK(mailbox.Verify()) << "ProduceTextureCHROMIUM was passed a "
3598 "mailbox that was not generated by "
3599 "GenMailboxCHROMIUM.";
3600 helper_->ProduceTextureCHROMIUMImmediate(target, data);
3601 CheckGLError();
3604 void GLES2Implementation::ProduceTextureDirectCHROMIUM(
3605 GLuint texture, GLenum target, const GLbyte* data) {
3606 GPU_CLIENT_SINGLE_THREAD_CHECK();
3607 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureDirectCHROMIUM("
3608 << static_cast<const void*>(data) << ")");
3609 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
3610 DCHECK(mailbox.Verify()) << "ProduceTextureDirectCHROMIUM was passed a "
3611 "mailbox that was not generated by "
3612 "GenMailboxCHROMIUM.";
3613 helper_->ProduceTextureDirectCHROMIUMImmediate(texture, target, data);
3614 CheckGLError();
3617 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target,
3618 const GLbyte* data) {
3619 GPU_CLIENT_SINGLE_THREAD_CHECK();
3620 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
3621 << static_cast<const void*>(data) << ")");
3622 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
3623 DCHECK(mailbox.Verify()) << "ConsumeTextureCHROMIUM was passed a "
3624 "mailbox that was not generated by "
3625 "GenMailboxCHROMIUM.";
3626 helper_->ConsumeTextureCHROMIUMImmediate(target, data);
3627 CheckGLError();
3630 GLuint GLES2Implementation::CreateAndConsumeTextureCHROMIUM(
3631 GLenum target, const GLbyte* data) {
3632 GPU_CLIENT_SINGLE_THREAD_CHECK();
3633 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateAndConsumeTextureCHROMIUM("
3634 << static_cast<const void*>(data) << ")");
3635 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
3636 DCHECK(mailbox.Verify()) << "CreateAndConsumeTextureCHROMIUM was passed a "
3637 "mailbox that was not generated by "
3638 "GenMailboxCHROMIUM.";
3639 GLuint client_id;
3640 GetIdHandler(id_namespaces::kTextures)->MakeIds(this, 0, 1, &client_id);
3641 helper_->CreateAndConsumeTextureCHROMIUMImmediate(target,
3642 client_id, data);
3643 if (share_group_->bind_generates_resource())
3644 helper_->CommandBufferHelper::Flush();
3645 CheckGLError();
3646 return client_id;
3649 void GLES2Implementation::PushGroupMarkerEXT(
3650 GLsizei length, const GLchar* marker) {
3651 GPU_CLIENT_SINGLE_THREAD_CHECK();
3652 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
3653 << length << ", " << marker << ")");
3654 if (!marker) {
3655 marker = "";
3657 SetBucketAsString(
3658 kResultBucketId,
3659 (length ? std::string(marker, length) : std::string(marker)));
3660 helper_->PushGroupMarkerEXT(kResultBucketId);
3661 helper_->SetBucketSize(kResultBucketId, 0);
3662 debug_marker_manager_.PushGroup(
3663 length ? std::string(marker, length) : std::string(marker));
3666 void GLES2Implementation::InsertEventMarkerEXT(
3667 GLsizei length, const GLchar* marker) {
3668 GPU_CLIENT_SINGLE_THREAD_CHECK();
3669 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
3670 << length << ", " << marker << ")");
3671 if (!marker) {
3672 marker = "";
3674 SetBucketAsString(
3675 kResultBucketId,
3676 (length ? std::string(marker, length) : std::string(marker)));
3677 helper_->InsertEventMarkerEXT(kResultBucketId);
3678 helper_->SetBucketSize(kResultBucketId, 0);
3679 debug_marker_manager_.SetMarker(
3680 length ? std::string(marker, length) : std::string(marker));
3683 void GLES2Implementation::PopGroupMarkerEXT() {
3684 GPU_CLIENT_SINGLE_THREAD_CHECK();
3685 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
3686 helper_->PopGroupMarkerEXT();
3687 debug_marker_manager_.PopGroup();
3690 void GLES2Implementation::TraceBeginCHROMIUM(const char* name) {
3691 GPU_CLIENT_SINGLE_THREAD_CHECK();
3692 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
3693 << name << ")");
3694 if (current_trace_name_.get()) {
3695 SetGLError(GL_INVALID_OPERATION, "glTraceBeginCHROMIUM",
3696 "trace already running");
3697 return;
3699 TRACE_EVENT_COPY_ASYNC_BEGIN0("gpu", name, this);
3700 SetBucketAsCString(kResultBucketId, name);
3701 helper_->TraceBeginCHROMIUM(kResultBucketId);
3702 helper_->SetBucketSize(kResultBucketId, 0);
3703 current_trace_name_.reset(new std::string(name));
3706 void GLES2Implementation::TraceEndCHROMIUM() {
3707 GPU_CLIENT_SINGLE_THREAD_CHECK();
3708 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
3709 if (!current_trace_name_.get()) {
3710 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
3711 "missing begin trace");
3712 return;
3714 helper_->TraceEndCHROMIUM();
3715 TRACE_EVENT_COPY_ASYNC_END0("gpu", current_trace_name_->c_str(), this);
3716 current_trace_name_.reset();
3719 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
3720 GPU_CLIENT_SINGLE_THREAD_CHECK();
3721 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
3722 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
3723 switch (target) {
3724 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3725 if (access != GL_READ_ONLY) {
3726 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3727 return NULL;
3729 break;
3730 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3731 if (access != GL_WRITE_ONLY) {
3732 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3733 return NULL;
3735 break;
3736 default:
3737 SetGLError(
3738 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
3739 return NULL;
3741 GLuint buffer_id;
3742 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
3743 if (!buffer_id) {
3744 return NULL;
3746 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3747 if (!buffer) {
3748 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
3749 return NULL;
3751 if (buffer->mapped()) {
3752 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
3753 return NULL;
3755 // Here we wait for previous transfer operations to be finished.
3756 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
3757 // with this method of synchronization. Until this is fixed,
3758 // MapBufferCHROMIUM will not block even if the transfer is not ready
3759 // for these calls.
3760 if (buffer->last_usage_token()) {
3761 helper_->WaitForToken(buffer->last_usage_token());
3762 buffer->set_last_usage_token(0);
3764 buffer->set_mapped(true);
3766 GPU_CLIENT_LOG(" returned " << buffer->address());
3767 CheckGLError();
3768 return buffer->address();
3771 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
3772 GPU_CLIENT_SINGLE_THREAD_CHECK();
3773 GPU_CLIENT_LOG(
3774 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
3775 GLuint buffer_id;
3776 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
3777 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
3779 if (!buffer_id) {
3780 return false;
3782 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3783 if (!buffer) {
3784 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
3785 return false;
3787 if (!buffer->mapped()) {
3788 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
3789 return false;
3791 buffer->set_mapped(false);
3792 CheckGLError();
3793 return true;
3796 bool GLES2Implementation::EnsureAsyncUploadSync() {
3797 if (async_upload_sync_)
3798 return true;
3800 int32 shm_id;
3801 unsigned int shm_offset;
3802 void* mem = mapped_memory_->Alloc(sizeof(AsyncUploadSync),
3803 &shm_id,
3804 &shm_offset);
3805 if (!mem)
3806 return false;
3808 async_upload_sync_shm_id_ = shm_id;
3809 async_upload_sync_shm_offset_ = shm_offset;
3810 async_upload_sync_ = static_cast<AsyncUploadSync*>(mem);
3811 async_upload_sync_->Reset();
3813 return true;
3816 uint32 GLES2Implementation::NextAsyncUploadToken() {
3817 async_upload_token_++;
3818 if (async_upload_token_ == 0)
3819 async_upload_token_++;
3820 return async_upload_token_;
3823 void GLES2Implementation::PollAsyncUploads() {
3824 if (!async_upload_sync_)
3825 return;
3827 if (helper_->IsContextLost()) {
3828 DetachedAsyncUploadMemoryList::iterator it =
3829 detached_async_upload_memory_.begin();
3830 while (it != detached_async_upload_memory_.end()) {
3831 mapped_memory_->Free(it->first);
3832 it = detached_async_upload_memory_.erase(it);
3834 return;
3837 DetachedAsyncUploadMemoryList::iterator it =
3838 detached_async_upload_memory_.begin();
3839 while (it != detached_async_upload_memory_.end()) {
3840 if (HasAsyncUploadTokenPassed(it->second)) {
3841 mapped_memory_->Free(it->first);
3842 it = detached_async_upload_memory_.erase(it);
3843 } else {
3844 break;
3849 void GLES2Implementation::FreeAllAsyncUploadBuffers() {
3850 // Free all completed unmanaged async uploads buffers.
3851 PollAsyncUploads();
3853 // Synchronously free rest of the unmanaged async upload buffers.
3854 if (!detached_async_upload_memory_.empty()) {
3855 WaitAllAsyncTexImage2DCHROMIUM();
3856 WaitForCmd();
3857 PollAsyncUploads();
3861 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
3862 GLenum target, GLint level, GLenum internalformat, GLsizei width,
3863 GLsizei height, GLint border, GLenum format, GLenum type,
3864 const void* pixels) {
3865 GPU_CLIENT_SINGLE_THREAD_CHECK();
3866 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
3867 << GLES2Util::GetStringTextureTarget(target) << ", "
3868 << level << ", "
3869 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
3870 << width << ", " << height << ", " << border << ", "
3871 << GLES2Util::GetStringTextureFormat(format) << ", "
3872 << GLES2Util::GetStringPixelType(type) << ", "
3873 << static_cast<const void*>(pixels) << ")");
3874 if (level < 0 || height < 0 || width < 0) {
3875 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
3876 return;
3878 if (border != 0) {
3879 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "border != 0");
3880 return;
3882 uint32 size;
3883 uint32 unpadded_row_size;
3884 uint32 padded_row_size;
3885 if (!GLES2Util::ComputeImageDataSizes(
3886 width, height, format, type, unpack_alignment_, &size,
3887 &unpadded_row_size, &padded_row_size)) {
3888 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
3889 return;
3892 // If there's no data/buffer just issue the AsyncTexImage2D
3893 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
3894 helper_->AsyncTexImage2DCHROMIUM(
3895 target, level, internalformat, width, height, format, type,
3896 0, 0, 0, 0, 0);
3897 return;
3900 if (!EnsureAsyncUploadSync()) {
3901 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
3902 return;
3905 // Otherwise, async uploads require a transfer buffer to be bound.
3906 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3907 // the buffer before the transfer is finished. (Currently such
3908 // synchronization has to be handled manually.)
3909 GLuint offset = ToGLuint(pixels);
3910 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3911 bound_pixel_unpack_transfer_buffer_id_,
3912 "glAsyncTexImage2DCHROMIUM", offset, size);
3913 if (buffer && buffer->shm_id() != -1) {
3914 uint32 async_token = NextAsyncUploadToken();
3915 buffer->set_last_async_upload_token(async_token);
3916 helper_->AsyncTexImage2DCHROMIUM(
3917 target, level, internalformat, width, height, format, type,
3918 buffer->shm_id(), buffer->shm_offset() + offset,
3919 async_token,
3920 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
3924 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
3925 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
3926 GLsizei height, GLenum format, GLenum type, const void* pixels) {
3927 GPU_CLIENT_SINGLE_THREAD_CHECK();
3928 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
3929 << GLES2Util::GetStringTextureTarget(target) << ", "
3930 << level << ", "
3931 << xoffset << ", " << yoffset << ", "
3932 << width << ", " << height << ", "
3933 << GLES2Util::GetStringTextureFormat(format) << ", "
3934 << GLES2Util::GetStringPixelType(type) << ", "
3935 << static_cast<const void*>(pixels) << ")");
3936 if (level < 0 || height < 0 || width < 0) {
3937 SetGLError(
3938 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
3939 return;
3942 uint32 size;
3943 uint32 unpadded_row_size;
3944 uint32 padded_row_size;
3945 if (!GLES2Util::ComputeImageDataSizes(
3946 width, height, format, type, unpack_alignment_, &size,
3947 &unpadded_row_size, &padded_row_size)) {
3948 SetGLError(
3949 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
3950 return;
3953 if (!EnsureAsyncUploadSync()) {
3954 SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
3955 return;
3958 // Async uploads require a transfer buffer to be bound.
3959 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3960 // the buffer before the transfer is finished. (Currently such
3961 // synchronization has to be handled manually.)
3962 GLuint offset = ToGLuint(pixels);
3963 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3964 bound_pixel_unpack_transfer_buffer_id_,
3965 "glAsyncTexSubImage2DCHROMIUM", offset, size);
3966 if (buffer && buffer->shm_id() != -1) {
3967 uint32 async_token = NextAsyncUploadToken();
3968 buffer->set_last_async_upload_token(async_token);
3969 helper_->AsyncTexSubImage2DCHROMIUM(
3970 target, level, xoffset, yoffset, width, height, format, type,
3971 buffer->shm_id(), buffer->shm_offset() + offset,
3972 async_token,
3973 async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
3977 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
3978 GPU_CLIENT_SINGLE_THREAD_CHECK();
3979 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
3980 << GLES2Util::GetStringTextureTarget(target) << ")");
3981 helper_->WaitAsyncTexImage2DCHROMIUM(target);
3982 CheckGLError();
3985 void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
3986 GPU_CLIENT_SINGLE_THREAD_CHECK();
3987 GPU_CLIENT_LOG("[" << GetLogPrefix()
3988 << "] glWaitAllAsyncTexImage2DCHROMIUM()");
3989 helper_->WaitAllAsyncTexImage2DCHROMIUM();
3990 CheckGLError();
3993 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
3994 GPU_CLIENT_SINGLE_THREAD_CHECK();
3995 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
3996 helper_->CommandBufferHelper::Flush();
3997 return gpu_control_->InsertSyncPoint();
4000 GLuint GLES2Implementation::InsertFutureSyncPointCHROMIUM() {
4001 GPU_CLIENT_SINGLE_THREAD_CHECK();
4002 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertFutureSyncPointCHROMIUM");
4003 DCHECK(capabilities_.future_sync_points);
4004 helper_->CommandBufferHelper::Flush();
4005 return gpu_control_->InsertFutureSyncPoint();
4008 void GLES2Implementation::RetireSyncPointCHROMIUM(GLuint sync_point) {
4009 GPU_CLIENT_SINGLE_THREAD_CHECK();
4010 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRetireSyncPointCHROMIUM("
4011 << sync_point << ")");
4012 DCHECK(capabilities_.future_sync_points);
4013 helper_->CommandBufferHelper::Flush();
4014 gpu_control_->RetireSyncPoint(sync_point);
4017 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(GLsizei width,
4018 GLsizei height,
4019 GLenum internalformat,
4020 GLenum usage) {
4021 if (width <= 0) {
4022 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
4023 return 0;
4026 if (height <= 0) {
4027 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
4028 return 0;
4030 // Flush the command stream to ensure ordering in case the newly
4031 // returned image_id has recently been in use with a different buffer.
4032 helper_->CommandBufferHelper::Flush();
4034 // Create new buffer.
4035 GLuint buffer_id = gpu_memory_buffer_tracker_->CreateBuffer(
4036 width, height, internalformat, usage);
4037 if (buffer_id == 0) {
4038 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "out of GPU memory.");
4039 return 0;
4041 return buffer_id;
4044 GLuint GLES2Implementation::CreateImageCHROMIUM(GLsizei width,
4045 GLsizei height,
4046 GLenum internalformat,
4047 GLenum usage) {
4048 GPU_CLIENT_SINGLE_THREAD_CHECK();
4049 GPU_CLIENT_LOG(
4050 "[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width << ", "
4051 << height << ", "
4052 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
4053 << GLES2Util::GetStringTextureInternalFormat(usage) << ")");
4054 GLuint image_id =
4055 CreateImageCHROMIUMHelper(width, height, internalformat, usage);
4056 CheckGLError();
4057 return image_id;
4060 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
4061 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
4062 image_id);
4063 if (!gpu_buffer) {
4064 SetGLError(GL_INVALID_OPERATION, "glDestroyImageCHROMIUM", "invalid image");
4065 return;
4068 // Flush the command stream to make sure all pending commands
4069 // that may refer to the image_id are executed on the service side.
4070 helper_->CommandBufferHelper::Flush();
4071 gpu_memory_buffer_tracker_->RemoveBuffer(image_id);
4074 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
4075 GPU_CLIENT_SINGLE_THREAD_CHECK();
4076 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
4077 << image_id << ")");
4078 DestroyImageCHROMIUMHelper(image_id);
4079 CheckGLError();
4082 void GLES2Implementation::UnmapImageCHROMIUMHelper(GLuint image_id) {
4083 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
4084 image_id);
4085 if (!gpu_buffer) {
4086 SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "invalid image");
4087 return;
4090 if (!gpu_buffer->IsMapped()) {
4091 SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "not mapped");
4092 return;
4094 gpu_buffer->Unmap();
4097 void GLES2Implementation::UnmapImageCHROMIUM(GLuint image_id) {
4098 GPU_CLIENT_SINGLE_THREAD_CHECK();
4099 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapImageCHROMIUM("
4100 << image_id << ")");
4102 UnmapImageCHROMIUMHelper(image_id);
4103 CheckGLError();
4106 void* GLES2Implementation::MapImageCHROMIUMHelper(GLuint image_id) {
4107 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
4108 image_id);
4109 if (!gpu_buffer) {
4110 SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "invalid image");
4111 return NULL;
4114 if (gpu_buffer->IsMapped()) {
4115 SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "already mapped");
4116 return NULL;
4119 return gpu_buffer->Map();
4122 void* GLES2Implementation::MapImageCHROMIUM(GLuint image_id) {
4123 GPU_CLIENT_SINGLE_THREAD_CHECK();
4124 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapImageCHROMIUM(" << image_id
4125 << ")");
4127 void* mapped = MapImageCHROMIUMHelper(image_id);
4128 CheckGLError();
4129 return mapped;
4132 void GLES2Implementation::GetImageParameterivCHROMIUMHelper(
4133 GLuint image_id, GLenum pname, GLint* params) {
4134 if (pname != GL_IMAGE_ROWBYTES_CHROMIUM) {
4135 SetGLError(GL_INVALID_ENUM, "glGetImageParameterivCHROMIUM",
4136 "invalid parameter");
4137 return;
4140 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
4141 image_id);
4142 if (!gpu_buffer) {
4143 SetGLError(GL_INVALID_OPERATION, "glGetImageParameterivCHROMIUM",
4144 "invalid image");
4145 return;
4148 if (!gpu_buffer->IsMapped()) {
4149 SetGLError(
4150 GL_INVALID_OPERATION, "glGetImageParameterivCHROMIUM", "not mapped");
4151 return;
4154 *params = gpu_buffer->GetStride();
4157 void GLES2Implementation::GetImageParameterivCHROMIUM(
4158 GLuint image_id, GLenum pname, GLint* params) {
4159 GPU_CLIENT_SINGLE_THREAD_CHECK();
4160 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
4161 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glImageParameterivCHROMIUM("
4162 << image_id << ", "
4163 << GLES2Util::GetStringBufferParameter(pname) << ", "
4164 << static_cast<const void*>(params) << ")");
4165 GetImageParameterivCHROMIUMHelper(image_id, pname, params);
4166 CheckGLError();
4169 bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
4170 if (size < 0) {
4171 SetGLError(GL_INVALID_VALUE, func, "size < 0");
4172 return false;
4174 if (!FitInt32NonNegative<GLsizeiptr>(size)) {
4175 SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
4176 return false;
4178 return true;
4181 bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
4182 if (offset < 0) {
4183 SetGLError(GL_INVALID_VALUE, func, "offset < 0");
4184 return false;
4186 if (!FitInt32NonNegative<GLintptr>(offset)) {
4187 SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
4188 return false;
4190 return true;
4193 // Include the auto-generated part of this file. We split this because it means
4194 // we can easily edit the non-auto generated parts right here in this file
4195 // instead of having to edit some template or the code generator.
4196 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
4198 } // namespace gles2
4199 } // namespace gpu