Add explicit |forceOnlineSignin| to user pod status
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blob93aa3d63a61b9a2dee29f7f87f067fe79233fe31
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 <algorithm>
10 #include <map>
11 #include <queue>
12 #include <set>
13 #include <limits>
14 #include <stdio.h>
15 #include <string.h>
16 #include <GLES2/gl2ext.h>
17 #include <GLES2/gl2extchromium.h>
18 #include "gpu/command_buffer/client/buffer_tracker.h"
19 #include "gpu/command_buffer/client/gpu_memory_buffer_tracker.h"
20 #include "gpu/command_buffer/client/program_info_manager.h"
21 #include "gpu/command_buffer/client/query_tracker.h"
22 #include "gpu/command_buffer/client/transfer_buffer.h"
23 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
24 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
25 #include "gpu/command_buffer/common/gpu_control.h"
26 #include "gpu/command_buffer/common/trace_event.h"
27 #include "ui/gfx/gpu_memory_buffer.h"
29 #if defined(__native_client__) && !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
30 #define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS
31 #endif
33 #if defined(GPU_CLIENT_DEBUG)
34 #include "ui/gl/gl_switches.h"
35 #include "base/command_line.h"
36 #endif
38 namespace gpu {
39 namespace gles2 {
41 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
42 static GLuint ToGLuint(const void* ptr) {
43 return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
46 #if !defined(_MSC_VER)
47 const size_t GLES2Implementation::kMaxSizeOfSimpleResult;
48 const unsigned int GLES2Implementation::kStartingOffset;
49 #endif
51 GLES2Implementation::GLStaticState::GLStaticState() {
54 GLES2Implementation::GLStaticState::~GLStaticState() {
57 GLES2Implementation::GLStaticState::IntState::IntState()
58 : max_combined_texture_image_units(0),
59 max_cube_map_texture_size(0),
60 max_fragment_uniform_vectors(0),
61 max_renderbuffer_size(0),
62 max_texture_image_units(0),
63 max_texture_size(0),
64 max_varying_vectors(0),
65 max_vertex_attribs(0),
66 max_vertex_texture_image_units(0),
67 max_vertex_uniform_vectors(0),
68 num_compressed_texture_formats(0),
69 num_shader_binary_formats(0) {
72 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
73 GLES2Implementation* gles2_implementation)
74 : gles2_implementation_(gles2_implementation) {
75 CHECK_EQ(0, gles2_implementation_->use_count_);
76 ++gles2_implementation_->use_count_;
79 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
80 --gles2_implementation_->use_count_;
81 CHECK_EQ(0, gles2_implementation_->use_count_);
84 GLES2Implementation::GLES2Implementation(
85 GLES2CmdHelper* helper,
86 ShareGroup* share_group,
87 TransferBufferInterface* transfer_buffer,
88 bool bind_generates_resource,
89 bool free_everything_when_invisible,
90 GpuControl* gpu_control)
91 : helper_(helper),
92 transfer_buffer_(transfer_buffer),
93 angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
94 chromium_framebuffer_multisample_(kUnknownExtensionStatus),
95 pack_alignment_(4),
96 unpack_alignment_(4),
97 unpack_flip_y_(false),
98 unpack_row_length_(0),
99 unpack_skip_rows_(0),
100 unpack_skip_pixels_(0),
101 pack_reverse_row_order_(false),
102 active_texture_unit_(0),
103 bound_framebuffer_(0),
104 bound_read_framebuffer_(0),
105 bound_renderbuffer_(0),
106 current_program_(0),
107 bound_array_buffer_id_(0),
108 bound_pixel_pack_transfer_buffer_id_(0),
109 bound_pixel_unpack_transfer_buffer_id_(0),
110 error_bits_(0),
111 debug_(false),
112 use_count_(0),
113 error_message_callback_(NULL),
114 gpu_control_(gpu_control),
115 surface_visible_(true),
116 free_everything_when_invisible_(free_everything_when_invisible),
117 capabilities_(gpu_control->GetCapabilities()),
118 weak_ptr_factory_(this) {
119 DCHECK(helper);
120 DCHECK(transfer_buffer);
121 DCHECK(gpu_control);
123 char temp[128];
124 sprintf(temp, "%p", static_cast<void*>(this));
125 this_in_hex_ = std::string(temp);
127 GPU_CLIENT_LOG_CODE_BLOCK({
128 debug_ = CommandLine::ForCurrentProcess()->HasSwitch(
129 switches::kEnableGPUClientLogging);
132 share_group_ =
133 (share_group ? share_group : new ShareGroup(bind_generates_resource));
135 memset(&reserved_ids_, 0, sizeof(reserved_ids_));
138 bool GLES2Implementation::Initialize(
139 unsigned int starting_transfer_buffer_size,
140 unsigned int min_transfer_buffer_size,
141 unsigned int max_transfer_buffer_size,
142 unsigned int mapped_memory_limit) {
143 DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
144 DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
145 DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
147 if (!transfer_buffer_->Initialize(
148 starting_transfer_buffer_size,
149 kStartingOffset,
150 min_transfer_buffer_size,
151 max_transfer_buffer_size,
152 kAlignment,
153 kSizeToFlush)) {
154 return false;
157 mapped_memory_.reset(new MappedMemoryManager(helper_, mapped_memory_limit));
159 unsigned chunk_size = 2 * 1024 * 1024;
160 if (mapped_memory_limit != kNoLimit) {
161 // Use smaller chunks if the client is very memory conscientious.
162 chunk_size = std::min(mapped_memory_limit / 4, chunk_size);
164 mapped_memory_->set_chunk_size_multiple(chunk_size);
166 if (!QueryAndCacheStaticState())
167 return false;
169 util_.set_num_compressed_texture_formats(
170 static_state_.int_state.num_compressed_texture_formats);
171 util_.set_num_shader_binary_formats(
172 static_state_.int_state.num_shader_binary_formats);
174 texture_units_.reset(
175 new TextureUnit[
176 static_state_.int_state.max_combined_texture_image_units]);
178 query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
179 buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
180 gpu_memory_buffer_tracker_.reset(new GpuMemoryBufferTracker(gpu_control_));
182 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
183 GetIdHandler(id_namespaces::kBuffers)->MakeIds(
184 this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
185 #endif
187 vertex_array_object_manager_.reset(new VertexArrayObjectManager(
188 static_state_.int_state.max_vertex_attribs,
189 reserved_ids_[0],
190 reserved_ids_[1]));
192 return true;
195 bool GLES2Implementation::QueryAndCacheStaticState() {
196 // Setup query for multiple GetIntegerv's
197 static const GLenum pnames[] = {
198 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
199 GL_MAX_CUBE_MAP_TEXTURE_SIZE,
200 GL_MAX_FRAGMENT_UNIFORM_VECTORS,
201 GL_MAX_RENDERBUFFER_SIZE,
202 GL_MAX_TEXTURE_IMAGE_UNITS,
203 GL_MAX_TEXTURE_SIZE,
204 GL_MAX_VARYING_VECTORS,
205 GL_MAX_VERTEX_ATTRIBS,
206 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
207 GL_MAX_VERTEX_UNIFORM_VECTORS,
208 GL_NUM_COMPRESSED_TEXTURE_FORMATS,
209 GL_NUM_SHADER_BINARY_FORMATS,
212 GetMultipleIntegervState integerv_state(
213 pnames, arraysize(pnames),
214 &static_state_.int_state.max_combined_texture_image_units,
215 sizeof(static_state_.int_state));
216 if (!GetMultipleIntegervSetup(&integerv_state)) {
217 return false;
220 // Setup query for multiple GetShaderPrecisionFormat's
221 static const GLenum precision_params[][2] = {
222 { GL_VERTEX_SHADER, GL_LOW_INT },
223 { GL_VERTEX_SHADER, GL_MEDIUM_INT },
224 { GL_VERTEX_SHADER, GL_HIGH_INT },
225 { GL_VERTEX_SHADER, GL_LOW_FLOAT },
226 { GL_VERTEX_SHADER, GL_MEDIUM_FLOAT },
227 { GL_VERTEX_SHADER, GL_HIGH_FLOAT },
228 { GL_FRAGMENT_SHADER, GL_LOW_INT },
229 { GL_FRAGMENT_SHADER, GL_MEDIUM_INT },
230 { GL_FRAGMENT_SHADER, GL_HIGH_INT },
231 { GL_FRAGMENT_SHADER, GL_LOW_FLOAT },
232 { GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT },
233 { GL_FRAGMENT_SHADER, GL_HIGH_FLOAT },
236 GetAllShaderPrecisionFormatsState precision_state(
237 precision_params, arraysize(precision_params));
238 GetAllShaderPrecisionFormatsSetup(&precision_state);
240 // Allocate and partition transfer buffer for all requests
241 void* buffer = transfer_buffer_->Alloc(
242 integerv_state.transfer_buffer_size_needed +
243 precision_state.transfer_buffer_size_needed);
244 if (!buffer) {
245 SetGLError(GL_OUT_OF_MEMORY, "QueryAndCacheStaticState",
246 "Transfer buffer allocation failed.");
247 return false;
249 integerv_state.buffer = buffer;
250 precision_state.results_buffer =
251 static_cast<char*>(buffer) + integerv_state.transfer_buffer_size_needed;
253 // Make all the requests and wait once for all the results.
254 GetMultipleIntegervRequest(&integerv_state);
255 GetAllShaderPrecisionFormatsRequest(&precision_state);
256 WaitForCmd();
257 GetMultipleIntegervOnCompleted(&integerv_state);
258 GetAllShaderPrecisionFormatsOnCompleted(&precision_state);
260 // TODO(gman): We should be able to free without a token.
261 transfer_buffer_->FreePendingToken(buffer, helper_->InsertToken());
262 CheckGLError();
264 return true;
267 GLES2Implementation::~GLES2Implementation() {
268 // Make sure the queries are finished otherwise we'll delete the
269 // shared memory (mapped_memory_) which will free the memory used
270 // by the queries. The GPU process when validating that memory is still
271 // shared will fail and abort (ie, it will stop running).
272 WaitForCmd();
273 query_tracker_.reset();
275 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
276 DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
277 #endif
278 buffer_tracker_.reset();
280 // Make sure the commands make it the service.
281 WaitForCmd();
284 GLES2CmdHelper* GLES2Implementation::helper() const {
285 return helper_;
288 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
289 return share_group_->GetIdHandler(namespace_id);
292 void* GLES2Implementation::GetResultBuffer() {
293 return transfer_buffer_->GetResultBuffer();
296 int32 GLES2Implementation::GetResultShmId() {
297 return transfer_buffer_->GetShmId();
300 uint32 GLES2Implementation::GetResultShmOffset() {
301 return transfer_buffer_->GetResultOffset();
304 void GLES2Implementation::FreeUnusedSharedMemory() {
305 mapped_memory_->FreeUnused();
308 void GLES2Implementation::FreeEverything() {
309 WaitForCmd();
310 query_tracker_->Shrink();
311 FreeUnusedSharedMemory();
312 transfer_buffer_->Free();
313 helper_->FreeRingBuffer();
316 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
317 if (!helper_->IsContextLost())
318 callback.Run();
321 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
322 const base::Closure& callback) {
323 gpu_control_->SignalSyncPoint(
324 sync_point,
325 base::Bind(&GLES2Implementation::RunIfContextNotLost,
326 weak_ptr_factory_.GetWeakPtr(),
327 callback));
330 void GLES2Implementation::SignalQuery(uint32 query,
331 const base::Closure& callback) {
332 // Flush previously entered commands to ensure ordering with any
333 // glBeginQueryEXT() calls that may have been put into the context.
334 ShallowFlushCHROMIUM();
335 gpu_control_->SignalQuery(
336 query,
337 base::Bind(&GLES2Implementation::RunIfContextNotLost,
338 weak_ptr_factory_.GetWeakPtr(),
339 callback));
342 void GLES2Implementation::SetSurfaceVisible(bool visible) {
343 // TODO(piman): This probably should be ShallowFlushCHROMIUM().
344 Flush();
345 surface_visible_ = visible;
346 gpu_control_->SetSurfaceVisible(visible);
347 if (!visible)
348 FreeEverything();
351 void GLES2Implementation::SendManagedMemoryStats(
352 const ManagedMemoryStats& stats) {
353 gpu_control_->SendManagedMemoryStats(stats);
356 void GLES2Implementation::WaitForCmd() {
357 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
358 helper_->CommandBufferHelper::Finish();
361 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
362 const char* extensions =
363 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
364 if (!extensions)
365 return false;
367 int length = strlen(ext);
368 while (true) {
369 int n = strcspn(extensions, " ");
370 if (n == length && 0 == strncmp(ext, extensions, length)) {
371 return true;
373 if ('\0' == extensions[n]) {
374 return false;
376 extensions += n + 1;
380 bool GLES2Implementation::IsExtensionAvailableHelper(
381 const char* extension, ExtensionStatus* status) {
382 switch (*status) {
383 case kAvailableExtensionStatus:
384 return true;
385 case kUnavailableExtensionStatus:
386 return false;
387 default: {
388 bool available = IsExtensionAvailable(extension);
389 *status = available ? kAvailableExtensionStatus :
390 kUnavailableExtensionStatus;
391 return available;
396 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
397 return IsExtensionAvailableHelper(
398 "GL_ANGLE_pack_reverse_row_order",
399 &angle_pack_reverse_row_order_status_);
402 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
403 return IsExtensionAvailableHelper(
404 "GL_CHROMIUM_framebuffer_multisample",
405 &chromium_framebuffer_multisample_);
408 const std::string& GLES2Implementation::GetLogPrefix() const {
409 const std::string& prefix(debug_marker_manager_.GetMarker());
410 return prefix.empty() ? this_in_hex_ : prefix;
413 GLenum GLES2Implementation::GetError() {
414 GPU_CLIENT_SINGLE_THREAD_CHECK();
415 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
416 GLenum err = GetGLError();
417 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
418 return err;
421 GLenum GLES2Implementation::GetClientSideGLError() {
422 if (error_bits_ == 0) {
423 return GL_NO_ERROR;
426 GLenum error = GL_NO_ERROR;
427 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
428 if ((error_bits_ & mask) != 0) {
429 error = GLES2Util::GLErrorBitToGLError(mask);
430 break;
433 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
434 return error;
437 GLenum GLES2Implementation::GetGLError() {
438 TRACE_EVENT0("gpu", "GLES2::GetGLError");
439 // Check the GL error first, then our wrapped error.
440 typedef cmds::GetError::Result Result;
441 Result* result = GetResultAs<Result*>();
442 // If we couldn't allocate a result the context is lost.
443 if (!result) {
444 return GL_NO_ERROR;
446 *result = GL_NO_ERROR;
447 helper_->GetError(GetResultShmId(), GetResultShmOffset());
448 WaitForCmd();
449 GLenum error = *result;
450 if (error == GL_NO_ERROR) {
451 error = GetClientSideGLError();
452 } else {
453 // There was an error, clear the corresponding wrapped error.
454 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
456 return error;
459 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
460 void GLES2Implementation::FailGLError(GLenum error) {
461 if (error != GL_NO_ERROR) {
462 NOTREACHED() << "Error";
465 // NOTE: Calling GetGLError overwrites data in the result buffer.
466 void GLES2Implementation::CheckGLError() {
467 FailGLError(GetGLError());
469 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
471 void GLES2Implementation::SetGLError(
472 GLenum error, const char* function_name, const char* msg) {
473 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
474 << GLES2Util::GetStringError(error) << ": "
475 << function_name << ": " << msg);
476 FailGLError(error);
477 if (msg) {
478 last_error_ = msg;
480 if (error_message_callback_) {
481 std::string temp(GLES2Util::GetStringError(error) + " : " +
482 function_name + ": " + (msg ? msg : ""));
483 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
485 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
488 void GLES2Implementation::SetGLErrorInvalidEnum(
489 const char* function_name, GLenum value, const char* label) {
490 SetGLError(GL_INVALID_ENUM, function_name,
491 (std::string(label) + " was " +
492 GLES2Util::GetStringEnum(value)).c_str());
495 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
496 std::vector<int8>* data) {
497 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
498 DCHECK(data);
499 const uint32 kStartSize = 32 * 1024;
500 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
501 if (!buffer.valid()) {
502 return false;
504 typedef cmd::GetBucketStart::Result Result;
505 Result* result = GetResultAs<Result*>();
506 if (!result) {
507 return false;
509 *result = 0;
510 helper_->GetBucketStart(
511 bucket_id, GetResultShmId(), GetResultShmOffset(),
512 buffer.size(), buffer.shm_id(), buffer.offset());
513 WaitForCmd();
514 uint32 size = *result;
515 data->resize(size);
516 if (size > 0u) {
517 uint32 offset = 0;
518 while (size) {
519 if (!buffer.valid()) {
520 buffer.Reset(size);
521 if (!buffer.valid()) {
522 return false;
524 helper_->GetBucketData(
525 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
526 WaitForCmd();
528 uint32 size_to_copy = std::min(size, buffer.size());
529 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
530 offset += size_to_copy;
531 size -= size_to_copy;
532 buffer.Release();
534 // Free the bucket. This is not required but it does free up the memory.
535 // and we don't have to wait for the result so from the client's perspective
536 // it's cheap.
537 helper_->SetBucketSize(bucket_id, 0);
539 return true;
542 void GLES2Implementation::SetBucketContents(
543 uint32 bucket_id, const void* data, size_t size) {
544 DCHECK(data);
545 helper_->SetBucketSize(bucket_id, size);
546 if (size > 0u) {
547 uint32 offset = 0;
548 while (size) {
549 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
550 if (!buffer.valid()) {
551 return;
553 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
554 buffer.size());
555 helper_->SetBucketData(
556 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
557 offset += buffer.size();
558 size -= buffer.size();
563 void GLES2Implementation::SetBucketAsCString(
564 uint32 bucket_id, const char* str) {
565 // NOTE: strings are passed NULL terminated. That means the empty
566 // string will have a size of 1 and no-string will have a size of 0
567 if (str) {
568 SetBucketContents(bucket_id, str, strlen(str) + 1);
569 } else {
570 helper_->SetBucketSize(bucket_id, 0);
574 bool GLES2Implementation::GetBucketAsString(
575 uint32 bucket_id, std::string* str) {
576 DCHECK(str);
577 std::vector<int8> data;
578 // NOTE: strings are passed NULL terminated. That means the empty
579 // string will have a size of 1 and no-string will have a size of 0
580 if (!GetBucketContents(bucket_id, &data)) {
581 return false;
583 if (data.empty()) {
584 return false;
586 str->assign(&data[0], &data[0] + data.size() - 1);
587 return true;
590 void GLES2Implementation::SetBucketAsString(
591 uint32 bucket_id, const std::string& str) {
592 // NOTE: strings are passed NULL terminated. That means the empty
593 // string will have a size of 1 and no-string will have a size of 0
594 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
597 void GLES2Implementation::Disable(GLenum cap) {
598 GPU_CLIENT_SINGLE_THREAD_CHECK();
599 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
600 << GLES2Util::GetStringCapability(cap) << ")");
601 bool changed = false;
602 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
603 helper_->Disable(cap);
605 CheckGLError();
608 void GLES2Implementation::Enable(GLenum cap) {
609 GPU_CLIENT_SINGLE_THREAD_CHECK();
610 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
611 << GLES2Util::GetStringCapability(cap) << ")");
612 bool changed = false;
613 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
614 helper_->Enable(cap);
616 CheckGLError();
619 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
620 GPU_CLIENT_SINGLE_THREAD_CHECK();
621 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
622 << GLES2Util::GetStringCapability(cap) << ")");
623 bool state = false;
624 if (!state_.GetEnabled(cap, &state)) {
625 typedef cmds::IsEnabled::Result Result;
626 Result* result = GetResultAs<Result*>();
627 if (!result) {
628 return GL_FALSE;
630 *result = 0;
631 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
632 WaitForCmd();
633 state = (*result) != 0;
636 GPU_CLIENT_LOG("returned " << state);
637 CheckGLError();
638 return state;
641 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
642 switch (pname) {
643 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
644 *params = static_state_.int_state.max_combined_texture_image_units;
645 return true;
646 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
647 *params = static_state_.int_state.max_cube_map_texture_size;
648 return true;
649 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
650 *params = static_state_.int_state.max_fragment_uniform_vectors;
651 return true;
652 case GL_MAX_RENDERBUFFER_SIZE:
653 *params = static_state_.int_state.max_renderbuffer_size;
654 return true;
655 case GL_MAX_TEXTURE_IMAGE_UNITS:
656 *params = static_state_.int_state.max_texture_image_units;
657 return true;
658 case GL_MAX_TEXTURE_SIZE:
659 *params = static_state_.int_state.max_texture_size;
660 return true;
661 case GL_MAX_VARYING_VECTORS:
662 *params = static_state_.int_state.max_varying_vectors;
663 return true;
664 case GL_MAX_VERTEX_ATTRIBS:
665 *params = static_state_.int_state.max_vertex_attribs;
666 return true;
667 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
668 *params = static_state_.int_state.max_vertex_texture_image_units;
669 return true;
670 case GL_MAX_VERTEX_UNIFORM_VECTORS:
671 *params = static_state_.int_state.max_vertex_uniform_vectors;
672 return true;
673 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
674 *params = static_state_.int_state.num_compressed_texture_formats;
675 return true;
676 case GL_NUM_SHADER_BINARY_FORMATS:
677 *params = static_state_.int_state.num_shader_binary_formats;
678 return true;
679 case GL_ARRAY_BUFFER_BINDING:
680 if (share_group_->bind_generates_resource()) {
681 *params = bound_array_buffer_id_;
682 return true;
684 return false;
685 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
686 if (share_group_->bind_generates_resource()) {
687 *params =
688 vertex_array_object_manager_->bound_element_array_buffer();
689 return true;
691 return false;
692 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
693 *params = bound_pixel_pack_transfer_buffer_id_;
694 return true;
695 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
696 *params = bound_pixel_unpack_transfer_buffer_id_;
697 return true;
698 case GL_ACTIVE_TEXTURE:
699 *params = active_texture_unit_ + GL_TEXTURE0;
700 return true;
701 case GL_TEXTURE_BINDING_2D:
702 if (share_group_->bind_generates_resource()) {
703 *params = texture_units_[active_texture_unit_].bound_texture_2d;
704 return true;
706 return false;
707 case GL_TEXTURE_BINDING_CUBE_MAP:
708 if (share_group_->bind_generates_resource()) {
709 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
710 return true;
712 return false;
713 case GL_TEXTURE_BINDING_EXTERNAL_OES:
714 if (share_group_->bind_generates_resource()) {
715 *params =
716 texture_units_[active_texture_unit_].bound_texture_external_oes;
717 return true;
719 return false;
720 case GL_FRAMEBUFFER_BINDING:
721 if (share_group_->bind_generates_resource()) {
722 *params = bound_framebuffer_;
723 return true;
725 return false;
726 case GL_READ_FRAMEBUFFER_BINDING:
727 if (IsChromiumFramebufferMultisampleAvailable() &&
728 share_group_->bind_generates_resource()) {
729 *params = bound_read_framebuffer_;
730 return true;
732 return false;
733 case GL_RENDERBUFFER_BINDING:
734 if (share_group_->bind_generates_resource()) {
735 *params = bound_renderbuffer_;
736 return true;
738 return false;
739 default:
740 return false;
744 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
745 // TODO(gman): Make this handle pnames that return more than 1 value.
746 GLint value;
747 if (!GetHelper(pname, &value)) {
748 return false;
750 *params = static_cast<GLboolean>(value);
751 return true;
754 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
755 // TODO(gman): Make this handle pnames that return more than 1 value.
756 GLint value;
757 if (!GetHelper(pname, &value)) {
758 return false;
760 *params = static_cast<GLfloat>(value);
761 return true;
764 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
765 return GetHelper(pname, params);
768 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
769 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
770 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
771 Result* result = GetResultAs<Result*>();
772 if (!result) {
773 return 0;
775 *result = 0;
776 helper_->GetMaxValueInBufferCHROMIUM(
777 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
778 WaitForCmd();
779 return *result;
782 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
783 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
784 GPU_CLIENT_SINGLE_THREAD_CHECK();
785 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
786 << buffer_id << ", " << count << ", "
787 << GLES2Util::GetStringGetMaxIndexType(type)
788 << ", " << offset << ")");
789 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
790 buffer_id, count, type, offset);
791 GPU_CLIENT_LOG("returned " << result);
792 CheckGLError();
793 return result;
796 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
797 if (restore) {
798 RestoreArrayBuffer(restore);
799 // Restore the element array binding.
800 // We only need to restore it if it wasn't a client side array.
801 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
802 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
807 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
808 if (restore) {
809 // Restore the user's current binding.
810 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_);
814 void GLES2Implementation::DrawElements(
815 GLenum mode, GLsizei count, GLenum type, const void* indices) {
816 GPU_CLIENT_SINGLE_THREAD_CHECK();
817 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
818 << GLES2Util::GetStringDrawMode(mode) << ", "
819 << count << ", "
820 << GLES2Util::GetStringIndexType(type) << ", "
821 << static_cast<const void*>(indices) << ")");
822 if (count < 0) {
823 SetGLError(GL_INVALID_VALUE, "glDrawElements", "count less than 0.");
824 return;
826 if (count == 0) {
827 return;
829 GLuint offset = 0;
830 bool simulated = false;
831 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
832 "glDrawElements", this, helper_, count, type, 0, indices,
833 &offset, &simulated)) {
834 return;
836 helper_->DrawElements(mode, count, type, offset);
837 RestoreElementAndArrayBuffers(simulated);
838 CheckGLError();
841 void GLES2Implementation::Flush() {
842 GPU_CLIENT_SINGLE_THREAD_CHECK();
843 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
844 // Insert the cmd to call glFlush
845 helper_->Flush();
846 // Flush our command buffer
847 // (tell the service to execute up to the flush cmd.)
848 helper_->CommandBufferHelper::Flush();
849 if (!surface_visible_ && free_everything_when_invisible_)
850 FreeEverything();
853 void GLES2Implementation::ShallowFlushCHROMIUM() {
854 GPU_CLIENT_SINGLE_THREAD_CHECK();
855 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
856 // Flush our command buffer
857 // (tell the service to execute up to the flush cmd.)
858 helper_->CommandBufferHelper::Flush();
859 // TODO(piman): Add the FreeEverything() logic here.
862 void GLES2Implementation::Finish() {
863 GPU_CLIENT_SINGLE_THREAD_CHECK();
864 FinishHelper();
865 if (!surface_visible_ && free_everything_when_invisible_)
866 FreeEverything();
869 void GLES2Implementation::ShallowFinishCHROMIUM() {
870 GPU_CLIENT_SINGLE_THREAD_CHECK();
871 // Flush our command buffer (tell the service to execute up to the flush cmd
872 // and don't return until it completes).
873 helper_->CommandBufferHelper::Finish();
876 bool GLES2Implementation::MustBeContextLost() {
877 bool context_lost = helper_->IsContextLost();
878 if (!context_lost) {
879 WaitForCmd();
880 context_lost = helper_->IsContextLost();
882 CHECK(context_lost);
883 return context_lost;
886 void GLES2Implementation::FinishHelper() {
887 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
888 TRACE_EVENT0("gpu", "GLES2::Finish");
889 // Insert the cmd to call glFinish
890 helper_->Finish();
891 // Finish our command buffer
892 // (tell the service to execute up to the Finish cmd and wait for it to
893 // execute.)
894 helper_->CommandBufferHelper::Finish();
897 void GLES2Implementation::SwapBuffers() {
898 GPU_CLIENT_SINGLE_THREAD_CHECK();
899 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
900 // TODO(piman): Strictly speaking we'd want to insert the token after the
901 // swap, but the state update with the updated token might not have happened
902 // by the time the SwapBuffer callback gets called, forcing us to synchronize
903 // with the GPU process more than needed. So instead, make it happen before.
904 // All it means is that we could be slightly looser on the kMaxSwapBuffers
905 // semantics if the client doesn't use the callback mechanism, and by chance
906 // the scheduler yields between the InsertToken and the SwapBuffers.
907 swap_buffers_tokens_.push(helper_->InsertToken());
908 helper_->SwapBuffers();
909 helper_->CommandBufferHelper::Flush();
910 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
911 // compensate for TODO above.
912 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
913 helper_->WaitForToken(swap_buffers_tokens_.front());
914 swap_buffers_tokens_.pop();
918 void GLES2Implementation::GenSharedIdsCHROMIUM(
919 GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) {
920 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenSharedIdsCHROMIUM("
921 << namespace_id << ", " << id_offset << ", " << n << ", " <<
922 static_cast<void*>(ids) << ")");
923 TRACE_EVENT0("gpu", "GLES2::GenSharedIdsCHROMIUM");
924 GLsizei num = n;
925 GLuint* dst = ids;
926 while (num) {
927 ScopedTransferBufferArray<GLint> id_buffer(num, helper_, transfer_buffer_);
928 if (!id_buffer.valid()) {
929 return;
931 helper_->GenSharedIdsCHROMIUM(
932 namespace_id, id_offset, id_buffer.num_elements(),
933 id_buffer.shm_id(), id_buffer.offset());
934 WaitForCmd();
935 memcpy(dst, id_buffer.address(), sizeof(*dst) * id_buffer.num_elements());
936 num -= id_buffer.num_elements();
937 dst += id_buffer.num_elements();
939 GPU_CLIENT_LOG_CODE_BLOCK({
940 for (GLsizei i = 0; i < n; ++i) {
941 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
946 void GLES2Implementation::DeleteSharedIdsCHROMIUM(
947 GLuint namespace_id, GLsizei n, const GLuint* ids) {
948 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteSharedIdsCHROMIUM("
949 << namespace_id << ", " << n << ", "
950 << static_cast<const void*>(ids) << ")");
951 GPU_CLIENT_LOG_CODE_BLOCK({
952 for (GLsizei i = 0; i < n; ++i) {
953 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
956 TRACE_EVENT0("gpu", "GLES2::DeleteSharedIdsCHROMIUM");
957 while (n) {
958 ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
959 if (!id_buffer.valid()) {
960 return;
962 memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
963 helper_->DeleteSharedIdsCHROMIUM(
964 namespace_id, id_buffer.num_elements(),
965 id_buffer.shm_id(), id_buffer.offset());
966 WaitForCmd();
967 n -= id_buffer.num_elements();
968 ids += id_buffer.num_elements();
972 void GLES2Implementation::RegisterSharedIdsCHROMIUM(
973 GLuint namespace_id, GLsizei n, const GLuint* ids) {
974 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRegisterSharedIdsCHROMIUM("
975 << namespace_id << ", " << n << ", "
976 << static_cast<const void*>(ids) << ")");
977 GPU_CLIENT_LOG_CODE_BLOCK({
978 for (GLsizei i = 0; i < n; ++i) {
979 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
982 TRACE_EVENT0("gpu", "GLES2::RegisterSharedIdsCHROMIUM");
983 while (n) {
984 ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
985 if (!id_buffer.valid()) {
986 return;
988 memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
989 helper_->RegisterSharedIdsCHROMIUM(
990 namespace_id, id_buffer.num_elements(),
991 id_buffer.shm_id(), id_buffer.offset());
992 WaitForCmd();
993 n -= id_buffer.num_elements();
994 ids += id_buffer.num_elements();
998 void GLES2Implementation::BindAttribLocation(
999 GLuint program, GLuint index, const char* name) {
1000 GPU_CLIENT_SINGLE_THREAD_CHECK();
1001 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
1002 << program << ", " << index << ", " << name << ")");
1003 SetBucketAsString(kResultBucketId, name);
1004 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
1005 helper_->SetBucketSize(kResultBucketId, 0);
1006 CheckGLError();
1009 void GLES2Implementation::BindUniformLocationCHROMIUM(
1010 GLuint program, GLint location, const char* name) {
1011 GPU_CLIENT_SINGLE_THREAD_CHECK();
1012 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1013 << program << ", " << location << ", " << name << ")");
1014 SetBucketAsString(kResultBucketId, name);
1015 helper_->BindUniformLocationCHROMIUMBucket(
1016 program, location, kResultBucketId);
1017 helper_->SetBucketSize(kResultBucketId, 0);
1018 CheckGLError();
1021 void GLES2Implementation::GetVertexAttribPointerv(
1022 GLuint index, GLenum pname, void** ptr) {
1023 GPU_CLIENT_SINGLE_THREAD_CHECK();
1024 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1025 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1026 << static_cast<void*>(ptr) << ")");
1027 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
1028 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1029 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1030 typedef cmds::GetVertexAttribPointerv::Result Result;
1031 Result* result = GetResultAs<Result*>();
1032 if (!result) {
1033 return;
1035 result->SetNumResults(0);
1036 helper_->GetVertexAttribPointerv(
1037 index, pname, GetResultShmId(), GetResultShmOffset());
1038 WaitForCmd();
1039 result->CopyResult(ptr);
1040 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1042 GPU_CLIENT_LOG_CODE_BLOCK({
1043 for (int32 i = 0; i < num_results; ++i) {
1044 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
1047 CheckGLError();
1050 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1051 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1052 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
1053 SetGLError(
1054 GL_INVALID_VALUE,
1055 "glDeleteProgram", "id not created by this context.");
1056 return false;
1058 if (program == current_program_) {
1059 current_program_ = 0;
1061 return true;
1064 void GLES2Implementation::DeleteProgramStub(
1065 GLsizei n, const GLuint* programs) {
1066 DCHECK_EQ(1, n);
1067 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1068 helper_->DeleteProgram(programs[0]);
1071 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1072 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1073 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1074 SetGLError(
1075 GL_INVALID_VALUE,
1076 "glDeleteShader", "id not created by this context.");
1077 return false;
1079 return true;
1082 void GLES2Implementation::DeleteShaderStub(
1083 GLsizei n, const GLuint* shaders) {
1084 DCHECK_EQ(1, n);
1085 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1086 helper_->DeleteShader(shaders[0]);
1090 GLint GLES2Implementation::GetAttribLocationHelper(
1091 GLuint program, const char* name) {
1092 typedef cmds::GetAttribLocationBucket::Result Result;
1093 Result* result = GetResultAs<Result*>();
1094 if (!result) {
1095 return -1;
1097 *result = -1;
1098 SetBucketAsCString(kResultBucketId, name);
1099 helper_->GetAttribLocationBucket(
1100 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1101 WaitForCmd();
1102 helper_->SetBucketSize(kResultBucketId, 0);
1103 return *result;
1106 GLint GLES2Implementation::GetAttribLocation(
1107 GLuint program, const char* name) {
1108 GPU_CLIENT_SINGLE_THREAD_CHECK();
1109 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1110 << ", " << name << ")");
1111 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1112 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1113 this, program, name);
1114 GPU_CLIENT_LOG("returned " << loc);
1115 CheckGLError();
1116 return loc;
1119 GLint GLES2Implementation::GetUniformLocationHelper(
1120 GLuint program, const char* name) {
1121 typedef cmds::GetUniformLocationBucket::Result Result;
1122 Result* result = GetResultAs<Result*>();
1123 if (!result) {
1124 return -1;
1126 *result = -1;
1127 SetBucketAsCString(kResultBucketId, name);
1128 helper_->GetUniformLocationBucket(program, kResultBucketId,
1129 GetResultShmId(), GetResultShmOffset());
1130 WaitForCmd();
1131 helper_->SetBucketSize(kResultBucketId, 0);
1132 return *result;
1135 GLint GLES2Implementation::GetUniformLocation(
1136 GLuint program, const char* name) {
1137 GPU_CLIENT_SINGLE_THREAD_CHECK();
1138 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1139 << ", " << name << ")");
1140 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1141 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1142 this, program, name);
1143 GPU_CLIENT_LOG("returned " << loc);
1144 CheckGLError();
1145 return loc;
1148 void GLES2Implementation::UseProgram(GLuint program) {
1149 GPU_CLIENT_SINGLE_THREAD_CHECK();
1150 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUseProgram(" << program << ")");
1151 if (current_program_ != program) {
1152 current_program_ = program;
1153 helper_->UseProgram(program);
1155 CheckGLError();
1158 bool GLES2Implementation::GetProgramivHelper(
1159 GLuint program, GLenum pname, GLint* params) {
1160 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1161 this, program, pname, params);
1162 GPU_CLIENT_LOG_CODE_BLOCK({
1163 if (got_value) {
1164 GPU_CLIENT_LOG(" 0: " << *params);
1167 return got_value;
1170 void GLES2Implementation::LinkProgram(GLuint program) {
1171 GPU_CLIENT_SINGLE_THREAD_CHECK();
1172 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1173 helper_->LinkProgram(program);
1174 share_group_->program_info_manager()->CreateInfo(program);
1175 CheckGLError();
1178 void GLES2Implementation::ShaderBinary(
1179 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1180 GLsizei length) {
1181 GPU_CLIENT_SINGLE_THREAD_CHECK();
1182 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1183 << static_cast<const void*>(shaders) << ", "
1184 << GLES2Util::GetStringEnum(binaryformat) << ", "
1185 << static_cast<const void*>(binary) << ", "
1186 << length << ")");
1187 if (n < 0) {
1188 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1189 return;
1191 if (length < 0) {
1192 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1193 return;
1195 // TODO(gman): ShaderBinary should use buckets.
1196 unsigned int shader_id_size = n * sizeof(*shaders);
1197 ScopedTransferBufferArray<GLint> buffer(
1198 shader_id_size + length, helper_, transfer_buffer_);
1199 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1200 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1201 return;
1203 void* shader_ids = buffer.elements();
1204 void* shader_data = buffer.elements() + shader_id_size;
1205 memcpy(shader_ids, shaders, shader_id_size);
1206 memcpy(shader_data, binary, length);
1207 helper_->ShaderBinary(
1209 buffer.shm_id(),
1210 buffer.offset(),
1211 binaryformat,
1212 buffer.shm_id(),
1213 buffer.offset() + shader_id_size,
1214 length);
1215 CheckGLError();
1218 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1219 GPU_CLIENT_SINGLE_THREAD_CHECK();
1220 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1221 << GLES2Util::GetStringPixelStore(pname) << ", "
1222 << param << ")");
1223 switch (pname) {
1224 case GL_PACK_ALIGNMENT:
1225 pack_alignment_ = param;
1226 break;
1227 case GL_UNPACK_ALIGNMENT:
1228 unpack_alignment_ = param;
1229 break;
1230 case GL_UNPACK_ROW_LENGTH_EXT:
1231 unpack_row_length_ = param;
1232 return;
1233 case GL_UNPACK_SKIP_ROWS_EXT:
1234 unpack_skip_rows_ = param;
1235 return;
1236 case GL_UNPACK_SKIP_PIXELS_EXT:
1237 unpack_skip_pixels_ = param;
1238 return;
1239 case GL_UNPACK_FLIP_Y_CHROMIUM:
1240 unpack_flip_y_ = (param != 0);
1241 break;
1242 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1243 pack_reverse_row_order_ =
1244 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1245 break;
1246 default:
1247 break;
1249 helper_->PixelStorei(pname, param);
1250 CheckGLError();
1254 void GLES2Implementation::VertexAttribPointer(
1255 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1256 const void* ptr) {
1257 GPU_CLIENT_SINGLE_THREAD_CHECK();
1258 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1259 << index << ", "
1260 << size << ", "
1261 << GLES2Util::GetStringVertexAttribType(type) << ", "
1262 << GLES2Util::GetStringBool(normalized) << ", "
1263 << stride << ", "
1264 << static_cast<const void*>(ptr) << ")");
1265 // Record the info on the client side.
1266 if (!vertex_array_object_manager_->SetAttribPointer(
1267 bound_array_buffer_id_, index, size, type, normalized, stride, ptr)) {
1268 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1269 "client side arrays are not allowed in vertex array objects.");
1270 return;
1272 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1273 if (bound_array_buffer_id_ != 0) {
1274 // Only report NON client side buffers to the service.
1275 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1276 ToGLuint(ptr));
1278 #else // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1279 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1280 ToGLuint(ptr));
1281 #endif // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1282 CheckGLError();
1285 void GLES2Implementation::VertexAttribDivisorANGLE(
1286 GLuint index, GLuint divisor) {
1287 GPU_CLIENT_SINGLE_THREAD_CHECK();
1288 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1289 << index << ", "
1290 << divisor << ") ");
1291 // Record the info on the client side.
1292 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1293 helper_->VertexAttribDivisorANGLE(index, divisor);
1294 CheckGLError();
1297 void GLES2Implementation::ShaderSource(
1298 GLuint shader, GLsizei count, const GLchar* const* source, const GLint* length) {
1299 GPU_CLIENT_SINGLE_THREAD_CHECK();
1300 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderSource("
1301 << shader << ", " << count << ", "
1302 << static_cast<const void*>(source) << ", "
1303 << static_cast<const void*>(length) << ")");
1304 GPU_CLIENT_LOG_CODE_BLOCK({
1305 for (GLsizei ii = 0; ii < count; ++ii) {
1306 if (source[ii]) {
1307 if (length && length[ii] >= 0) {
1308 std::string str(source[ii], length[ii]);
1309 GPU_CLIENT_LOG(" " << ii << ": ---\n" << str << "\n---");
1310 } else {
1311 GPU_CLIENT_LOG(" " << ii << ": ---\n" << source[ii] << "\n---");
1313 } else {
1314 GPU_CLIENT_LOG(" " << ii << ": NULL");
1318 if (count < 0) {
1319 SetGLError(GL_INVALID_VALUE, "glShaderSource", "count < 0");
1320 return;
1322 if (shader == 0) {
1323 SetGLError(GL_INVALID_VALUE, "glShaderSource", "shader == 0");
1324 return;
1327 // Compute the total size.
1328 uint32 total_size = 1;
1329 for (GLsizei ii = 0; ii < count; ++ii) {
1330 if (source[ii]) {
1331 total_size += (length && length[ii] >= 0) ?
1332 static_cast<size_t>(length[ii]) : strlen(source[ii]);
1336 // Concatenate all the strings in to a bucket on the service.
1337 helper_->SetBucketSize(kResultBucketId, total_size);
1338 uint32 offset = 0;
1339 for (GLsizei ii = 0; ii <= count; ++ii) {
1340 const char* src = ii < count ? source[ii] : "";
1341 if (src) {
1342 uint32 size = ii < count ?
1343 (length ? static_cast<size_t>(length[ii]) : strlen(src)) : 1;
1344 while (size) {
1345 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1346 if (!buffer.valid()) {
1347 return;
1349 memcpy(buffer.address(), src, buffer.size());
1350 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
1351 buffer.shm_id(), buffer.offset());
1352 offset += buffer.size();
1353 src += buffer.size();
1354 size -= buffer.size();
1359 DCHECK_EQ(total_size, offset);
1361 helper_->ShaderSourceBucket(shader, kResultBucketId);
1362 helper_->SetBucketSize(kResultBucketId, 0);
1363 CheckGLError();
1366 void GLES2Implementation::BufferDataHelper(
1367 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1368 if (size < 0) {
1369 SetGLError(GL_INVALID_VALUE, "glBufferData", "size < 0");
1370 return;
1373 GLuint buffer_id;
1374 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1375 if (!buffer_id) {
1376 return;
1379 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1380 if (buffer) {
1381 // Free buffer memory, pending the passage of a token.
1382 buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
1384 // Remove old buffer.
1385 buffer_tracker_->RemoveBuffer(buffer_id);
1388 // Create new buffer.
1389 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1390 DCHECK(buffer);
1391 if (buffer->address() && data)
1392 memcpy(buffer->address(), data, size);
1393 return;
1396 if (size == 0) {
1397 return;
1400 // If there is no data just send BufferData
1401 if (!data) {
1402 helper_->BufferData(target, size, 0, 0, usage);
1403 return;
1406 // See if we can send all at once.
1407 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1408 if (!buffer.valid()) {
1409 return;
1412 if (buffer.size() >= static_cast<unsigned int>(size)) {
1413 memcpy(buffer.address(), data, size);
1414 helper_->BufferData(
1415 target,
1416 size,
1417 buffer.shm_id(),
1418 buffer.offset(),
1419 usage);
1420 return;
1423 // Make the buffer with BufferData then send via BufferSubData
1424 helper_->BufferData(target, size, 0, 0, usage);
1425 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1426 CheckGLError();
1429 void GLES2Implementation::BufferData(
1430 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1431 GPU_CLIENT_SINGLE_THREAD_CHECK();
1432 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1433 << GLES2Util::GetStringBufferTarget(target) << ", "
1434 << size << ", "
1435 << static_cast<const void*>(data) << ", "
1436 << GLES2Util::GetStringBufferUsage(usage) << ")");
1437 BufferDataHelper(target, size, data, usage);
1438 CheckGLError();
1441 void GLES2Implementation::BufferSubDataHelper(
1442 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1443 if (size == 0) {
1444 return;
1447 if (size < 0) {
1448 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "size < 0");
1449 return;
1452 GLuint buffer_id;
1453 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1454 if (!buffer_id) {
1455 return;
1457 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1458 if (!buffer) {
1459 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1460 return;
1463 int32 end = 0;
1464 int32 buffer_size = buffer->size();
1465 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1466 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1467 return;
1470 if (buffer->address() && data)
1471 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1472 return;
1475 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1476 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1479 void GLES2Implementation::BufferSubDataHelperImpl(
1480 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1481 ScopedTransferBufferPtr* buffer) {
1482 DCHECK(buffer);
1483 DCHECK_GT(size, 0);
1485 const int8* source = static_cast<const int8*>(data);
1486 while (size) {
1487 if (!buffer->valid() || buffer->size() == 0) {
1488 buffer->Reset(size);
1489 if (!buffer->valid()) {
1490 return;
1493 memcpy(buffer->address(), source, buffer->size());
1494 helper_->BufferSubData(
1495 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1496 offset += buffer->size();
1497 source += buffer->size();
1498 size -= buffer->size();
1499 buffer->Release();
1503 void GLES2Implementation::BufferSubData(
1504 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1505 GPU_CLIENT_SINGLE_THREAD_CHECK();
1506 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1507 << GLES2Util::GetStringBufferTarget(target) << ", "
1508 << offset << ", " << size << ", "
1509 << static_cast<const void*>(data) << ")");
1510 BufferSubDataHelper(target, offset, size, data);
1511 CheckGLError();
1514 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1515 GLenum target,
1516 const char* function_name,
1517 GLuint* buffer_id) {
1518 *buffer_id = 0;
1520 switch (target) {
1521 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1522 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1523 break;
1524 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1525 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1526 break;
1527 default:
1528 // Unknown target
1529 return false;
1531 if (!*buffer_id) {
1532 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1534 return true;
1537 BufferTracker::Buffer*
1538 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1539 GLuint buffer_id,
1540 const char* function_name,
1541 GLuint offset, GLsizei size)
1543 DCHECK(buffer_id);
1544 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1545 if (!buffer) {
1546 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1547 return NULL;
1549 if (buffer->mapped()) {
1550 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1551 return NULL;
1553 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1554 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1555 return NULL;
1557 return buffer;
1560 void GLES2Implementation::CompressedTexImage2D(
1561 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1562 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1563 GPU_CLIENT_SINGLE_THREAD_CHECK();
1564 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1565 << GLES2Util::GetStringTextureTarget(target) << ", "
1566 << level << ", "
1567 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1568 << width << ", " << height << ", " << border << ", "
1569 << image_size << ", "
1570 << static_cast<const void*>(data) << ")");
1571 if (width < 0 || height < 0 || level < 0) {
1572 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1573 return;
1575 if (height == 0 || width == 0) {
1576 return;
1578 // If there's a pixel unpack buffer bound use it when issuing
1579 // CompressedTexImage2D.
1580 if (bound_pixel_unpack_transfer_buffer_id_) {
1581 GLuint offset = ToGLuint(data);
1582 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1583 bound_pixel_unpack_transfer_buffer_id_,
1584 "glCompressedTexImage2D", offset, image_size);
1585 if (buffer && buffer->shm_id() != -1) {
1586 helper_->CompressedTexImage2D(
1587 target, level, internalformat, width, height, border, image_size,
1588 buffer->shm_id(), buffer->shm_offset() + offset);
1589 buffer->set_transfer_ready_token(helper_->InsertToken());
1591 return;
1593 SetBucketContents(kResultBucketId, data, image_size);
1594 helper_->CompressedTexImage2DBucket(
1595 target, level, internalformat, width, height, border, kResultBucketId);
1596 // Free the bucket. This is not required but it does free up the memory.
1597 // and we don't have to wait for the result so from the client's perspective
1598 // it's cheap.
1599 helper_->SetBucketSize(kResultBucketId, 0);
1600 CheckGLError();
1603 void GLES2Implementation::CompressedTexSubImage2D(
1604 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1605 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1606 GPU_CLIENT_SINGLE_THREAD_CHECK();
1607 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1608 << GLES2Util::GetStringTextureTarget(target) << ", "
1609 << level << ", "
1610 << xoffset << ", " << yoffset << ", "
1611 << width << ", " << height << ", "
1612 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1613 << image_size << ", "
1614 << static_cast<const void*>(data) << ")");
1615 if (width < 0 || height < 0 || level < 0) {
1616 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1617 return;
1619 // If there's a pixel unpack buffer bound use it when issuing
1620 // CompressedTexSubImage2D.
1621 if (bound_pixel_unpack_transfer_buffer_id_) {
1622 GLuint offset = ToGLuint(data);
1623 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1624 bound_pixel_unpack_transfer_buffer_id_,
1625 "glCompressedTexSubImage2D", offset, image_size);
1626 if (buffer && buffer->shm_id() != -1) {
1627 helper_->CompressedTexSubImage2D(
1628 target, level, xoffset, yoffset, width, height, format, image_size,
1629 buffer->shm_id(), buffer->shm_offset() + offset);
1630 buffer->set_transfer_ready_token(helper_->InsertToken());
1631 CheckGLError();
1633 return;
1635 SetBucketContents(kResultBucketId, data, image_size);
1636 helper_->CompressedTexSubImage2DBucket(
1637 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1638 // Free the bucket. This is not required but it does free up the memory.
1639 // and we don't have to wait for the result so from the client's perspective
1640 // it's cheap.
1641 helper_->SetBucketSize(kResultBucketId, 0);
1642 CheckGLError();
1645 namespace {
1647 void CopyRectToBuffer(
1648 const void* pixels,
1649 uint32 height,
1650 uint32 unpadded_row_size,
1651 uint32 pixels_padded_row_size,
1652 bool flip_y,
1653 void* buffer,
1654 uint32 buffer_padded_row_size) {
1655 const int8* source = static_cast<const int8*>(pixels);
1656 int8* dest = static_cast<int8*>(buffer);
1657 if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
1658 if (flip_y) {
1659 dest += buffer_padded_row_size * (height - 1);
1661 // the last row is copied unpadded at the end
1662 for (; height > 1; --height) {
1663 memcpy(dest, source, buffer_padded_row_size);
1664 if (flip_y) {
1665 dest -= buffer_padded_row_size;
1666 } else {
1667 dest += buffer_padded_row_size;
1669 source += pixels_padded_row_size;
1671 memcpy(dest, source, unpadded_row_size);
1672 } else {
1673 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
1674 memcpy(dest, source, size);
1678 } // anonymous namespace
1680 void GLES2Implementation::TexImage2D(
1681 GLenum target, GLint level, GLint internalformat, GLsizei width,
1682 GLsizei height, GLint border, GLenum format, GLenum type,
1683 const void* pixels) {
1684 GPU_CLIENT_SINGLE_THREAD_CHECK();
1685 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1686 << GLES2Util::GetStringTextureTarget(target) << ", "
1687 << level << ", "
1688 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1689 << width << ", " << height << ", " << border << ", "
1690 << GLES2Util::GetStringTextureFormat(format) << ", "
1691 << GLES2Util::GetStringPixelType(type) << ", "
1692 << static_cast<const void*>(pixels) << ")");
1693 if (level < 0 || height < 0 || width < 0) {
1694 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
1695 return;
1697 uint32 size;
1698 uint32 unpadded_row_size;
1699 uint32 padded_row_size;
1700 if (!GLES2Util::ComputeImageDataSizes(
1701 width, height, format, type, unpack_alignment_, &size,
1702 &unpadded_row_size, &padded_row_size)) {
1703 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
1704 return;
1707 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1708 if (bound_pixel_unpack_transfer_buffer_id_) {
1709 GLuint offset = ToGLuint(pixels);
1710 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1711 bound_pixel_unpack_transfer_buffer_id_,
1712 "glTexImage2D", offset, size);
1713 if (buffer && buffer->shm_id() != -1) {
1714 helper_->TexImage2D(
1715 target, level, internalformat, width, height, border, format, type,
1716 buffer->shm_id(), buffer->shm_offset() + offset);
1717 buffer->set_transfer_ready_token(helper_->InsertToken());
1718 CheckGLError();
1720 return;
1723 // If there's no data just issue TexImage2D
1724 if (!pixels) {
1725 helper_->TexImage2D(
1726 target, level, internalformat, width, height, border, format, type,
1727 0, 0);
1728 CheckGLError();
1729 return;
1732 // compute the advance bytes per row for the src pixels
1733 uint32 src_padded_row_size;
1734 if (unpack_row_length_ > 0) {
1735 if (!GLES2Util::ComputeImagePaddedRowSize(
1736 unpack_row_length_, format, type, unpack_alignment_,
1737 &src_padded_row_size)) {
1738 SetGLError(
1739 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1740 return;
1742 } else {
1743 src_padded_row_size = padded_row_size;
1746 // advance pixels pointer past the skip rows and skip pixels
1747 pixels = reinterpret_cast<const int8*>(pixels) +
1748 unpack_skip_rows_ * src_padded_row_size;
1749 if (unpack_skip_pixels_) {
1750 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1751 pixels = reinterpret_cast<const int8*>(pixels) +
1752 unpack_skip_pixels_ * group_size;
1755 // Check if we can send it all at once.
1756 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1757 if (!buffer.valid()) {
1758 return;
1761 if (buffer.size() >= size) {
1762 CopyRectToBuffer(
1763 pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
1764 buffer.address(), padded_row_size);
1765 helper_->TexImage2D(
1766 target, level, internalformat, width, height, border, format, type,
1767 buffer.shm_id(), buffer.offset());
1768 CheckGLError();
1769 return;
1772 // No, so send it using TexSubImage2D.
1773 helper_->TexImage2D(
1774 target, level, internalformat, width, height, border, format, type,
1775 0, 0);
1776 TexSubImage2DImpl(
1777 target, level, 0, 0, width, height, format, type, unpadded_row_size,
1778 pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
1779 CheckGLError();
1782 void GLES2Implementation::TexSubImage2D(
1783 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1784 GLsizei height, GLenum format, GLenum type, const void* pixels) {
1785 GPU_CLIENT_SINGLE_THREAD_CHECK();
1786 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1787 << GLES2Util::GetStringTextureTarget(target) << ", "
1788 << level << ", "
1789 << xoffset << ", " << yoffset << ", "
1790 << width << ", " << height << ", "
1791 << GLES2Util::GetStringTextureFormat(format) << ", "
1792 << GLES2Util::GetStringPixelType(type) << ", "
1793 << static_cast<const void*>(pixels) << ")");
1795 if (level < 0 || height < 0 || width < 0) {
1796 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
1797 return;
1799 if (height == 0 || width == 0) {
1800 return;
1803 uint32 temp_size;
1804 uint32 unpadded_row_size;
1805 uint32 padded_row_size;
1806 if (!GLES2Util::ComputeImageDataSizes(
1807 width, height, format, type, unpack_alignment_, &temp_size,
1808 &unpadded_row_size, &padded_row_size)) {
1809 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
1810 return;
1813 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1814 if (bound_pixel_unpack_transfer_buffer_id_) {
1815 GLuint offset = ToGLuint(pixels);
1816 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1817 bound_pixel_unpack_transfer_buffer_id_,
1818 "glTexSubImage2D", offset, temp_size);
1819 if (buffer && buffer->shm_id() != -1) {
1820 helper_->TexSubImage2D(
1821 target, level, xoffset, yoffset, width, height, format, type,
1822 buffer->shm_id(), buffer->shm_offset() + offset, false);
1823 buffer->set_transfer_ready_token(helper_->InsertToken());
1824 CheckGLError();
1826 return;
1829 // compute the advance bytes per row for the src pixels
1830 uint32 src_padded_row_size;
1831 if (unpack_row_length_ > 0) {
1832 if (!GLES2Util::ComputeImagePaddedRowSize(
1833 unpack_row_length_, format, type, unpack_alignment_,
1834 &src_padded_row_size)) {
1835 SetGLError(
1836 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1837 return;
1839 } else {
1840 src_padded_row_size = padded_row_size;
1843 // advance pixels pointer past the skip rows and skip pixels
1844 pixels = reinterpret_cast<const int8*>(pixels) +
1845 unpack_skip_rows_ * src_padded_row_size;
1846 if (unpack_skip_pixels_) {
1847 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1848 pixels = reinterpret_cast<const int8*>(pixels) +
1849 unpack_skip_pixels_ * group_size;
1852 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
1853 TexSubImage2DImpl(
1854 target, level, xoffset, yoffset, width, height, format, type,
1855 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
1856 padded_row_size);
1857 CheckGLError();
1860 static GLint ComputeNumRowsThatFitInBuffer(
1861 GLsizeiptr padded_row_size, GLsizeiptr unpadded_row_size,
1862 unsigned int size) {
1863 DCHECK_GE(unpadded_row_size, 0);
1864 if (padded_row_size == 0) {
1865 return 1;
1867 GLint num_rows = size / padded_row_size;
1868 return num_rows + (size - num_rows * padded_row_size) / unpadded_row_size;
1871 void GLES2Implementation::TexSubImage2DImpl(
1872 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1873 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
1874 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
1875 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
1876 DCHECK(buffer);
1877 DCHECK_GE(level, 0);
1878 DCHECK_GT(height, 0);
1879 DCHECK_GT(width, 0);
1881 const int8* source = reinterpret_cast<const int8*>(pixels);
1882 GLint original_yoffset = yoffset;
1883 // Transfer by rows.
1884 while (height) {
1885 unsigned int desired_size =
1886 buffer_padded_row_size * (height - 1) + unpadded_row_size;
1887 if (!buffer->valid() || buffer->size() == 0) {
1888 buffer->Reset(desired_size);
1889 if (!buffer->valid()) {
1890 return;
1894 GLint num_rows = ComputeNumRowsThatFitInBuffer(
1895 buffer_padded_row_size, unpadded_row_size, buffer->size());
1896 num_rows = std::min(num_rows, height);
1897 CopyRectToBuffer(
1898 source, num_rows, unpadded_row_size, pixels_padded_row_size,
1899 unpack_flip_y_, buffer->address(), buffer_padded_row_size);
1900 GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
1901 helper_->TexSubImage2D(
1902 target, level, xoffset, y, width, num_rows, format, type,
1903 buffer->shm_id(), buffer->offset(), internal);
1904 buffer->Release();
1905 yoffset += num_rows;
1906 source += num_rows * pixels_padded_row_size;
1907 height -= num_rows;
1911 bool GLES2Implementation::GetActiveAttribHelper(
1912 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1913 GLenum* type, char* name) {
1914 // Clear the bucket so if the command fails nothing will be in it.
1915 helper_->SetBucketSize(kResultBucketId, 0);
1916 typedef cmds::GetActiveAttrib::Result Result;
1917 Result* result = GetResultAs<Result*>();
1918 if (!result) {
1919 return false;
1921 // Set as failed so if the command fails we'll recover.
1922 result->success = false;
1923 helper_->GetActiveAttrib(program, index, kResultBucketId,
1924 GetResultShmId(), GetResultShmOffset());
1925 WaitForCmd();
1926 if (result->success) {
1927 if (size) {
1928 *size = result->size;
1930 if (type) {
1931 *type = result->type;
1933 if (length || name) {
1934 std::vector<int8> str;
1935 GetBucketContents(kResultBucketId, &str);
1936 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
1937 std::max(static_cast<size_t>(0),
1938 str.size() - 1));
1939 if (length) {
1940 *length = max_size;
1942 if (name && bufsize > 0) {
1943 memcpy(name, &str[0], max_size);
1944 name[max_size] = '\0';
1948 return result->success != 0;
1951 void GLES2Implementation::GetActiveAttrib(
1952 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1953 GLenum* type, char* name) {
1954 GPU_CLIENT_SINGLE_THREAD_CHECK();
1955 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
1956 << program << ", " << index << ", " << bufsize << ", "
1957 << static_cast<const void*>(length) << ", "
1958 << static_cast<const void*>(size) << ", "
1959 << static_cast<const void*>(type) << ", "
1960 << static_cast<const void*>(name) << ", ");
1961 if (bufsize < 0) {
1962 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
1963 return;
1965 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
1966 bool success = share_group_->program_info_manager()->GetActiveAttrib(
1967 this, program, index, bufsize, length, size, type, name);
1968 if (success) {
1969 if (size) {
1970 GPU_CLIENT_LOG(" size: " << *size);
1972 if (type) {
1973 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
1975 if (name) {
1976 GPU_CLIENT_LOG(" name: " << name);
1979 CheckGLError();
1982 bool GLES2Implementation::GetActiveUniformHelper(
1983 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1984 GLenum* type, char* name) {
1985 // Clear the bucket so if the command fails nothing will be in it.
1986 helper_->SetBucketSize(kResultBucketId, 0);
1987 typedef cmds::GetActiveUniform::Result Result;
1988 Result* result = GetResultAs<Result*>();
1989 if (!result) {
1990 return false;
1992 // Set as failed so if the command fails we'll recover.
1993 result->success = false;
1994 helper_->GetActiveUniform(program, index, kResultBucketId,
1995 GetResultShmId(), GetResultShmOffset());
1996 WaitForCmd();
1997 if (result->success) {
1998 if (size) {
1999 *size = result->size;
2001 if (type) {
2002 *type = result->type;
2004 if (length || name) {
2005 std::vector<int8> str;
2006 GetBucketContents(kResultBucketId, &str);
2007 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2008 std::max(static_cast<size_t>(0),
2009 str.size() - 1));
2010 if (length) {
2011 *length = max_size;
2013 if (name && bufsize > 0) {
2014 memcpy(name, &str[0], max_size);
2015 name[max_size] = '\0';
2019 return result->success != 0;
2022 void GLES2Implementation::GetActiveUniform(
2023 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2024 GLenum* type, char* name) {
2025 GPU_CLIENT_SINGLE_THREAD_CHECK();
2026 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2027 << program << ", " << index << ", " << bufsize << ", "
2028 << static_cast<const void*>(length) << ", "
2029 << static_cast<const void*>(size) << ", "
2030 << static_cast<const void*>(type) << ", "
2031 << static_cast<const void*>(name) << ", ");
2032 if (bufsize < 0) {
2033 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2034 return;
2036 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2037 bool success = share_group_->program_info_manager()->GetActiveUniform(
2038 this, program, index, bufsize, length, size, type, name);
2039 if (success) {
2040 if (size) {
2041 GPU_CLIENT_LOG(" size: " << *size);
2043 if (type) {
2044 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2046 if (name) {
2047 GPU_CLIENT_LOG(" name: " << name);
2050 CheckGLError();
2053 void GLES2Implementation::GetAttachedShaders(
2054 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
2055 GPU_CLIENT_SINGLE_THREAD_CHECK();
2056 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2057 << program << ", " << maxcount << ", "
2058 << static_cast<const void*>(count) << ", "
2059 << static_cast<const void*>(shaders) << ", ");
2060 if (maxcount < 0) {
2061 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
2062 return;
2064 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2065 typedef cmds::GetAttachedShaders::Result Result;
2066 uint32 size = Result::ComputeSize(maxcount);
2067 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
2068 if (!result) {
2069 return;
2071 result->SetNumResults(0);
2072 helper_->GetAttachedShaders(
2073 program,
2074 transfer_buffer_->GetShmId(),
2075 transfer_buffer_->GetOffset(result),
2076 size);
2077 int32 token = helper_->InsertToken();
2078 WaitForCmd();
2079 if (count) {
2080 *count = result->GetNumResults();
2082 result->CopyResult(shaders);
2083 GPU_CLIENT_LOG_CODE_BLOCK({
2084 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2085 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2088 transfer_buffer_->FreePendingToken(result, token);
2089 CheckGLError();
2092 void GLES2Implementation::GetShaderPrecisionFormat(
2093 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
2094 GPU_CLIENT_SINGLE_THREAD_CHECK();
2095 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2096 << GLES2Util::GetStringShaderType(shadertype) << ", "
2097 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
2098 << static_cast<const void*>(range) << ", "
2099 << static_cast<const void*>(precision) << ", ");
2100 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2101 typedef cmds::GetShaderPrecisionFormat::Result Result;
2102 Result* result = GetResultAs<Result*>();
2103 if (!result) {
2104 return;
2107 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
2108 GLStaticState::ShaderPrecisionMap::iterator i =
2109 static_state_.shader_precisions.find(key);
2110 if (i != static_state_.shader_precisions.end()) {
2111 *result = i->second;
2112 } else {
2113 result->success = false;
2114 helper_->GetShaderPrecisionFormat(
2115 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
2116 WaitForCmd();
2117 if (result->success)
2118 static_state_.shader_precisions[key] = *result;
2121 if (result->success) {
2122 if (range) {
2123 range[0] = result->min_range;
2124 range[1] = result->max_range;
2125 GPU_CLIENT_LOG(" min_range: " << range[0]);
2126 GPU_CLIENT_LOG(" min_range: " << range[1]);
2128 if (precision) {
2129 precision[0] = result->precision;
2130 GPU_CLIENT_LOG(" min_range: " << precision[0]);
2133 CheckGLError();
2136 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
2137 const char* result = NULL;
2138 // Clears the bucket so if the command fails nothing will be in it.
2139 helper_->SetBucketSize(kResultBucketId, 0);
2140 helper_->GetString(name, kResultBucketId);
2141 std::string str;
2142 if (GetBucketAsString(kResultBucketId, &str)) {
2143 // Adds extensions implemented on client side only.
2144 switch (name) {
2145 case GL_EXTENSIONS:
2146 str += std::string(str.empty() ? "" : " ") +
2147 "GL_CHROMIUM_flipy "
2148 "GL_EXT_unpack_subimage";
2149 if (capabilities_.map_image) {
2150 // The first space character is intentional.
2151 str += " GL_CHROMIUM_map_image";
2153 break;
2154 default:
2155 break;
2158 // Because of WebGL the extensions can change. We have to cache each unique
2159 // result since we don't know when the client will stop referring to a
2160 // previous one it queries.
2161 GLStringMap::iterator it = gl_strings_.find(name);
2162 if (it == gl_strings_.end()) {
2163 std::set<std::string> strings;
2164 std::pair<GLStringMap::iterator, bool> insert_result =
2165 gl_strings_.insert(std::make_pair(name, strings));
2166 DCHECK(insert_result.second);
2167 it = insert_result.first;
2169 std::set<std::string>& string_set = it->second;
2170 std::set<std::string>::const_iterator sit = string_set.find(str);
2171 if (sit != string_set.end()) {
2172 result = sit->c_str();
2173 } else {
2174 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2175 string_set.insert(str);
2176 DCHECK(insert_result.second);
2177 result = insert_result.first->c_str();
2180 return reinterpret_cast<const GLubyte*>(result);
2183 const GLubyte* GLES2Implementation::GetString(GLenum name) {
2184 GPU_CLIENT_SINGLE_THREAD_CHECK();
2185 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2186 << GLES2Util::GetStringStringType(name) << ")");
2187 TRACE_EVENT0("gpu", "GLES2::GetString");
2188 const GLubyte* result = GetStringHelper(name);
2189 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
2190 CheckGLError();
2191 return result;
2194 void GLES2Implementation::GetUniformfv(
2195 GLuint program, GLint location, GLfloat* params) {
2196 GPU_CLIENT_SINGLE_THREAD_CHECK();
2197 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2198 << program << ", " << location << ", "
2199 << static_cast<const void*>(params) << ")");
2200 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2201 typedef cmds::GetUniformfv::Result Result;
2202 Result* result = GetResultAs<Result*>();
2203 if (!result) {
2204 return;
2206 result->SetNumResults(0);
2207 helper_->GetUniformfv(
2208 program, location, GetResultShmId(), GetResultShmOffset());
2209 WaitForCmd();
2210 result->CopyResult(params);
2211 GPU_CLIENT_LOG_CODE_BLOCK({
2212 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2213 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2216 CheckGLError();
2219 void GLES2Implementation::GetUniformiv(
2220 GLuint program, GLint location, GLint* params) {
2221 GPU_CLIENT_SINGLE_THREAD_CHECK();
2222 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2223 << program << ", " << location << ", "
2224 << static_cast<const void*>(params) << ")");
2225 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2226 typedef cmds::GetUniformiv::Result Result;
2227 Result* result = GetResultAs<Result*>();
2228 if (!result) {
2229 return;
2231 result->SetNumResults(0);
2232 helper_->GetUniformiv(
2233 program, location, GetResultShmId(), GetResultShmOffset());
2234 WaitForCmd();
2235 GetResultAs<cmds::GetUniformfv::Result*>()->CopyResult(params);
2236 GPU_CLIENT_LOG_CODE_BLOCK({
2237 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2238 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2241 CheckGLError();
2244 void GLES2Implementation::ReadPixels(
2245 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
2246 GLenum type, void* pixels) {
2247 GPU_CLIENT_SINGLE_THREAD_CHECK();
2248 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2249 << xoffset << ", " << yoffset << ", "
2250 << width << ", " << height << ", "
2251 << GLES2Util::GetStringReadPixelFormat(format) << ", "
2252 << GLES2Util::GetStringPixelType(type) << ", "
2253 << static_cast<const void*>(pixels) << ")");
2254 if (width < 0 || height < 0) {
2255 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
2256 return;
2258 if (width == 0 || height == 0) {
2259 return;
2262 // glReadPixel pads the size of each row of pixels by an amount specified by
2263 // glPixelStorei. So, we have to take that into account both in the fact that
2264 // the pixels returned from the ReadPixel command will include that padding
2265 // and that when we copy the results to the user's buffer we need to not
2266 // write those padding bytes but leave them as they are.
2268 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2269 typedef cmds::ReadPixels::Result Result;
2271 int8* dest = reinterpret_cast<int8*>(pixels);
2272 uint32 temp_size;
2273 uint32 unpadded_row_size;
2274 uint32 padded_row_size;
2275 if (!GLES2Util::ComputeImageDataSizes(
2276 width, 2, format, type, pack_alignment_, &temp_size, &unpadded_row_size,
2277 &padded_row_size)) {
2278 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
2279 return;
2282 if (bound_pixel_pack_transfer_buffer_id_) {
2283 GLuint offset = ToGLuint(pixels);
2284 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2285 bound_pixel_pack_transfer_buffer_id_,
2286 "glReadPixels", offset, padded_row_size * height);
2287 if (buffer && buffer->shm_id() != -1) {
2288 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
2289 buffer->shm_id(), buffer->shm_offset(),
2290 0, 0, true);
2291 CheckGLError();
2293 return;
2296 if (!pixels) {
2297 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
2298 return;
2301 // Transfer by rows.
2302 // The max rows we can transfer.
2303 while (height) {
2304 GLsizei desired_size = padded_row_size * height - 1 + unpadded_row_size;
2305 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
2306 if (!buffer.valid()) {
2307 return;
2309 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2310 padded_row_size, unpadded_row_size, buffer.size());
2311 num_rows = std::min(num_rows, height);
2312 // NOTE: We must look up the address of the result area AFTER allocation
2313 // of the transfer buffer since the transfer buffer may be reallocated.
2314 Result* result = GetResultAs<Result*>();
2315 if (!result) {
2316 return;
2318 *result = 0; // mark as failed.
2319 helper_->ReadPixels(
2320 xoffset, yoffset, width, num_rows, format, type,
2321 buffer.shm_id(), buffer.offset(),
2322 GetResultShmId(), GetResultShmOffset(),
2323 false);
2324 WaitForCmd();
2325 if (*result != 0) {
2326 // when doing a y-flip we have to iterate through top-to-bottom chunks
2327 // of the dst. The service side handles reversing the rows within a
2328 // chunk.
2329 int8* rows_dst;
2330 if (pack_reverse_row_order_) {
2331 rows_dst = dest + (height - num_rows) * padded_row_size;
2332 } else {
2333 rows_dst = dest;
2335 // We have to copy 1 row at a time to avoid writing pad bytes.
2336 const int8* src = static_cast<const int8*>(buffer.address());
2337 for (GLint yy = 0; yy < num_rows; ++yy) {
2338 memcpy(rows_dst, src, unpadded_row_size);
2339 rows_dst += padded_row_size;
2340 src += padded_row_size;
2342 if (!pack_reverse_row_order_) {
2343 dest = rows_dst;
2346 // If it was not marked as successful exit.
2347 if (*result == 0) {
2348 return;
2350 yoffset += num_rows;
2351 height -= num_rows;
2353 CheckGLError();
2356 void GLES2Implementation::ActiveTexture(GLenum texture) {
2357 GPU_CLIENT_SINGLE_THREAD_CHECK();
2358 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2359 << GLES2Util::GetStringEnum(texture) << ")");
2360 GLuint texture_index = texture - GL_TEXTURE0;
2361 if (texture_index >= static_cast<GLuint>(
2362 static_state_.int_state.max_combined_texture_image_units)) {
2363 SetGLErrorInvalidEnum(
2364 "glActiveTexture", texture, "texture");
2365 return;
2368 active_texture_unit_ = texture_index;
2369 helper_->ActiveTexture(texture);
2370 CheckGLError();
2373 void GLES2Implementation::GenBuffersHelper(
2374 GLsizei /* n */, const GLuint* /* buffers */) {
2377 void GLES2Implementation::GenFramebuffersHelper(
2378 GLsizei /* n */, const GLuint* /* framebuffers */) {
2381 void GLES2Implementation::GenRenderbuffersHelper(
2382 GLsizei /* n */, const GLuint* /* renderbuffers */) {
2385 void GLES2Implementation::GenTexturesHelper(
2386 GLsizei /* n */, const GLuint* /* textures */) {
2389 void GLES2Implementation::GenVertexArraysOESHelper(
2390 GLsizei n, const GLuint* arrays) {
2391 vertex_array_object_manager_->GenVertexArrays(n, arrays);
2394 void GLES2Implementation::GenQueriesEXTHelper(
2395 GLsizei /* n */, const GLuint* /* queries */) {
2398 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
2399 // generates a new resource. On newer versions of OpenGL they don't. The code
2400 // related to binding below will need to change if we switch to the new OpenGL
2401 // model. Specifically it assumes a bind will succeed which is always true in
2402 // the old model but possibly not true in the new model if another context has
2403 // deleted the resource.
2405 bool GLES2Implementation::BindBufferHelper(
2406 GLenum target, GLuint buffer) {
2407 // TODO(gman): See note #1 above.
2408 bool changed = false;
2409 switch (target) {
2410 case GL_ARRAY_BUFFER:
2411 if (bound_array_buffer_id_ != buffer) {
2412 bound_array_buffer_id_ = buffer;
2413 changed = true;
2415 break;
2416 case GL_ELEMENT_ARRAY_BUFFER:
2417 changed = vertex_array_object_manager_->BindElementArray(buffer);
2418 break;
2419 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
2420 bound_pixel_pack_transfer_buffer_id_ = buffer;
2421 break;
2422 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
2423 bound_pixel_unpack_transfer_buffer_id_ = buffer;
2424 break;
2425 default:
2426 changed = true;
2427 break;
2429 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2430 // used even though it's marked it as used here.
2431 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(buffer);
2432 return changed;
2435 bool GLES2Implementation::BindFramebufferHelper(
2436 GLenum target, GLuint framebuffer) {
2437 // TODO(gman): See note #1 above.
2438 bool changed = false;
2439 switch (target) {
2440 case GL_FRAMEBUFFER:
2441 if (bound_framebuffer_ != framebuffer ||
2442 bound_read_framebuffer_ != framebuffer) {
2443 bound_framebuffer_ = framebuffer;
2444 bound_read_framebuffer_ = framebuffer;
2445 changed = true;
2447 break;
2448 case GL_READ_FRAMEBUFFER:
2449 if (!IsChromiumFramebufferMultisampleAvailable()) {
2450 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2451 return false;
2453 if (bound_read_framebuffer_ != framebuffer) {
2454 bound_read_framebuffer_ = framebuffer;
2455 changed = true;
2457 break;
2458 case GL_DRAW_FRAMEBUFFER:
2459 if (!IsChromiumFramebufferMultisampleAvailable()) {
2460 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2461 return false;
2463 if (bound_framebuffer_ != framebuffer) {
2464 bound_framebuffer_ = framebuffer;
2465 changed = true;
2467 break;
2468 default:
2469 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2470 return false;
2472 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(framebuffer);
2473 return changed;
2476 bool GLES2Implementation::BindRenderbufferHelper(
2477 GLenum target, GLuint renderbuffer) {
2478 // TODO(gman): See note #1 above.
2479 bool changed = false;
2480 switch (target) {
2481 case GL_RENDERBUFFER:
2482 if (bound_renderbuffer_ != renderbuffer) {
2483 bound_renderbuffer_ = renderbuffer;
2484 changed = true;
2486 break;
2487 default:
2488 changed = true;
2489 break;
2491 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2492 // used even though it's marked it as used here.
2493 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(renderbuffer);
2494 return changed;
2497 bool GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
2498 // TODO(gman): See note #1 above.
2499 // TODO(gman): Change this to false once we figure out why it's failing
2500 // on daisy.
2501 bool changed = true;
2502 TextureUnit& unit = texture_units_[active_texture_unit_];
2503 switch (target) {
2504 case GL_TEXTURE_2D:
2505 if (unit.bound_texture_2d != texture) {
2506 unit.bound_texture_2d = texture;
2507 changed = true;
2509 break;
2510 case GL_TEXTURE_CUBE_MAP:
2511 if (unit.bound_texture_cube_map != texture) {
2512 unit.bound_texture_cube_map = texture;
2513 changed = true;
2515 break;
2516 case GL_TEXTURE_EXTERNAL_OES:
2517 if (unit.bound_texture_external_oes != texture) {
2518 unit.bound_texture_external_oes = texture;
2519 changed = true;
2521 break;
2522 default:
2523 changed = true;
2524 break;
2526 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2527 // used. even though it's marked it as used here.
2528 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(texture);
2529 return changed;
2532 bool GLES2Implementation::BindVertexArrayHelper(GLuint array) {
2533 // TODO(gman): See note #1 above.
2534 bool changed = false;
2535 if (!vertex_array_object_manager_->BindVertexArray(array, &changed)) {
2536 SetGLError(
2537 GL_INVALID_OPERATION, "glBindVertexArrayOES",
2538 "id was not generated with glGenVertexArrayOES");
2540 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
2541 // because unlike other resources VertexArrayObject ids must
2542 // be generated by GenVertexArrays. A random id to Bind will not
2543 // generate a new object.
2544 return changed;
2547 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
2548 return vertex_array_object_manager_->IsReservedId(id);
2551 void GLES2Implementation::DeleteBuffersHelper(
2552 GLsizei n, const GLuint* buffers) {
2553 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
2554 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
2555 SetGLError(
2556 GL_INVALID_VALUE,
2557 "glDeleteBuffers", "id not created by this context.");
2558 return;
2560 for (GLsizei ii = 0; ii < n; ++ii) {
2561 if (buffers[ii] == bound_array_buffer_id_) {
2562 bound_array_buffer_id_ = 0;
2564 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
2565 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
2566 if (buffer) {
2567 // Free buffer memory, pending the passage of a token.
2568 buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
2569 // Remove buffer.
2570 buffer_tracker_->RemoveBuffer(buffers[ii]);
2572 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
2573 bound_pixel_unpack_transfer_buffer_id_ = 0;
2578 void GLES2Implementation::DeleteBuffersStub(
2579 GLsizei n, const GLuint* buffers) {
2580 helper_->DeleteBuffersImmediate(n, buffers);
2584 void GLES2Implementation::DeleteFramebuffersHelper(
2585 GLsizei n, const GLuint* framebuffers) {
2586 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
2587 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
2588 SetGLError(
2589 GL_INVALID_VALUE,
2590 "glDeleteFramebuffers", "id not created by this context.");
2591 return;
2593 for (GLsizei ii = 0; ii < n; ++ii) {
2594 if (framebuffers[ii] == bound_framebuffer_) {
2595 bound_framebuffer_ = 0;
2597 if (framebuffers[ii] == bound_read_framebuffer_) {
2598 bound_read_framebuffer_ = 0;
2603 void GLES2Implementation::DeleteFramebuffersStub(
2604 GLsizei n, const GLuint* framebuffers) {
2605 helper_->DeleteFramebuffersImmediate(n, framebuffers);
2608 void GLES2Implementation::DeleteRenderbuffersHelper(
2609 GLsizei n, const GLuint* renderbuffers) {
2610 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
2611 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
2612 SetGLError(
2613 GL_INVALID_VALUE,
2614 "glDeleteRenderbuffers", "id not created by this context.");
2615 return;
2617 for (GLsizei ii = 0; ii < n; ++ii) {
2618 if (renderbuffers[ii] == bound_renderbuffer_) {
2619 bound_renderbuffer_ = 0;
2624 void GLES2Implementation::DeleteRenderbuffersStub(
2625 GLsizei n, const GLuint* renderbuffers) {
2626 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
2629 void GLES2Implementation::DeleteTexturesHelper(
2630 GLsizei n, const GLuint* textures) {
2631 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
2632 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
2633 SetGLError(
2634 GL_INVALID_VALUE,
2635 "glDeleteTextures", "id not created by this context.");
2636 return;
2638 for (GLsizei ii = 0; ii < n; ++ii) {
2639 for (GLint tt = 0;
2640 tt < static_state_.int_state.max_combined_texture_image_units;
2641 ++tt) {
2642 TextureUnit& unit = texture_units_[tt];
2643 if (textures[ii] == unit.bound_texture_2d) {
2644 unit.bound_texture_2d = 0;
2646 if (textures[ii] == unit.bound_texture_cube_map) {
2647 unit.bound_texture_cube_map = 0;
2649 if (textures[ii] == unit.bound_texture_external_oes) {
2650 unit.bound_texture_external_oes = 0;
2656 void GLES2Implementation::DeleteVertexArraysOESHelper(
2657 GLsizei n, const GLuint* arrays) {
2658 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
2659 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
2660 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
2661 SetGLError(
2662 GL_INVALID_VALUE,
2663 "glDeleteVertexArraysOES", "id not created by this context.");
2664 return;
2668 void GLES2Implementation::DeleteVertexArraysOESStub(
2669 GLsizei n, const GLuint* arrays) {
2670 helper_->DeleteVertexArraysOESImmediate(n, arrays);
2673 void GLES2Implementation::DeleteTexturesStub(
2674 GLsizei n, const GLuint* textures) {
2675 helper_->DeleteTexturesImmediate(n, textures);
2678 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
2679 GPU_CLIENT_SINGLE_THREAD_CHECK();
2680 GPU_CLIENT_LOG(
2681 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
2682 vertex_array_object_manager_->SetAttribEnable(index, false);
2683 helper_->DisableVertexAttribArray(index);
2684 CheckGLError();
2687 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
2688 GPU_CLIENT_SINGLE_THREAD_CHECK();
2689 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
2690 << index << ")");
2691 vertex_array_object_manager_->SetAttribEnable(index, true);
2692 helper_->EnableVertexAttribArray(index);
2693 CheckGLError();
2696 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
2697 GPU_CLIENT_SINGLE_THREAD_CHECK();
2698 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
2699 << GLES2Util::GetStringDrawMode(mode) << ", "
2700 << first << ", " << count << ")");
2701 if (count < 0) {
2702 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
2703 return;
2705 bool simulated = false;
2706 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
2707 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
2708 return;
2710 helper_->DrawArrays(mode, first, count);
2711 RestoreArrayBuffer(simulated);
2712 CheckGLError();
2715 void GLES2Implementation::GetVertexAttribfv(
2716 GLuint index, GLenum pname, GLfloat* params) {
2717 GPU_CLIENT_SINGLE_THREAD_CHECK();
2718 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
2719 << index << ", "
2720 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2721 << static_cast<const void*>(params) << ")");
2722 uint32 value = 0;
2723 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2724 *params = static_cast<float>(value);
2725 return;
2727 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
2728 typedef cmds::GetVertexAttribfv::Result Result;
2729 Result* result = GetResultAs<Result*>();
2730 if (!result) {
2731 return;
2733 result->SetNumResults(0);
2734 helper_->GetVertexAttribfv(
2735 index, pname, GetResultShmId(), GetResultShmOffset());
2736 WaitForCmd();
2737 result->CopyResult(params);
2738 GPU_CLIENT_LOG_CODE_BLOCK({
2739 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2740 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2743 CheckGLError();
2746 void GLES2Implementation::GetVertexAttribiv(
2747 GLuint index, GLenum pname, GLint* params) {
2748 GPU_CLIENT_SINGLE_THREAD_CHECK();
2749 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
2750 << index << ", "
2751 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2752 << static_cast<const void*>(params) << ")");
2753 uint32 value = 0;
2754 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2755 *params = value;
2756 return;
2758 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
2759 typedef cmds::GetVertexAttribiv::Result Result;
2760 Result* result = GetResultAs<Result*>();
2761 if (!result) {
2762 return;
2764 result->SetNumResults(0);
2765 helper_->GetVertexAttribiv(
2766 index, pname, GetResultShmId(), GetResultShmOffset());
2767 WaitForCmd();
2768 result->CopyResult(params);
2769 GPU_CLIENT_LOG_CODE_BLOCK({
2770 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2771 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2774 CheckGLError();
2777 void GLES2Implementation::Swap() {
2778 SwapBuffers();
2779 gpu_control_->Echo(
2780 base::Bind(&GLES2Implementation::OnSwapBuffersComplete,
2781 weak_ptr_factory_.GetWeakPtr()));
2784 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
2785 PostSubBufferCHROMIUM(sub_buffer.x(),
2786 sub_buffer.y(),
2787 sub_buffer.width(),
2788 sub_buffer.height());
2789 gpu_control_->Echo(base::Bind(&GLES2Implementation::OnSwapBuffersComplete,
2790 weak_ptr_factory_.GetWeakPtr()));
2793 void GLES2Implementation::SetSwapBuffersCompleteCallback(
2794 const base::Closure& swap_buffers_complete_callback) {
2795 swap_buffers_complete_callback_ = swap_buffers_complete_callback;
2798 void GLES2Implementation::OnSwapBuffersComplete() {
2799 if (!swap_buffers_complete_callback_.is_null())
2800 swap_buffers_complete_callback_.Run();
2803 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
2804 const char* feature) {
2805 GPU_CLIENT_SINGLE_THREAD_CHECK();
2806 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
2807 << feature << ")");
2808 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
2809 typedef cmds::EnableFeatureCHROMIUM::Result Result;
2810 Result* result = GetResultAs<Result*>();
2811 if (!result) {
2812 return false;
2814 *result = 0;
2815 SetBucketAsCString(kResultBucketId, feature);
2816 helper_->EnableFeatureCHROMIUM(
2817 kResultBucketId, GetResultShmId(), GetResultShmOffset());
2818 WaitForCmd();
2819 helper_->SetBucketSize(kResultBucketId, 0);
2820 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
2821 return *result;
2824 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
2825 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
2826 GPU_CLIENT_SINGLE_THREAD_CHECK();
2827 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
2828 << target << ", " << offset << ", " << size << ", "
2829 << GLES2Util::GetStringEnum(access) << ")");
2830 // NOTE: target is NOT checked because the service will check it
2831 // and we don't know what targets are valid.
2832 if (access != GL_WRITE_ONLY) {
2833 SetGLErrorInvalidEnum(
2834 "glMapBufferSubDataCHROMIUM", access, "access");
2835 return NULL;
2837 if (offset < 0 || size < 0) {
2838 SetGLError(GL_INVALID_VALUE, "glMapBufferSubDataCHROMIUM", "bad range");
2839 return NULL;
2841 int32 shm_id;
2842 unsigned int shm_offset;
2843 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2844 if (!mem) {
2845 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
2846 return NULL;
2849 std::pair<MappedBufferMap::iterator, bool> result =
2850 mapped_buffers_.insert(std::make_pair(
2851 mem,
2852 MappedBuffer(
2853 access, shm_id, mem, shm_offset, target, offset, size)));
2854 DCHECK(result.second);
2855 GPU_CLIENT_LOG(" returned " << mem);
2856 return mem;
2859 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
2860 GPU_CLIENT_SINGLE_THREAD_CHECK();
2861 GPU_CLIENT_LOG(
2862 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
2863 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
2864 if (it == mapped_buffers_.end()) {
2865 SetGLError(
2866 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
2867 return;
2869 const MappedBuffer& mb = it->second;
2870 helper_->BufferSubData(
2871 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
2872 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
2873 mapped_buffers_.erase(it);
2874 CheckGLError();
2877 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
2878 GLenum target,
2879 GLint level,
2880 GLint xoffset,
2881 GLint yoffset,
2882 GLsizei width,
2883 GLsizei height,
2884 GLenum format,
2885 GLenum type,
2886 GLenum access) {
2887 GPU_CLIENT_SINGLE_THREAD_CHECK();
2888 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
2889 << target << ", " << level << ", "
2890 << xoffset << ", " << yoffset << ", "
2891 << width << ", " << height << ", "
2892 << GLES2Util::GetStringTextureFormat(format) << ", "
2893 << GLES2Util::GetStringPixelType(type) << ", "
2894 << GLES2Util::GetStringEnum(access) << ")");
2895 if (access != GL_WRITE_ONLY) {
2896 SetGLErrorInvalidEnum(
2897 "glMapTexSubImage2DCHROMIUM", access, "access");
2898 return NULL;
2900 // NOTE: target is NOT checked because the service will check it
2901 // and we don't know what targets are valid.
2902 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
2903 SetGLError(
2904 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
2905 return NULL;
2907 uint32 size;
2908 if (!GLES2Util::ComputeImageDataSizes(
2909 width, height, format, type, unpack_alignment_, &size, NULL, NULL)) {
2910 SetGLError(
2911 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
2912 return NULL;
2914 int32 shm_id;
2915 unsigned int shm_offset;
2916 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2917 if (!mem) {
2918 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
2919 return NULL;
2922 std::pair<MappedTextureMap::iterator, bool> result =
2923 mapped_textures_.insert(std::make_pair(
2924 mem,
2925 MappedTexture(
2926 access, shm_id, mem, shm_offset,
2927 target, level, xoffset, yoffset, width, height, format, type)));
2928 DCHECK(result.second);
2929 GPU_CLIENT_LOG(" returned " << mem);
2930 return mem;
2933 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
2934 GPU_CLIENT_SINGLE_THREAD_CHECK();
2935 GPU_CLIENT_LOG(
2936 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
2937 MappedTextureMap::iterator it = mapped_textures_.find(mem);
2938 if (it == mapped_textures_.end()) {
2939 SetGLError(
2940 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
2941 return;
2943 const MappedTexture& mt = it->second;
2944 helper_->TexSubImage2D(
2945 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
2946 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
2947 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
2948 mapped_textures_.erase(it);
2949 CheckGLError();
2952 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
2953 float scale_factor) {
2954 GPU_CLIENT_SINGLE_THREAD_CHECK();
2955 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
2956 << width << ", " << height << ", " << scale_factor << ")");
2957 helper_->ResizeCHROMIUM(width, height, scale_factor);
2958 CheckGLError();
2961 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
2962 GPU_CLIENT_SINGLE_THREAD_CHECK();
2963 GPU_CLIENT_LOG("[" << GetLogPrefix()
2964 << "] glGetRequestableExtensionsCHROMIUM()");
2965 TRACE_EVENT0("gpu",
2966 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
2967 const char* result = NULL;
2968 // Clear the bucket so if the command fails nothing will be in it.
2969 helper_->SetBucketSize(kResultBucketId, 0);
2970 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
2971 std::string str;
2972 if (GetBucketAsString(kResultBucketId, &str)) {
2973 // The set of requestable extensions shrinks as we enable
2974 // them. Because we don't know when the client will stop referring
2975 // to a previous one it queries (see GetString) we need to cache
2976 // the unique results.
2977 std::set<std::string>::const_iterator sit =
2978 requestable_extensions_set_.find(str);
2979 if (sit != requestable_extensions_set_.end()) {
2980 result = sit->c_str();
2981 } else {
2982 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2983 requestable_extensions_set_.insert(str);
2984 DCHECK(insert_result.second);
2985 result = insert_result.first->c_str();
2988 GPU_CLIENT_LOG(" returned " << result);
2989 return reinterpret_cast<const GLchar*>(result);
2992 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
2993 // with VirtualGL contexts.
2994 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
2995 GPU_CLIENT_SINGLE_THREAD_CHECK();
2996 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
2997 << extension << ")");
2998 SetBucketAsCString(kResultBucketId, extension);
2999 helper_->RequestExtensionCHROMIUM(kResultBucketId);
3000 helper_->SetBucketSize(kResultBucketId, 0);
3002 struct ExtensionCheck {
3003 const char* extension;
3004 ExtensionStatus* status;
3006 const ExtensionCheck checks[] = {
3008 "GL_ANGLE_pack_reverse_row_order",
3009 &angle_pack_reverse_row_order_status_,
3012 "GL_CHROMIUM_framebuffer_multisample",
3013 &chromium_framebuffer_multisample_,
3016 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
3017 for (size_t ii = 0; ii < kNumChecks; ++ii) {
3018 const ExtensionCheck& check = checks[ii];
3019 if (*check.status == kUnavailableExtensionStatus &&
3020 !strcmp(extension, check.extension)) {
3021 *check.status = kUnknownExtensionStatus;
3026 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
3027 GPU_CLIENT_SINGLE_THREAD_CHECK();
3028 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
3029 // Wait if this would add too many rate limit tokens.
3030 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
3031 helper_->WaitForToken(rate_limit_tokens_.front());
3032 rate_limit_tokens_.pop();
3034 rate_limit_tokens_.push(helper_->InsertToken());
3037 void GLES2Implementation::GetMultipleIntegervCHROMIUM(
3038 const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size) {
3039 GPU_CLIENT_SINGLE_THREAD_CHECK();
3040 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMultipleIntegervCHROMIUM("
3041 << static_cast<const void*>(pnames) << ", "
3042 << count << ", " << results << ", "
3043 << size << ")");
3044 GPU_CLIENT_LOG_CODE_BLOCK({
3045 for (GLuint i = 0; i < count; ++i) {
3046 GPU_CLIENT_LOG(
3047 " " << i << ": " << GLES2Util::GetStringGLState(pnames[i]));
3051 GetMultipleIntegervState state(pnames, count, results, size);
3052 if (!GetMultipleIntegervSetup(&state)) {
3053 return;
3055 state.buffer = transfer_buffer_->Alloc(state.transfer_buffer_size_needed);
3056 if (!state.buffer) {
3057 SetGLError(GL_OUT_OF_MEMORY, "glGetMultipleIntegervCHROMIUM",
3058 "Transfer buffer allocation failed.");
3059 return;
3061 GetMultipleIntegervRequest(&state);
3062 WaitForCmd();
3063 GetMultipleIntegervOnCompleted(&state);
3065 GPU_CLIENT_LOG(" returned");
3066 GPU_CLIENT_LOG_CODE_BLOCK({
3067 for (int i = 0; i < state.num_results; ++i) {
3068 GPU_CLIENT_LOG(" " << i << ": " << (results[i]));
3072 // TODO(gman): We should be able to free without a token.
3073 transfer_buffer_->FreePendingToken(state.buffer, helper_->InsertToken());
3074 CheckGLError();
3077 bool GLES2Implementation::GetMultipleIntegervSetup(
3078 GetMultipleIntegervState* state) {
3079 state->num_results = 0;
3080 for (GLuint ii = 0; ii < state->pnames_count; ++ii) {
3081 int num = util_.GLGetNumValuesReturned(state->pnames[ii]);
3082 if (!num) {
3083 SetGLErrorInvalidEnum(
3084 "glGetMultipleIntegervCHROMIUM", state->pnames[ii], "pname");
3085 return false;
3087 state->num_results += num;
3089 if (static_cast<size_t>(state->results_size) !=
3090 state->num_results * sizeof(GLint)) {
3091 SetGLError(GL_INVALID_VALUE, "glGetMultipleIntegervCHROMIUM", "bad size");
3092 return false;
3094 for (int ii = 0; ii < state->num_results; ++ii) {
3095 if (state->results[ii] != 0) {
3096 SetGLError(GL_INVALID_VALUE,
3097 "glGetMultipleIntegervCHROMIUM", "results not set to zero.");
3098 return false;
3101 state->transfer_buffer_size_needed =
3102 state->pnames_count * sizeof(state->pnames[0]) +
3103 state->num_results * sizeof(state->results[0]);
3104 return true;
3107 void GLES2Implementation::GetMultipleIntegervRequest(
3108 GetMultipleIntegervState* state) {
3109 GLenum* pnames_buffer = static_cast<GLenum*>(state->buffer);
3110 state->results_buffer = pnames_buffer + state->pnames_count;
3111 memcpy(pnames_buffer, state->pnames, state->pnames_count * sizeof(GLenum));
3112 memset(state->results_buffer, 0, state->num_results * sizeof(GLint));
3113 helper_->GetMultipleIntegervCHROMIUM(
3114 transfer_buffer_->GetShmId(),
3115 transfer_buffer_->GetOffset(pnames_buffer),
3116 state->pnames_count,
3117 transfer_buffer_->GetShmId(),
3118 transfer_buffer_->GetOffset(state->results_buffer),
3119 state->results_size);
3122 void GLES2Implementation::GetMultipleIntegervOnCompleted(
3123 GetMultipleIntegervState* state) {
3124 memcpy(state->results, state->results_buffer, state->results_size);;
3127 void GLES2Implementation::GetAllShaderPrecisionFormatsSetup(
3128 GetAllShaderPrecisionFormatsState* state) {
3129 state->transfer_buffer_size_needed =
3130 state->precision_params_count *
3131 sizeof(cmds::GetShaderPrecisionFormat::Result);
3134 void GLES2Implementation::GetAllShaderPrecisionFormatsRequest(
3135 GetAllShaderPrecisionFormatsState* state) {
3136 typedef cmds::GetShaderPrecisionFormat::Result Result;
3137 Result* result = static_cast<Result*>(state->results_buffer);
3139 for (int i = 0; i < state->precision_params_count; i++) {
3140 result->success = false;
3141 helper_->GetShaderPrecisionFormat(state->precision_params[i][0],
3142 state->precision_params[i][1],
3143 transfer_buffer_->GetShmId(),
3144 transfer_buffer_->GetOffset(result));
3145 result++;
3149 void GLES2Implementation::GetAllShaderPrecisionFormatsOnCompleted(
3150 GetAllShaderPrecisionFormatsState* state) {
3151 typedef cmds::GetShaderPrecisionFormat::Result Result;
3152 Result* result = static_cast<Result*>(state->results_buffer);
3154 for (int i = 0; i < state->precision_params_count; i++) {
3155 if (result->success) {
3156 const GLStaticState::ShaderPrecisionKey key(
3157 state->precision_params[i][0], state->precision_params[i][1]);
3158 static_state_.shader_precisions[key] = *result;
3160 result++;
3164 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3165 GLuint program, std::vector<int8>* result) {
3166 DCHECK(result);
3167 // Clear the bucket so if the command fails nothing will be in it.
3168 helper_->SetBucketSize(kResultBucketId, 0);
3169 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
3170 GetBucketContents(kResultBucketId, result);
3173 void GLES2Implementation::GetProgramInfoCHROMIUM(
3174 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3175 GPU_CLIENT_SINGLE_THREAD_CHECK();
3176 if (bufsize < 0) {
3177 SetGLError(
3178 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3179 return;
3181 if (size == NULL) {
3182 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
3183 return;
3185 // Make sure they've set size to 0 else the value will be undefined on
3186 // lost context.
3187 DCHECK(*size == 0);
3188 std::vector<int8> result;
3189 GetProgramInfoCHROMIUMHelper(program, &result);
3190 if (result.empty()) {
3191 return;
3193 *size = result.size();
3194 if (!info) {
3195 return;
3197 if (static_cast<size_t>(bufsize) < result.size()) {
3198 SetGLError(GL_INVALID_OPERATION,
3199 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3200 return;
3202 memcpy(info, &result[0], result.size());
3205 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
3206 GPU_CLIENT_SINGLE_THREAD_CHECK();
3207 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
3208 << texture << ")");
3209 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
3210 typedef cmds::CreateStreamTextureCHROMIUM::Result Result;
3211 Result* result = GetResultAs<Result*>();
3212 if (!result) {
3213 return GL_ZERO;
3215 *result = GL_ZERO;
3217 helper_->CreateStreamTextureCHROMIUM(texture,
3218 GetResultShmId(),
3219 GetResultShmOffset());
3220 WaitForCmd();
3221 GLuint result_value = *result;
3222 CheckGLError();
3223 return result_value;
3226 void GLES2Implementation::DestroyStreamTextureCHROMIUM(GLuint texture) {
3227 GPU_CLIENT_SINGLE_THREAD_CHECK();
3228 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] DestroyStreamTextureCHROMIUM("
3229 << texture << ")");
3230 TRACE_EVENT0("gpu", "GLES2::DestroyStreamTextureCHROMIUM");
3231 helper_->DestroyStreamTextureCHROMIUM(texture);
3232 CheckGLError();
3235 void GLES2Implementation::PostSubBufferCHROMIUM(
3236 GLint x, GLint y, GLint width, GLint height) {
3237 GPU_CLIENT_SINGLE_THREAD_CHECK();
3238 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
3239 << x << ", " << y << ", " << width << ", " << height << ")");
3240 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
3241 "width", width, "height", height);
3243 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
3244 swap_buffers_tokens_.push(helper_->InsertToken());
3245 helper_->PostSubBufferCHROMIUM(x, y, width, height);
3246 helper_->CommandBufferHelper::Flush();
3247 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
3248 helper_->WaitForToken(swap_buffers_tokens_.front());
3249 swap_buffers_tokens_.pop();
3253 void GLES2Implementation::DeleteQueriesEXTHelper(
3254 GLsizei n, const GLuint* queries) {
3255 // TODO(gman): Remove this as queries are not shared resources.
3256 if (!GetIdHandler(id_namespaces::kQueries)->FreeIds(
3257 this, n, queries, &GLES2Implementation::DeleteQueriesStub)) {
3258 SetGLError(
3259 GL_INVALID_VALUE,
3260 "glDeleteTextures", "id not created by this context.");
3261 return;
3264 for (GLsizei ii = 0; ii < n; ++ii)
3265 query_tracker_->RemoveQuery(queries[ii]);
3267 helper_->DeleteQueriesEXTImmediate(n, queries);
3270 // TODO(gman): Remove this. Queries are not shared resources.
3271 void GLES2Implementation::DeleteQueriesStub(
3272 GLsizei /* n */, const GLuint* /* queries */) {
3275 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
3276 GPU_CLIENT_SINGLE_THREAD_CHECK();
3277 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
3279 // TODO(gman): To be spec compliant IDs from other contexts sharing
3280 // resources need to return true here even though you can't share
3281 // queries across contexts?
3282 return query_tracker_->GetQuery(id) != NULL;
3285 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
3286 GPU_CLIENT_SINGLE_THREAD_CHECK();
3287 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
3288 << GLES2Util::GetStringQueryTarget(target)
3289 << ", " << id << ")");
3291 // if any outstanding queries INV_OP
3292 QueryMap::iterator it = current_queries_.find(target);
3293 if (it != current_queries_.end()) {
3294 SetGLError(
3295 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
3296 return;
3299 // id = 0 INV_OP
3300 if (id == 0) {
3301 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
3302 return;
3305 // TODO(gman) if id not GENned INV_OPERATION
3307 // if id does not have an object
3308 QueryTracker::Query* query = query_tracker_->GetQuery(id);
3309 if (!query) {
3310 query = query_tracker_->CreateQuery(id, target);
3311 if (!query) {
3312 MustBeContextLost();
3313 return;
3315 } else if (query->target() != target) {
3316 SetGLError(
3317 GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
3318 return;
3321 current_queries_[target] = query;
3323 query->Begin(this);
3324 CheckGLError();
3327 void GLES2Implementation::EndQueryEXT(GLenum target) {
3328 GPU_CLIENT_SINGLE_THREAD_CHECK();
3329 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
3330 << GLES2Util::GetStringQueryTarget(target) << ")");
3331 // Don't do anything if the context is lost.
3332 if (helper_->IsContextLost()) {
3333 return;
3336 QueryMap::iterator it = current_queries_.find(target);
3337 if (it == current_queries_.end()) {
3338 SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
3339 return;
3342 QueryTracker::Query* query = it->second;
3343 query->End(this);
3344 current_queries_.erase(it);
3345 CheckGLError();
3348 void GLES2Implementation::GetQueryivEXT(
3349 GLenum target, GLenum pname, GLint* params) {
3350 GPU_CLIENT_SINGLE_THREAD_CHECK();
3351 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
3352 << GLES2Util::GetStringQueryTarget(target) << ", "
3353 << GLES2Util::GetStringQueryParameter(pname) << ", "
3354 << static_cast<const void*>(params) << ")");
3356 if (pname != GL_CURRENT_QUERY_EXT) {
3357 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
3358 return;
3360 QueryMap::iterator it = current_queries_.find(target);
3361 if (it != current_queries_.end()) {
3362 QueryTracker::Query* query = it->second;
3363 *params = query->id();
3364 } else {
3365 *params = 0;
3367 GPU_CLIENT_LOG(" " << *params);
3368 CheckGLError();
3371 void GLES2Implementation::GetQueryObjectuivEXT(
3372 GLuint id, GLenum pname, GLuint* params) {
3373 GPU_CLIENT_SINGLE_THREAD_CHECK();
3374 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
3375 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
3376 << static_cast<const void*>(params) << ")");
3378 QueryTracker::Query* query = query_tracker_->GetQuery(id);
3379 if (!query) {
3380 SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
3381 return;
3384 QueryMap::iterator it = current_queries_.find(query->target());
3385 if (it != current_queries_.end()) {
3386 SetGLError(
3387 GL_INVALID_OPERATION,
3388 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
3389 return;
3392 if (query->NeverUsed()) {
3393 SetGLError(
3394 GL_INVALID_OPERATION,
3395 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
3396 return;
3399 switch (pname) {
3400 case GL_QUERY_RESULT_EXT:
3401 if (!query->CheckResultsAvailable(helper_)) {
3402 helper_->WaitForToken(query->token());
3403 if (!query->CheckResultsAvailable(helper_)) {
3404 // TODO(gman): Speed this up.
3405 WaitForCmd();
3406 CHECK(query->CheckResultsAvailable(helper_));
3409 *params = query->GetResult();
3410 break;
3411 case GL_QUERY_RESULT_AVAILABLE_EXT:
3412 *params = query->CheckResultsAvailable(helper_);
3413 break;
3414 default:
3415 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
3416 break;
3418 GPU_CLIENT_LOG(" " << *params);
3419 CheckGLError();
3422 void GLES2Implementation::DrawArraysInstancedANGLE(
3423 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
3424 GPU_CLIENT_SINGLE_THREAD_CHECK();
3425 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
3426 << GLES2Util::GetStringDrawMode(mode) << ", "
3427 << first << ", " << count << ", " << primcount << ")");
3428 if (count < 0) {
3429 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
3430 return;
3432 if (primcount < 0) {
3433 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
3434 return;
3436 if (primcount == 0) {
3437 return;
3439 bool simulated = false;
3440 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
3441 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
3442 &simulated)) {
3443 return;
3445 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
3446 RestoreArrayBuffer(simulated);
3447 CheckGLError();
3450 void GLES2Implementation::DrawElementsInstancedANGLE(
3451 GLenum mode, GLsizei count, GLenum type, const void* indices,
3452 GLsizei primcount) {
3453 GPU_CLIENT_SINGLE_THREAD_CHECK();
3454 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
3455 << GLES2Util::GetStringDrawMode(mode) << ", "
3456 << count << ", "
3457 << GLES2Util::GetStringIndexType(type) << ", "
3458 << static_cast<const void*>(indices) << ", "
3459 << primcount << ")");
3460 if (count < 0) {
3461 SetGLError(GL_INVALID_VALUE,
3462 "glDrawElementsInstancedANGLE", "count less than 0.");
3463 return;
3465 if (count == 0) {
3466 return;
3468 if (primcount < 0) {
3469 SetGLError(GL_INVALID_VALUE,
3470 "glDrawElementsInstancedANGLE", "primcount < 0");
3471 return;
3473 if (primcount == 0) {
3474 return;
3476 GLuint offset = 0;
3477 bool simulated = false;
3478 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
3479 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
3480 indices, &offset, &simulated)) {
3481 return;
3483 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
3484 RestoreElementAndArrayBuffers(simulated);
3485 CheckGLError();
3488 void GLES2Implementation::GenMailboxCHROMIUM(
3489 GLbyte* mailbox) {
3490 GPU_CLIENT_SINGLE_THREAD_CHECK();
3491 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
3492 << static_cast<const void*>(mailbox) << ")");
3493 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
3495 std::vector<gpu::Mailbox> names;
3496 if (!gpu_control_->GenerateMailboxNames(1, &names)) {
3497 SetGLError(GL_OUT_OF_MEMORY, "glGenMailboxCHROMIUM", "Generate failed.");
3498 return;
3500 memcpy(mailbox, names[0].name, GL_MAILBOX_SIZE_CHROMIUM);
3503 void GLES2Implementation::PushGroupMarkerEXT(
3504 GLsizei length, const GLchar* marker) {
3505 GPU_CLIENT_SINGLE_THREAD_CHECK();
3506 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
3507 << length << ", " << marker << ")");
3508 if (!marker) {
3509 marker = "";
3511 SetBucketAsString(
3512 kResultBucketId,
3513 (length ? std::string(marker, length) : std::string(marker)));
3514 helper_->PushGroupMarkerEXT(kResultBucketId);
3515 helper_->SetBucketSize(kResultBucketId, 0);
3516 debug_marker_manager_.PushGroup(
3517 length ? std::string(marker, length) : std::string(marker));
3520 void GLES2Implementation::InsertEventMarkerEXT(
3521 GLsizei length, const GLchar* marker) {
3522 GPU_CLIENT_SINGLE_THREAD_CHECK();
3523 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
3524 << length << ", " << marker << ")");
3525 if (!marker) {
3526 marker = "";
3528 SetBucketAsString(
3529 kResultBucketId,
3530 (length ? std::string(marker, length) : std::string(marker)));
3531 helper_->InsertEventMarkerEXT(kResultBucketId);
3532 helper_->SetBucketSize(kResultBucketId, 0);
3533 debug_marker_manager_.SetMarker(
3534 length ? std::string(marker, length) : std::string(marker));
3537 void GLES2Implementation::PopGroupMarkerEXT() {
3538 GPU_CLIENT_SINGLE_THREAD_CHECK();
3539 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
3540 helper_->PopGroupMarkerEXT();
3541 debug_marker_manager_.PopGroup();
3544 void GLES2Implementation::TraceBeginCHROMIUM(const char* name) {
3545 GPU_CLIENT_SINGLE_THREAD_CHECK();
3546 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
3547 << name << ")");
3548 if (current_trace_name_.get()) {
3549 SetGLError(GL_INVALID_OPERATION, "glTraceBeginCHROMIUM",
3550 "trace already running");
3551 return;
3553 TRACE_EVENT_COPY_ASYNC_BEGIN0("gpu", name, this);
3554 SetBucketAsCString(kResultBucketId, name);
3555 helper_->TraceBeginCHROMIUM(kResultBucketId);
3556 helper_->SetBucketSize(kResultBucketId, 0);
3557 current_trace_name_.reset(new std::string(name));
3560 void GLES2Implementation::TraceEndCHROMIUM() {
3561 GPU_CLIENT_SINGLE_THREAD_CHECK();
3562 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
3563 if (!current_trace_name_.get()) {
3564 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
3565 "missing begin trace");
3566 return;
3568 helper_->TraceEndCHROMIUM();
3569 TRACE_EVENT_COPY_ASYNC_END0("gpu", current_trace_name_->c_str(), this);
3570 current_trace_name_.reset();
3573 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
3574 GPU_CLIENT_SINGLE_THREAD_CHECK();
3575 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
3576 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
3577 switch (target) {
3578 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3579 if (access != GL_READ_ONLY) {
3580 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3581 return NULL;
3583 break;
3584 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3585 if (access != GL_WRITE_ONLY) {
3586 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3587 return NULL;
3589 break;
3590 default:
3591 SetGLError(
3592 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
3593 return NULL;
3595 GLuint buffer_id;
3596 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
3597 if (!buffer_id) {
3598 return NULL;
3600 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3601 if (!buffer) {
3602 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
3603 return NULL;
3605 if (buffer->mapped()) {
3606 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
3607 return NULL;
3609 // Here we wait for previous transfer operations to be finished.
3610 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
3611 // with this method of synchronization. Until this is fixed,
3612 // MapBufferCHROMIUM will not block even if the transfer is not ready
3613 // for these calls.
3614 if (buffer->transfer_ready_token()) {
3615 helper_->WaitForToken(buffer->transfer_ready_token());
3616 buffer->set_transfer_ready_token(0);
3618 buffer->set_mapped(true);
3620 GPU_CLIENT_LOG(" returned " << buffer->address());
3621 CheckGLError();
3622 return buffer->address();
3625 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
3626 GPU_CLIENT_SINGLE_THREAD_CHECK();
3627 GPU_CLIENT_LOG(
3628 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
3629 GLuint buffer_id;
3630 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
3631 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
3633 if (!buffer_id) {
3634 return false;
3636 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3637 if (!buffer) {
3638 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
3639 return false;
3641 if (!buffer->mapped()) {
3642 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
3643 return false;
3645 buffer->set_mapped(false);
3646 CheckGLError();
3647 return true;
3650 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
3651 GLenum target, GLint level, GLint internalformat, GLsizei width,
3652 GLsizei height, GLint border, GLenum format, GLenum type,
3653 const void* pixels) {
3654 GPU_CLIENT_SINGLE_THREAD_CHECK();
3655 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
3656 << GLES2Util::GetStringTextureTarget(target) << ", "
3657 << level << ", "
3658 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
3659 << width << ", " << height << ", " << border << ", "
3660 << GLES2Util::GetStringTextureFormat(format) << ", "
3661 << GLES2Util::GetStringPixelType(type) << ", "
3662 << static_cast<const void*>(pixels) << ")");
3663 if (level < 0 || height < 0 || width < 0) {
3664 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
3665 return;
3667 uint32 size;
3668 uint32 unpadded_row_size;
3669 uint32 padded_row_size;
3670 if (!GLES2Util::ComputeImageDataSizes(
3671 width, height, format, type, unpack_alignment_, &size,
3672 &unpadded_row_size, &padded_row_size)) {
3673 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
3674 return;
3677 // If there's no data/buffer just issue the AsyncTexImage2D
3678 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
3679 helper_->AsyncTexImage2DCHROMIUM(
3680 target, level, internalformat, width, height, border, format, type,
3681 0, 0);
3682 return;
3685 // Otherwise, async uploads require a transfer buffer to be bound.
3686 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3687 // the buffer before the transfer is finished. (Currently such
3688 // synchronization has to be handled manually.)
3689 GLuint offset = ToGLuint(pixels);
3690 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3691 bound_pixel_unpack_transfer_buffer_id_,
3692 "glAsyncTexImage2DCHROMIUM", offset, size);
3693 if (buffer && buffer->shm_id() != -1) {
3694 helper_->AsyncTexImage2DCHROMIUM(
3695 target, level, internalformat, width, height, border, format, type,
3696 buffer->shm_id(), buffer->shm_offset() + offset);
3700 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
3701 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
3702 GLsizei height, GLenum format, GLenum type, const void* pixels) {
3703 GPU_CLIENT_SINGLE_THREAD_CHECK();
3704 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
3705 << GLES2Util::GetStringTextureTarget(target) << ", "
3706 << level << ", "
3707 << xoffset << ", " << yoffset << ", "
3708 << width << ", " << height << ", "
3709 << GLES2Util::GetStringTextureFormat(format) << ", "
3710 << GLES2Util::GetStringPixelType(type) << ", "
3711 << static_cast<const void*>(pixels) << ")");
3712 if (level < 0 || height < 0 || width < 0) {
3713 SetGLError(
3714 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
3715 return;
3718 uint32 size;
3719 uint32 unpadded_row_size;
3720 uint32 padded_row_size;
3721 if (!GLES2Util::ComputeImageDataSizes(
3722 width, height, format, type, unpack_alignment_, &size,
3723 &unpadded_row_size, &padded_row_size)) {
3724 SetGLError(
3725 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
3726 return;
3729 // Async uploads require a transfer buffer to be bound.
3730 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3731 // the buffer before the transfer is finished. (Currently such
3732 // synchronization has to be handled manually.)
3733 GLuint offset = ToGLuint(pixels);
3734 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3735 bound_pixel_unpack_transfer_buffer_id_,
3736 "glAsyncTexSubImage2DCHROMIUM", offset, size);
3737 if (buffer && buffer->shm_id() != -1) {
3738 helper_->AsyncTexSubImage2DCHROMIUM(
3739 target, level, xoffset, yoffset, width, height, format, type,
3740 buffer->shm_id(), buffer->shm_offset() + offset);
3744 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
3745 GPU_CLIENT_SINGLE_THREAD_CHECK();
3746 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
3747 << GLES2Util::GetStringTextureTarget(target) << ")");
3748 helper_->WaitAsyncTexImage2DCHROMIUM(target);
3749 CheckGLError();
3752 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
3753 GPU_CLIENT_SINGLE_THREAD_CHECK();
3754 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
3755 helper_->CommandBufferHelper::Flush();
3756 return gpu_control_->InsertSyncPoint();
3759 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(
3760 GLsizei width, GLsizei height, GLenum internalformat) {
3761 if (width <= 0) {
3762 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
3763 return 0;
3766 if (height <= 0) {
3767 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
3768 return 0;
3770 // Flush the command stream to ensure ordering in case the newly
3771 // returned image_id has recently been in use with a different buffer.
3772 helper_->CommandBufferHelper::Flush();
3774 // Create new buffer.
3775 GLuint buffer_id = gpu_memory_buffer_tracker_->CreateBuffer(
3776 width, height, internalformat);
3777 if (buffer_id == 0) {
3778 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "out of GPU memory.");
3779 return 0;
3781 return buffer_id;
3784 GLuint GLES2Implementation::CreateImageCHROMIUM(
3785 GLsizei width, GLsizei height, GLenum internalformat) {
3786 GPU_CLIENT_SINGLE_THREAD_CHECK();
3787 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM("
3788 << width << ", "
3789 << height << ", "
3790 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ")");
3791 GLuint image_id = CreateImageCHROMIUMHelper(width, height, internalformat);
3792 CheckGLError();
3793 return image_id;
3796 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
3797 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3798 image_id);
3799 if (!gpu_buffer) {
3800 SetGLError(GL_INVALID_OPERATION, "glDestroyImageCHROMIUM", "invalid image");
3801 return;
3804 // Flush the command stream to make sure all pending commands
3805 // that may refer to the image_id are executed on the service side.
3806 helper_->CommandBufferHelper::Flush();
3807 gpu_memory_buffer_tracker_->RemoveBuffer(image_id);
3810 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
3811 GPU_CLIENT_SINGLE_THREAD_CHECK();
3812 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
3813 << image_id << ")");
3814 DestroyImageCHROMIUMHelper(image_id);
3815 CheckGLError();
3818 void GLES2Implementation::UnmapImageCHROMIUMHelper(GLuint image_id) {
3819 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3820 image_id);
3821 if (!gpu_buffer) {
3822 SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "invalid image");
3823 return;
3826 if (!gpu_buffer->IsMapped()) {
3827 SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "not mapped");
3828 return;
3830 gpu_buffer->Unmap();
3833 void GLES2Implementation::UnmapImageCHROMIUM(GLuint image_id) {
3834 GPU_CLIENT_SINGLE_THREAD_CHECK();
3835 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapImageCHROMIUM("
3836 << image_id << ")");
3838 UnmapImageCHROMIUMHelper(image_id);
3839 CheckGLError();
3842 void* GLES2Implementation::MapImageCHROMIUMHelper(GLuint image_id,
3843 GLenum access) {
3844 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3845 image_id);
3846 if (!gpu_buffer) {
3847 SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "invalid image");
3848 return NULL;
3850 gfx::GpuMemoryBuffer::AccessMode mode;
3851 switch(access) {
3852 case GL_WRITE_ONLY:
3853 mode = gfx::GpuMemoryBuffer::WRITE_ONLY;
3854 break;
3855 case GL_READ_ONLY:
3856 mode = gfx::GpuMemoryBuffer::READ_ONLY;
3857 break;
3858 case GL_READ_WRITE:
3859 mode = gfx::GpuMemoryBuffer::READ_WRITE;
3860 break;
3861 default:
3862 SetGLError(GL_INVALID_ENUM, "glMapImageCHROMIUM",
3863 "invalid GPU access mode");
3864 return NULL;
3867 if (gpu_buffer->IsMapped()) {
3868 SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "already mapped");
3869 return NULL;
3872 void* mapped_buffer = NULL;
3873 gpu_buffer->Map(mode, &mapped_buffer);
3874 return mapped_buffer;
3877 void* GLES2Implementation::MapImageCHROMIUM(
3878 GLuint image_id, GLenum access) {
3879 GPU_CLIENT_SINGLE_THREAD_CHECK();
3880 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapImageCHROMIUM("
3881 << image_id << ", "
3882 << GLES2Util::GetStringEnum(access) << ")");
3884 void* mapped = MapImageCHROMIUMHelper(image_id, access);
3885 CheckGLError();
3886 return mapped;
3889 void GLES2Implementation::GetImageParameterivCHROMIUMHelper(
3890 GLuint image_id, GLenum pname, GLint* params) {
3891 if (pname != GL_IMAGE_ROWBYTES_CHROMIUM) {
3892 SetGLError(GL_INVALID_ENUM, "glGetImageParameterivCHROMIUM",
3893 "invalid parameter");
3894 return;
3897 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3898 image_id);
3899 if (!gpu_buffer) {
3900 SetGLError(GL_INVALID_OPERATION, "glGetImageParameterivCHROMIUM",
3901 "invalid image");
3902 return;
3905 *params = gpu_buffer->GetStride();
3908 void GLES2Implementation::GetImageParameterivCHROMIUM(
3909 GLuint image_id, GLenum pname, GLint* params) {
3910 GPU_CLIENT_SINGLE_THREAD_CHECK();
3911 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
3912 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glImageParameterivCHROMIUM("
3913 << image_id << ", "
3914 << GLES2Util::GetStringBufferParameter(pname) << ", "
3915 << static_cast<const void*>(params) << ")");
3916 GetImageParameterivCHROMIUMHelper(image_id, pname, params);
3917 CheckGLError();
3920 // Include the auto-generated part of this file. We split this because it means
3921 // we can easily edit the non-auto generated parts right here in this file
3922 // instead of having to edit some template or the code generator.
3923 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
3925 } // namespace gles2
3926 } // namespace gpu