Updated Khronos GLES2 headers.
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blobf1d33926efb3d3afd1dbffdd641f81ecda8251ee
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 current_query_(NULL),
114 error_message_callback_(NULL),
115 gpu_control_(gpu_control),
116 surface_visible_(true),
117 free_everything_when_invisible_(free_everything_when_invisible),
118 capabilities_(gpu_control->GetCapabilities()),
119 weak_ptr_factory_(this) {
120 DCHECK(helper);
121 DCHECK(transfer_buffer);
122 DCHECK(gpu_control);
124 char temp[128];
125 sprintf(temp, "%p", static_cast<void*>(this));
126 this_in_hex_ = std::string(temp);
128 GPU_CLIENT_LOG_CODE_BLOCK({
129 debug_ = CommandLine::ForCurrentProcess()->HasSwitch(
130 switches::kEnableGPUClientLogging);
133 share_group_ =
134 (share_group ? share_group : new ShareGroup(bind_generates_resource));
136 memset(&reserved_ids_, 0, sizeof(reserved_ids_));
139 bool GLES2Implementation::Initialize(
140 unsigned int starting_transfer_buffer_size,
141 unsigned int min_transfer_buffer_size,
142 unsigned int max_transfer_buffer_size,
143 unsigned int mapped_memory_limit) {
144 DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
145 DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
146 DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
148 if (!transfer_buffer_->Initialize(
149 starting_transfer_buffer_size,
150 kStartingOffset,
151 min_transfer_buffer_size,
152 max_transfer_buffer_size,
153 kAlignment,
154 kSizeToFlush)) {
155 return false;
158 mapped_memory_.reset(new MappedMemoryManager(helper_, mapped_memory_limit));
160 unsigned chunk_size = 2 * 1024 * 1024;
161 if (mapped_memory_limit != kNoLimit) {
162 // Use smaller chunks if the client is very memory conscientious.
163 chunk_size = std::min(mapped_memory_limit / 4, chunk_size);
165 mapped_memory_->set_chunk_size_multiple(chunk_size);
167 if (!QueryAndCacheStaticState())
168 return false;
170 util_.set_num_compressed_texture_formats(
171 static_state_.int_state.num_compressed_texture_formats);
172 util_.set_num_shader_binary_formats(
173 static_state_.int_state.num_shader_binary_formats);
175 texture_units_.reset(
176 new TextureUnit[
177 static_state_.int_state.max_combined_texture_image_units]);
179 query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
180 buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
181 gpu_memory_buffer_tracker_.reset(new GpuMemoryBufferTracker(gpu_control_));
183 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
184 GetIdHandler(id_namespaces::kBuffers)->MakeIds(
185 this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
186 #endif
188 vertex_array_object_manager_.reset(new VertexArrayObjectManager(
189 static_state_.int_state.max_vertex_attribs,
190 reserved_ids_[0],
191 reserved_ids_[1]));
193 return true;
196 bool GLES2Implementation::QueryAndCacheStaticState() {
197 // Setup query for multiple GetIntegerv's
198 static const GLenum pnames[] = {
199 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
200 GL_MAX_CUBE_MAP_TEXTURE_SIZE,
201 GL_MAX_FRAGMENT_UNIFORM_VECTORS,
202 GL_MAX_RENDERBUFFER_SIZE,
203 GL_MAX_TEXTURE_IMAGE_UNITS,
204 GL_MAX_TEXTURE_SIZE,
205 GL_MAX_VARYING_VECTORS,
206 GL_MAX_VERTEX_ATTRIBS,
207 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
208 GL_MAX_VERTEX_UNIFORM_VECTORS,
209 GL_NUM_COMPRESSED_TEXTURE_FORMATS,
210 GL_NUM_SHADER_BINARY_FORMATS,
213 GetMultipleIntegervState integerv_state(
214 pnames, arraysize(pnames),
215 &static_state_.int_state.max_combined_texture_image_units,
216 sizeof(static_state_.int_state));
217 if (!GetMultipleIntegervSetup(&integerv_state)) {
218 return false;
221 // Setup query for multiple GetShaderPrecisionFormat's
222 static const GLenum precision_params[][2] = {
223 { GL_VERTEX_SHADER, GL_LOW_INT },
224 { GL_VERTEX_SHADER, GL_MEDIUM_INT },
225 { GL_VERTEX_SHADER, GL_HIGH_INT },
226 { GL_VERTEX_SHADER, GL_LOW_FLOAT },
227 { GL_VERTEX_SHADER, GL_MEDIUM_FLOAT },
228 { GL_VERTEX_SHADER, GL_HIGH_FLOAT },
229 { GL_FRAGMENT_SHADER, GL_LOW_INT },
230 { GL_FRAGMENT_SHADER, GL_MEDIUM_INT },
231 { GL_FRAGMENT_SHADER, GL_HIGH_INT },
232 { GL_FRAGMENT_SHADER, GL_LOW_FLOAT },
233 { GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT },
234 { GL_FRAGMENT_SHADER, GL_HIGH_FLOAT },
237 GetAllShaderPrecisionFormatsState precision_state(
238 precision_params, arraysize(precision_params));
239 GetAllShaderPrecisionFormatsSetup(&precision_state);
241 // Allocate and partition transfer buffer for all requests
242 void* buffer = transfer_buffer_->Alloc(
243 integerv_state.transfer_buffer_size_needed +
244 precision_state.transfer_buffer_size_needed);
245 if (!buffer) {
246 SetGLError(GL_OUT_OF_MEMORY, "QueryAndCacheStaticState",
247 "Transfer buffer allocation failed.");
248 return false;
250 integerv_state.buffer = buffer;
251 precision_state.results_buffer =
252 static_cast<char*>(buffer) + integerv_state.transfer_buffer_size_needed;
254 // Make all the requests and wait once for all the results.
255 GetMultipleIntegervRequest(&integerv_state);
256 GetAllShaderPrecisionFormatsRequest(&precision_state);
257 WaitForCmd();
258 GetMultipleIntegervOnCompleted(&integerv_state);
259 GetAllShaderPrecisionFormatsOnCompleted(&precision_state);
261 // TODO(gman): We should be able to free without a token.
262 transfer_buffer_->FreePendingToken(buffer, helper_->InsertToken());
263 CheckGLError();
265 return true;
268 GLES2Implementation::~GLES2Implementation() {
269 // Make sure the queries are finished otherwise we'll delete the
270 // shared memory (mapped_memory_) which will free the memory used
271 // by the queries. The GPU process when validating that memory is still
272 // shared will fail and abort (ie, it will stop running).
273 WaitForCmd();
274 query_tracker_.reset();
276 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
277 DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
278 #endif
279 buffer_tracker_.reset();
281 // Make sure the commands make it the service.
282 WaitForCmd();
285 GLES2CmdHelper* GLES2Implementation::helper() const {
286 return helper_;
289 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
290 return share_group_->GetIdHandler(namespace_id);
293 void* GLES2Implementation::GetResultBuffer() {
294 return transfer_buffer_->GetResultBuffer();
297 int32 GLES2Implementation::GetResultShmId() {
298 return transfer_buffer_->GetShmId();
301 uint32 GLES2Implementation::GetResultShmOffset() {
302 return transfer_buffer_->GetResultOffset();
305 void GLES2Implementation::FreeUnusedSharedMemory() {
306 mapped_memory_->FreeUnused();
309 void GLES2Implementation::FreeEverything() {
310 WaitForCmd();
311 query_tracker_->Shrink();
312 FreeUnusedSharedMemory();
313 transfer_buffer_->Free();
314 helper_->FreeRingBuffer();
317 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
318 if (!helper_->IsContextLost())
319 callback.Run();
322 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
323 const base::Closure& callback) {
324 gpu_control_->SignalSyncPoint(
325 sync_point,
326 base::Bind(&GLES2Implementation::RunIfContextNotLost,
327 weak_ptr_factory_.GetWeakPtr(),
328 callback));
331 void GLES2Implementation::SignalQuery(uint32 query,
332 const base::Closure& callback) {
333 // Flush previously entered commands to ensure ordering with any
334 // glBeginQueryEXT() calls that may have been put into the context.
335 ShallowFlushCHROMIUM();
336 gpu_control_->SignalQuery(
337 query,
338 base::Bind(&GLES2Implementation::RunIfContextNotLost,
339 weak_ptr_factory_.GetWeakPtr(),
340 callback));
343 void GLES2Implementation::SetSurfaceVisible(bool visible) {
344 // TODO(piman): This probably should be ShallowFlushCHROMIUM().
345 Flush();
346 surface_visible_ = visible;
347 gpu_control_->SetSurfaceVisible(visible);
348 if (!visible)
349 FreeEverything();
352 void GLES2Implementation::SendManagedMemoryStats(
353 const ManagedMemoryStats& stats) {
354 gpu_control_->SendManagedMemoryStats(stats);
357 void GLES2Implementation::WaitForCmd() {
358 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
359 helper_->CommandBufferHelper::Finish();
362 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
363 const char* extensions =
364 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
365 if (!extensions)
366 return false;
368 int length = strlen(ext);
369 while (true) {
370 int n = strcspn(extensions, " ");
371 if (n == length && 0 == strncmp(ext, extensions, length)) {
372 return true;
374 if ('\0' == extensions[n]) {
375 return false;
377 extensions += n + 1;
381 bool GLES2Implementation::IsExtensionAvailableHelper(
382 const char* extension, ExtensionStatus* status) {
383 switch (*status) {
384 case kAvailableExtensionStatus:
385 return true;
386 case kUnavailableExtensionStatus:
387 return false;
388 default: {
389 bool available = IsExtensionAvailable(extension);
390 *status = available ? kAvailableExtensionStatus :
391 kUnavailableExtensionStatus;
392 return available;
397 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
398 return IsExtensionAvailableHelper(
399 "GL_ANGLE_pack_reverse_row_order",
400 &angle_pack_reverse_row_order_status_);
403 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
404 return IsExtensionAvailableHelper(
405 "GL_CHROMIUM_framebuffer_multisample",
406 &chromium_framebuffer_multisample_);
409 const std::string& GLES2Implementation::GetLogPrefix() const {
410 const std::string& prefix(debug_marker_manager_.GetMarker());
411 return prefix.empty() ? this_in_hex_ : prefix;
414 GLenum GLES2Implementation::GetError() {
415 GPU_CLIENT_SINGLE_THREAD_CHECK();
416 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
417 GLenum err = GetGLError();
418 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
419 return err;
422 GLenum GLES2Implementation::GetClientSideGLError() {
423 if (error_bits_ == 0) {
424 return GL_NO_ERROR;
427 GLenum error = GL_NO_ERROR;
428 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
429 if ((error_bits_ & mask) != 0) {
430 error = GLES2Util::GLErrorBitToGLError(mask);
431 break;
434 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
435 return error;
438 GLenum GLES2Implementation::GetGLError() {
439 TRACE_EVENT0("gpu", "GLES2::GetGLError");
440 // Check the GL error first, then our wrapped error.
441 typedef cmds::GetError::Result Result;
442 Result* result = GetResultAs<Result*>();
443 // If we couldn't allocate a result the context is lost.
444 if (!result) {
445 return GL_NO_ERROR;
447 *result = GL_NO_ERROR;
448 helper_->GetError(GetResultShmId(), GetResultShmOffset());
449 WaitForCmd();
450 GLenum error = *result;
451 if (error == GL_NO_ERROR) {
452 error = GetClientSideGLError();
453 } else {
454 // There was an error, clear the corresponding wrapped error.
455 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
457 return error;
460 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
461 void GLES2Implementation::FailGLError(GLenum error) {
462 if (error != GL_NO_ERROR) {
463 NOTREACHED() << "Error";
466 // NOTE: Calling GetGLError overwrites data in the result buffer.
467 void GLES2Implementation::CheckGLError() {
468 FailGLError(GetGLError());
470 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
472 void GLES2Implementation::SetGLError(
473 GLenum error, const char* function_name, const char* msg) {
474 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
475 << GLES2Util::GetStringError(error) << ": "
476 << function_name << ": " << msg);
477 FailGLError(error);
478 if (msg) {
479 last_error_ = msg;
481 if (error_message_callback_) {
482 std::string temp(GLES2Util::GetStringError(error) + " : " +
483 function_name + ": " + (msg ? msg : ""));
484 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
486 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
489 void GLES2Implementation::SetGLErrorInvalidEnum(
490 const char* function_name, GLenum value, const char* label) {
491 SetGLError(GL_INVALID_ENUM, function_name,
492 (std::string(label) + " was " +
493 GLES2Util::GetStringEnum(value)).c_str());
496 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
497 std::vector<int8>* data) {
498 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
499 DCHECK(data);
500 const uint32 kStartSize = 32 * 1024;
501 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
502 if (!buffer.valid()) {
503 return false;
505 typedef cmd::GetBucketStart::Result Result;
506 Result* result = GetResultAs<Result*>();
507 if (!result) {
508 return false;
510 *result = 0;
511 helper_->GetBucketStart(
512 bucket_id, GetResultShmId(), GetResultShmOffset(),
513 buffer.size(), buffer.shm_id(), buffer.offset());
514 WaitForCmd();
515 uint32 size = *result;
516 data->resize(size);
517 if (size > 0u) {
518 uint32 offset = 0;
519 while (size) {
520 if (!buffer.valid()) {
521 buffer.Reset(size);
522 if (!buffer.valid()) {
523 return false;
525 helper_->GetBucketData(
526 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
527 WaitForCmd();
529 uint32 size_to_copy = std::min(size, buffer.size());
530 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
531 offset += size_to_copy;
532 size -= size_to_copy;
533 buffer.Release();
535 // Free the bucket. This is not required but it does free up the memory.
536 // and we don't have to wait for the result so from the client's perspective
537 // it's cheap.
538 helper_->SetBucketSize(bucket_id, 0);
540 return true;
543 void GLES2Implementation::SetBucketContents(
544 uint32 bucket_id, const void* data, size_t size) {
545 DCHECK(data);
546 helper_->SetBucketSize(bucket_id, size);
547 if (size > 0u) {
548 uint32 offset = 0;
549 while (size) {
550 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
551 if (!buffer.valid()) {
552 return;
554 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
555 buffer.size());
556 helper_->SetBucketData(
557 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
558 offset += buffer.size();
559 size -= buffer.size();
564 void GLES2Implementation::SetBucketAsCString(
565 uint32 bucket_id, const char* str) {
566 // NOTE: strings are passed NULL terminated. That means the empty
567 // string will have a size of 1 and no-string will have a size of 0
568 if (str) {
569 SetBucketContents(bucket_id, str, strlen(str) + 1);
570 } else {
571 helper_->SetBucketSize(bucket_id, 0);
575 bool GLES2Implementation::GetBucketAsString(
576 uint32 bucket_id, std::string* str) {
577 DCHECK(str);
578 std::vector<int8> data;
579 // NOTE: strings are passed NULL terminated. That means the empty
580 // string will have a size of 1 and no-string will have a size of 0
581 if (!GetBucketContents(bucket_id, &data)) {
582 return false;
584 if (data.empty()) {
585 return false;
587 str->assign(&data[0], &data[0] + data.size() - 1);
588 return true;
591 void GLES2Implementation::SetBucketAsString(
592 uint32 bucket_id, const std::string& str) {
593 // NOTE: strings are passed NULL terminated. That means the empty
594 // string will have a size of 1 and no-string will have a size of 0
595 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
598 void GLES2Implementation::Disable(GLenum cap) {
599 GPU_CLIENT_SINGLE_THREAD_CHECK();
600 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
601 << GLES2Util::GetStringCapability(cap) << ")");
602 bool changed = false;
603 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
604 helper_->Disable(cap);
606 CheckGLError();
609 void GLES2Implementation::Enable(GLenum cap) {
610 GPU_CLIENT_SINGLE_THREAD_CHECK();
611 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
612 << GLES2Util::GetStringCapability(cap) << ")");
613 bool changed = false;
614 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
615 helper_->Enable(cap);
617 CheckGLError();
620 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
621 GPU_CLIENT_SINGLE_THREAD_CHECK();
622 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
623 << GLES2Util::GetStringCapability(cap) << ")");
624 bool state = false;
625 if (!state_.GetEnabled(cap, &state)) {
626 typedef cmds::IsEnabled::Result Result;
627 Result* result = GetResultAs<Result*>();
628 if (!result) {
629 return GL_FALSE;
631 *result = 0;
632 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
633 WaitForCmd();
634 state = (*result) != 0;
637 GPU_CLIENT_LOG("returned " << state);
638 CheckGLError();
639 return state;
642 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
643 switch (pname) {
644 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
645 *params = static_state_.int_state.max_combined_texture_image_units;
646 return true;
647 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
648 *params = static_state_.int_state.max_cube_map_texture_size;
649 return true;
650 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
651 *params = static_state_.int_state.max_fragment_uniform_vectors;
652 return true;
653 case GL_MAX_RENDERBUFFER_SIZE:
654 *params = static_state_.int_state.max_renderbuffer_size;
655 return true;
656 case GL_MAX_TEXTURE_IMAGE_UNITS:
657 *params = static_state_.int_state.max_texture_image_units;
658 return true;
659 case GL_MAX_TEXTURE_SIZE:
660 *params = static_state_.int_state.max_texture_size;
661 return true;
662 case GL_MAX_VARYING_VECTORS:
663 *params = static_state_.int_state.max_varying_vectors;
664 return true;
665 case GL_MAX_VERTEX_ATTRIBS:
666 *params = static_state_.int_state.max_vertex_attribs;
667 return true;
668 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
669 *params = static_state_.int_state.max_vertex_texture_image_units;
670 return true;
671 case GL_MAX_VERTEX_UNIFORM_VECTORS:
672 *params = static_state_.int_state.max_vertex_uniform_vectors;
673 return true;
674 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
675 *params = static_state_.int_state.num_compressed_texture_formats;
676 return true;
677 case GL_NUM_SHADER_BINARY_FORMATS:
678 *params = static_state_.int_state.num_shader_binary_formats;
679 return true;
680 case GL_ARRAY_BUFFER_BINDING:
681 if (share_group_->bind_generates_resource()) {
682 *params = bound_array_buffer_id_;
683 return true;
685 return false;
686 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
687 if (share_group_->bind_generates_resource()) {
688 *params =
689 vertex_array_object_manager_->bound_element_array_buffer();
690 return true;
692 return false;
693 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
694 *params = bound_pixel_pack_transfer_buffer_id_;
695 return true;
696 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
697 *params = bound_pixel_unpack_transfer_buffer_id_;
698 return true;
699 case GL_ACTIVE_TEXTURE:
700 *params = active_texture_unit_ + GL_TEXTURE0;
701 return true;
702 case GL_TEXTURE_BINDING_2D:
703 if (share_group_->bind_generates_resource()) {
704 *params = texture_units_[active_texture_unit_].bound_texture_2d;
705 return true;
707 return false;
708 case GL_TEXTURE_BINDING_CUBE_MAP:
709 if (share_group_->bind_generates_resource()) {
710 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
711 return true;
713 return false;
714 case GL_TEXTURE_BINDING_EXTERNAL_OES:
715 if (share_group_->bind_generates_resource()) {
716 *params =
717 texture_units_[active_texture_unit_].bound_texture_external_oes;
718 return true;
720 return false;
721 case GL_FRAMEBUFFER_BINDING:
722 if (share_group_->bind_generates_resource()) {
723 *params = bound_framebuffer_;
724 return true;
726 return false;
727 case GL_READ_FRAMEBUFFER_BINDING:
728 if (IsChromiumFramebufferMultisampleAvailable() &&
729 share_group_->bind_generates_resource()) {
730 *params = bound_read_framebuffer_;
731 return true;
733 return false;
734 case GL_RENDERBUFFER_BINDING:
735 if (share_group_->bind_generates_resource()) {
736 *params = bound_renderbuffer_;
737 return true;
739 return false;
740 default:
741 return false;
745 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
746 // TODO(gman): Make this handle pnames that return more than 1 value.
747 GLint value;
748 if (!GetHelper(pname, &value)) {
749 return false;
751 *params = static_cast<GLboolean>(value);
752 return true;
755 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
756 // TODO(gman): Make this handle pnames that return more than 1 value.
757 GLint value;
758 if (!GetHelper(pname, &value)) {
759 return false;
761 *params = static_cast<GLfloat>(value);
762 return true;
765 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
766 return GetHelper(pname, params);
769 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
770 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
771 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
772 Result* result = GetResultAs<Result*>();
773 if (!result) {
774 return 0;
776 *result = 0;
777 helper_->GetMaxValueInBufferCHROMIUM(
778 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
779 WaitForCmd();
780 return *result;
783 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
784 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
785 GPU_CLIENT_SINGLE_THREAD_CHECK();
786 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
787 << buffer_id << ", " << count << ", "
788 << GLES2Util::GetStringGetMaxIndexType(type)
789 << ", " << offset << ")");
790 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
791 buffer_id, count, type, offset);
792 GPU_CLIENT_LOG("returned " << result);
793 CheckGLError();
794 return result;
797 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
798 if (restore) {
799 RestoreArrayBuffer(restore);
800 // Restore the element array binding.
801 // We only need to restore it if it wasn't a client side array.
802 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
803 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
808 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
809 if (restore) {
810 // Restore the user's current binding.
811 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_);
815 void GLES2Implementation::DrawElements(
816 GLenum mode, GLsizei count, GLenum type, const void* indices) {
817 GPU_CLIENT_SINGLE_THREAD_CHECK();
818 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
819 << GLES2Util::GetStringDrawMode(mode) << ", "
820 << count << ", "
821 << GLES2Util::GetStringIndexType(type) << ", "
822 << static_cast<const void*>(indices) << ")");
823 if (count < 0) {
824 SetGLError(GL_INVALID_VALUE, "glDrawElements", "count less than 0.");
825 return;
827 if (count == 0) {
828 return;
830 GLuint offset = 0;
831 bool simulated = false;
832 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
833 "glDrawElements", this, helper_, count, type, 0, indices,
834 &offset, &simulated)) {
835 return;
837 helper_->DrawElements(mode, count, type, offset);
838 RestoreElementAndArrayBuffers(simulated);
839 CheckGLError();
842 void GLES2Implementation::Flush() {
843 GPU_CLIENT_SINGLE_THREAD_CHECK();
844 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
845 // Insert the cmd to call glFlush
846 helper_->Flush();
847 // Flush our command buffer
848 // (tell the service to execute up to the flush cmd.)
849 helper_->CommandBufferHelper::Flush();
850 if (!surface_visible_ && free_everything_when_invisible_)
851 FreeEverything();
854 void GLES2Implementation::ShallowFlushCHROMIUM() {
855 GPU_CLIENT_SINGLE_THREAD_CHECK();
856 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
857 // Flush our command buffer
858 // (tell the service to execute up to the flush cmd.)
859 helper_->CommandBufferHelper::Flush();
860 // TODO(piman): Add the FreeEverything() logic here.
863 void GLES2Implementation::Finish() {
864 GPU_CLIENT_SINGLE_THREAD_CHECK();
865 FinishHelper();
866 if (!surface_visible_ && free_everything_when_invisible_)
867 FreeEverything();
870 void GLES2Implementation::ShallowFinishCHROMIUM() {
871 GPU_CLIENT_SINGLE_THREAD_CHECK();
872 // Flush our command buffer (tell the service to execute up to the flush cmd
873 // and don't return until it completes).
874 helper_->CommandBufferHelper::Finish();
877 bool GLES2Implementation::MustBeContextLost() {
878 bool context_lost = helper_->IsContextLost();
879 if (!context_lost) {
880 WaitForCmd();
881 context_lost = helper_->IsContextLost();
883 CHECK(context_lost);
884 return context_lost;
887 void GLES2Implementation::FinishHelper() {
888 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
889 TRACE_EVENT0("gpu", "GLES2::Finish");
890 // Insert the cmd to call glFinish
891 helper_->Finish();
892 // Finish our command buffer
893 // (tell the service to execute up to the Finish cmd and wait for it to
894 // execute.)
895 helper_->CommandBufferHelper::Finish();
898 void GLES2Implementation::SwapBuffers() {
899 GPU_CLIENT_SINGLE_THREAD_CHECK();
900 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
901 // TODO(piman): Strictly speaking we'd want to insert the token after the
902 // swap, but the state update with the updated token might not have happened
903 // by the time the SwapBuffer callback gets called, forcing us to synchronize
904 // with the GPU process more than needed. So instead, make it happen before.
905 // All it means is that we could be slightly looser on the kMaxSwapBuffers
906 // semantics if the client doesn't use the callback mechanism, and by chance
907 // the scheduler yields between the InsertToken and the SwapBuffers.
908 swap_buffers_tokens_.push(helper_->InsertToken());
909 helper_->SwapBuffers();
910 helper_->CommandBufferHelper::Flush();
911 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
912 // compensate for TODO above.
913 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
914 helper_->WaitForToken(swap_buffers_tokens_.front());
915 swap_buffers_tokens_.pop();
919 void GLES2Implementation::GenSharedIdsCHROMIUM(
920 GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) {
921 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenSharedIdsCHROMIUM("
922 << namespace_id << ", " << id_offset << ", " << n << ", " <<
923 static_cast<void*>(ids) << ")");
924 TRACE_EVENT0("gpu", "GLES2::GenSharedIdsCHROMIUM");
925 GLsizei num = n;
926 GLuint* dst = ids;
927 while (num) {
928 ScopedTransferBufferArray<GLint> id_buffer(num, helper_, transfer_buffer_);
929 if (!id_buffer.valid()) {
930 return;
932 helper_->GenSharedIdsCHROMIUM(
933 namespace_id, id_offset, id_buffer.num_elements(),
934 id_buffer.shm_id(), id_buffer.offset());
935 WaitForCmd();
936 memcpy(dst, id_buffer.address(), sizeof(*dst) * id_buffer.num_elements());
937 num -= id_buffer.num_elements();
938 dst += id_buffer.num_elements();
940 GPU_CLIENT_LOG_CODE_BLOCK({
941 for (GLsizei i = 0; i < n; ++i) {
942 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
947 void GLES2Implementation::DeleteSharedIdsCHROMIUM(
948 GLuint namespace_id, GLsizei n, const GLuint* ids) {
949 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteSharedIdsCHROMIUM("
950 << namespace_id << ", " << n << ", "
951 << static_cast<const void*>(ids) << ")");
952 GPU_CLIENT_LOG_CODE_BLOCK({
953 for (GLsizei i = 0; i < n; ++i) {
954 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
957 TRACE_EVENT0("gpu", "GLES2::DeleteSharedIdsCHROMIUM");
958 while (n) {
959 ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
960 if (!id_buffer.valid()) {
961 return;
963 memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
964 helper_->DeleteSharedIdsCHROMIUM(
965 namespace_id, id_buffer.num_elements(),
966 id_buffer.shm_id(), id_buffer.offset());
967 WaitForCmd();
968 n -= id_buffer.num_elements();
969 ids += id_buffer.num_elements();
973 void GLES2Implementation::RegisterSharedIdsCHROMIUM(
974 GLuint namespace_id, GLsizei n, const GLuint* ids) {
975 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRegisterSharedIdsCHROMIUM("
976 << namespace_id << ", " << n << ", "
977 << static_cast<const void*>(ids) << ")");
978 GPU_CLIENT_LOG_CODE_BLOCK({
979 for (GLsizei i = 0; i < n; ++i) {
980 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
983 TRACE_EVENT0("gpu", "GLES2::RegisterSharedIdsCHROMIUM");
984 while (n) {
985 ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
986 if (!id_buffer.valid()) {
987 return;
989 memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
990 helper_->RegisterSharedIdsCHROMIUM(
991 namespace_id, id_buffer.num_elements(),
992 id_buffer.shm_id(), id_buffer.offset());
993 WaitForCmd();
994 n -= id_buffer.num_elements();
995 ids += id_buffer.num_elements();
999 void GLES2Implementation::BindAttribLocation(
1000 GLuint program, GLuint index, const char* name) {
1001 GPU_CLIENT_SINGLE_THREAD_CHECK();
1002 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
1003 << program << ", " << index << ", " << name << ")");
1004 SetBucketAsString(kResultBucketId, name);
1005 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
1006 helper_->SetBucketSize(kResultBucketId, 0);
1007 CheckGLError();
1010 void GLES2Implementation::BindUniformLocationCHROMIUM(
1011 GLuint program, GLint location, const char* name) {
1012 GPU_CLIENT_SINGLE_THREAD_CHECK();
1013 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1014 << program << ", " << location << ", " << name << ")");
1015 SetBucketAsString(kResultBucketId, name);
1016 helper_->BindUniformLocationCHROMIUMBucket(
1017 program, location, kResultBucketId);
1018 helper_->SetBucketSize(kResultBucketId, 0);
1019 CheckGLError();
1022 void GLES2Implementation::GetVertexAttribPointerv(
1023 GLuint index, GLenum pname, void** ptr) {
1024 GPU_CLIENT_SINGLE_THREAD_CHECK();
1025 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1026 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1027 << static_cast<void*>(ptr) << ")");
1028 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
1029 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1030 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1031 typedef cmds::GetVertexAttribPointerv::Result Result;
1032 Result* result = GetResultAs<Result*>();
1033 if (!result) {
1034 return;
1036 result->SetNumResults(0);
1037 helper_->GetVertexAttribPointerv(
1038 index, pname, GetResultShmId(), GetResultShmOffset());
1039 WaitForCmd();
1040 result->CopyResult(ptr);
1041 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1043 GPU_CLIENT_LOG_CODE_BLOCK({
1044 for (int32 i = 0; i < num_results; ++i) {
1045 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
1048 CheckGLError();
1051 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1052 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1053 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
1054 SetGLError(
1055 GL_INVALID_VALUE,
1056 "glDeleteProgram", "id not created by this context.");
1057 return false;
1059 if (program == current_program_) {
1060 current_program_ = 0;
1062 return true;
1065 void GLES2Implementation::DeleteProgramStub(
1066 GLsizei n, const GLuint* programs) {
1067 DCHECK_EQ(1, n);
1068 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1069 helper_->DeleteProgram(programs[0]);
1072 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1073 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1074 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1075 SetGLError(
1076 GL_INVALID_VALUE,
1077 "glDeleteShader", "id not created by this context.");
1078 return false;
1080 return true;
1083 void GLES2Implementation::DeleteShaderStub(
1084 GLsizei n, const GLuint* shaders) {
1085 DCHECK_EQ(1, n);
1086 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1087 helper_->DeleteShader(shaders[0]);
1091 GLint GLES2Implementation::GetAttribLocationHelper(
1092 GLuint program, const char* name) {
1093 typedef cmds::GetAttribLocationBucket::Result Result;
1094 Result* result = GetResultAs<Result*>();
1095 if (!result) {
1096 return -1;
1098 *result = -1;
1099 SetBucketAsCString(kResultBucketId, name);
1100 helper_->GetAttribLocationBucket(
1101 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1102 WaitForCmd();
1103 helper_->SetBucketSize(kResultBucketId, 0);
1104 return *result;
1107 GLint GLES2Implementation::GetAttribLocation(
1108 GLuint program, const char* name) {
1109 GPU_CLIENT_SINGLE_THREAD_CHECK();
1110 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1111 << ", " << name << ")");
1112 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1113 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1114 this, program, name);
1115 GPU_CLIENT_LOG("returned " << loc);
1116 CheckGLError();
1117 return loc;
1120 GLint GLES2Implementation::GetUniformLocationHelper(
1121 GLuint program, const char* name) {
1122 typedef cmds::GetUniformLocationBucket::Result Result;
1123 Result* result = GetResultAs<Result*>();
1124 if (!result) {
1125 return -1;
1127 *result = -1;
1128 SetBucketAsCString(kResultBucketId, name);
1129 helper_->GetUniformLocationBucket(program, kResultBucketId,
1130 GetResultShmId(), GetResultShmOffset());
1131 WaitForCmd();
1132 helper_->SetBucketSize(kResultBucketId, 0);
1133 return *result;
1136 GLint GLES2Implementation::GetUniformLocation(
1137 GLuint program, const char* name) {
1138 GPU_CLIENT_SINGLE_THREAD_CHECK();
1139 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1140 << ", " << name << ")");
1141 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1142 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1143 this, program, name);
1144 GPU_CLIENT_LOG("returned " << loc);
1145 CheckGLError();
1146 return loc;
1149 void GLES2Implementation::UseProgram(GLuint program) {
1150 GPU_CLIENT_SINGLE_THREAD_CHECK();
1151 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUseProgram(" << program << ")");
1152 if (current_program_ != program) {
1153 current_program_ = program;
1154 helper_->UseProgram(program);
1156 CheckGLError();
1159 bool GLES2Implementation::GetProgramivHelper(
1160 GLuint program, GLenum pname, GLint* params) {
1161 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1162 this, program, pname, params);
1163 GPU_CLIENT_LOG_CODE_BLOCK({
1164 if (got_value) {
1165 GPU_CLIENT_LOG(" 0: " << *params);
1168 return got_value;
1171 void GLES2Implementation::LinkProgram(GLuint program) {
1172 GPU_CLIENT_SINGLE_THREAD_CHECK();
1173 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1174 helper_->LinkProgram(program);
1175 share_group_->program_info_manager()->CreateInfo(program);
1176 CheckGLError();
1179 void GLES2Implementation::ShaderBinary(
1180 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1181 GLsizei length) {
1182 GPU_CLIENT_SINGLE_THREAD_CHECK();
1183 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1184 << static_cast<const void*>(shaders) << ", "
1185 << GLES2Util::GetStringEnum(binaryformat) << ", "
1186 << static_cast<const void*>(binary) << ", "
1187 << length << ")");
1188 if (n < 0) {
1189 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1190 return;
1192 if (length < 0) {
1193 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1194 return;
1196 // TODO(gman): ShaderBinary should use buckets.
1197 unsigned int shader_id_size = n * sizeof(*shaders);
1198 ScopedTransferBufferArray<GLint> buffer(
1199 shader_id_size + length, helper_, transfer_buffer_);
1200 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1201 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1202 return;
1204 void* shader_ids = buffer.elements();
1205 void* shader_data = buffer.elements() + shader_id_size;
1206 memcpy(shader_ids, shaders, shader_id_size);
1207 memcpy(shader_data, binary, length);
1208 helper_->ShaderBinary(
1210 buffer.shm_id(),
1211 buffer.offset(),
1212 binaryformat,
1213 buffer.shm_id(),
1214 buffer.offset() + shader_id_size,
1215 length);
1216 CheckGLError();
1219 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1220 GPU_CLIENT_SINGLE_THREAD_CHECK();
1221 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1222 << GLES2Util::GetStringPixelStore(pname) << ", "
1223 << param << ")");
1224 switch (pname) {
1225 case GL_PACK_ALIGNMENT:
1226 pack_alignment_ = param;
1227 break;
1228 case GL_UNPACK_ALIGNMENT:
1229 unpack_alignment_ = param;
1230 break;
1231 case GL_UNPACK_ROW_LENGTH_EXT:
1232 unpack_row_length_ = param;
1233 return;
1234 case GL_UNPACK_SKIP_ROWS_EXT:
1235 unpack_skip_rows_ = param;
1236 return;
1237 case GL_UNPACK_SKIP_PIXELS_EXT:
1238 unpack_skip_pixels_ = param;
1239 return;
1240 case GL_UNPACK_FLIP_Y_CHROMIUM:
1241 unpack_flip_y_ = (param != 0);
1242 break;
1243 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1244 pack_reverse_row_order_ =
1245 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1246 break;
1247 default:
1248 break;
1250 helper_->PixelStorei(pname, param);
1251 CheckGLError();
1255 void GLES2Implementation::VertexAttribPointer(
1256 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1257 const void* ptr) {
1258 GPU_CLIENT_SINGLE_THREAD_CHECK();
1259 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1260 << index << ", "
1261 << size << ", "
1262 << GLES2Util::GetStringVertexAttribType(type) << ", "
1263 << GLES2Util::GetStringBool(normalized) << ", "
1264 << stride << ", "
1265 << static_cast<const void*>(ptr) << ")");
1266 // Record the info on the client side.
1267 if (!vertex_array_object_manager_->SetAttribPointer(
1268 bound_array_buffer_id_, index, size, type, normalized, stride, ptr)) {
1269 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1270 "client side arrays are not allowed in vertex array objects.");
1271 return;
1273 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1274 if (bound_array_buffer_id_ != 0) {
1275 // Only report NON client side buffers to the service.
1276 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1277 ToGLuint(ptr));
1279 #else // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1280 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1281 ToGLuint(ptr));
1282 #endif // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1283 CheckGLError();
1286 void GLES2Implementation::VertexAttribDivisorANGLE(
1287 GLuint index, GLuint divisor) {
1288 GPU_CLIENT_SINGLE_THREAD_CHECK();
1289 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1290 << index << ", "
1291 << divisor << ") ");
1292 // Record the info on the client side.
1293 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1294 helper_->VertexAttribDivisorANGLE(index, divisor);
1295 CheckGLError();
1298 void GLES2Implementation::ShaderSource(
1299 GLuint shader, GLsizei count, const GLchar* const* source, const GLint* length) {
1300 GPU_CLIENT_SINGLE_THREAD_CHECK();
1301 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderSource("
1302 << shader << ", " << count << ", "
1303 << static_cast<const void*>(source) << ", "
1304 << static_cast<const void*>(length) << ")");
1305 GPU_CLIENT_LOG_CODE_BLOCK({
1306 for (GLsizei ii = 0; ii < count; ++ii) {
1307 if (source[ii]) {
1308 if (length && length[ii] >= 0) {
1309 std::string str(source[ii], length[ii]);
1310 GPU_CLIENT_LOG(" " << ii << ": ---\n" << str << "\n---");
1311 } else {
1312 GPU_CLIENT_LOG(" " << ii << ": ---\n" << source[ii] << "\n---");
1314 } else {
1315 GPU_CLIENT_LOG(" " << ii << ": NULL");
1319 if (count < 0) {
1320 SetGLError(GL_INVALID_VALUE, "glShaderSource", "count < 0");
1321 return;
1323 if (shader == 0) {
1324 SetGLError(GL_INVALID_VALUE, "glShaderSource", "shader == 0");
1325 return;
1328 // Compute the total size.
1329 uint32 total_size = 1;
1330 for (GLsizei ii = 0; ii < count; ++ii) {
1331 if (source[ii]) {
1332 total_size += (length && length[ii] >= 0) ?
1333 static_cast<size_t>(length[ii]) : strlen(source[ii]);
1337 // Concatenate all the strings in to a bucket on the service.
1338 helper_->SetBucketSize(kResultBucketId, total_size);
1339 uint32 offset = 0;
1340 for (GLsizei ii = 0; ii <= count; ++ii) {
1341 const char* src = ii < count ? source[ii] : "";
1342 if (src) {
1343 uint32 size = ii < count ?
1344 (length ? static_cast<size_t>(length[ii]) : strlen(src)) : 1;
1345 while (size) {
1346 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1347 if (!buffer.valid()) {
1348 return;
1350 memcpy(buffer.address(), src, buffer.size());
1351 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
1352 buffer.shm_id(), buffer.offset());
1353 offset += buffer.size();
1354 src += buffer.size();
1355 size -= buffer.size();
1360 DCHECK_EQ(total_size, offset);
1362 helper_->ShaderSourceBucket(shader, kResultBucketId);
1363 helper_->SetBucketSize(kResultBucketId, 0);
1364 CheckGLError();
1367 void GLES2Implementation::BufferDataHelper(
1368 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1369 if (size < 0) {
1370 SetGLError(GL_INVALID_VALUE, "glBufferData", "size < 0");
1371 return;
1374 GLuint buffer_id;
1375 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1376 if (!buffer_id) {
1377 return;
1380 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1381 if (buffer) {
1382 // Free buffer memory, pending the passage of a token.
1383 buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
1385 // Remove old buffer.
1386 buffer_tracker_->RemoveBuffer(buffer_id);
1389 // Create new buffer.
1390 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1391 DCHECK(buffer);
1392 if (buffer->address() && data)
1393 memcpy(buffer->address(), data, size);
1394 return;
1397 if (size == 0) {
1398 return;
1401 // If there is no data just send BufferData
1402 if (!data) {
1403 helper_->BufferData(target, size, 0, 0, usage);
1404 return;
1407 // See if we can send all at once.
1408 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1409 if (!buffer.valid()) {
1410 return;
1413 if (buffer.size() >= static_cast<unsigned int>(size)) {
1414 memcpy(buffer.address(), data, size);
1415 helper_->BufferData(
1416 target,
1417 size,
1418 buffer.shm_id(),
1419 buffer.offset(),
1420 usage);
1421 return;
1424 // Make the buffer with BufferData then send via BufferSubData
1425 helper_->BufferData(target, size, 0, 0, usage);
1426 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1427 CheckGLError();
1430 void GLES2Implementation::BufferData(
1431 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1432 GPU_CLIENT_SINGLE_THREAD_CHECK();
1433 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1434 << GLES2Util::GetStringBufferTarget(target) << ", "
1435 << size << ", "
1436 << static_cast<const void*>(data) << ", "
1437 << GLES2Util::GetStringBufferUsage(usage) << ")");
1438 BufferDataHelper(target, size, data, usage);
1439 CheckGLError();
1442 void GLES2Implementation::BufferSubDataHelper(
1443 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1444 if (size == 0) {
1445 return;
1448 if (size < 0) {
1449 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "size < 0");
1450 return;
1453 GLuint buffer_id;
1454 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1455 if (!buffer_id) {
1456 return;
1458 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1459 if (!buffer) {
1460 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1461 return;
1464 int32 end = 0;
1465 int32 buffer_size = buffer->size();
1466 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1467 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1468 return;
1471 if (buffer->address() && data)
1472 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1473 return;
1476 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1477 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1480 void GLES2Implementation::BufferSubDataHelperImpl(
1481 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1482 ScopedTransferBufferPtr* buffer) {
1483 DCHECK(buffer);
1484 DCHECK_GT(size, 0);
1486 const int8* source = static_cast<const int8*>(data);
1487 while (size) {
1488 if (!buffer->valid() || buffer->size() == 0) {
1489 buffer->Reset(size);
1490 if (!buffer->valid()) {
1491 return;
1494 memcpy(buffer->address(), source, buffer->size());
1495 helper_->BufferSubData(
1496 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1497 offset += buffer->size();
1498 source += buffer->size();
1499 size -= buffer->size();
1500 buffer->Release();
1504 void GLES2Implementation::BufferSubData(
1505 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1506 GPU_CLIENT_SINGLE_THREAD_CHECK();
1507 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1508 << GLES2Util::GetStringBufferTarget(target) << ", "
1509 << offset << ", " << size << ", "
1510 << static_cast<const void*>(data) << ")");
1511 BufferSubDataHelper(target, offset, size, data);
1512 CheckGLError();
1515 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1516 GLenum target,
1517 const char* function_name,
1518 GLuint* buffer_id) {
1519 *buffer_id = 0;
1521 switch (target) {
1522 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1523 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1524 break;
1525 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1526 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1527 break;
1528 default:
1529 // Unknown target
1530 return false;
1532 if (!*buffer_id) {
1533 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1535 return true;
1538 BufferTracker::Buffer*
1539 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1540 GLuint buffer_id,
1541 const char* function_name,
1542 GLuint offset, GLsizei size)
1544 DCHECK(buffer_id);
1545 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1546 if (!buffer) {
1547 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1548 return NULL;
1550 if (buffer->mapped()) {
1551 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1552 return NULL;
1554 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1555 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1556 return NULL;
1558 return buffer;
1561 void GLES2Implementation::CompressedTexImage2D(
1562 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1563 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1564 GPU_CLIENT_SINGLE_THREAD_CHECK();
1565 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1566 << GLES2Util::GetStringTextureTarget(target) << ", "
1567 << level << ", "
1568 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1569 << width << ", " << height << ", " << border << ", "
1570 << image_size << ", "
1571 << static_cast<const void*>(data) << ")");
1572 if (width < 0 || height < 0 || level < 0) {
1573 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1574 return;
1576 if (height == 0 || width == 0) {
1577 return;
1579 // If there's a pixel unpack buffer bound use it when issuing
1580 // CompressedTexImage2D.
1581 if (bound_pixel_unpack_transfer_buffer_id_) {
1582 GLuint offset = ToGLuint(data);
1583 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1584 bound_pixel_unpack_transfer_buffer_id_,
1585 "glCompressedTexImage2D", offset, image_size);
1586 if (buffer && buffer->shm_id() != -1) {
1587 helper_->CompressedTexImage2D(
1588 target, level, internalformat, width, height, border, image_size,
1589 buffer->shm_id(), buffer->shm_offset() + offset);
1590 buffer->set_transfer_ready_token(helper_->InsertToken());
1592 return;
1594 SetBucketContents(kResultBucketId, data, image_size);
1595 helper_->CompressedTexImage2DBucket(
1596 target, level, internalformat, width, height, border, kResultBucketId);
1597 // Free the bucket. This is not required but it does free up the memory.
1598 // and we don't have to wait for the result so from the client's perspective
1599 // it's cheap.
1600 helper_->SetBucketSize(kResultBucketId, 0);
1601 CheckGLError();
1604 void GLES2Implementation::CompressedTexSubImage2D(
1605 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1606 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1607 GPU_CLIENT_SINGLE_THREAD_CHECK();
1608 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1609 << GLES2Util::GetStringTextureTarget(target) << ", "
1610 << level << ", "
1611 << xoffset << ", " << yoffset << ", "
1612 << width << ", " << height << ", "
1613 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1614 << image_size << ", "
1615 << static_cast<const void*>(data) << ")");
1616 if (width < 0 || height < 0 || level < 0) {
1617 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1618 return;
1620 // If there's a pixel unpack buffer bound use it when issuing
1621 // CompressedTexSubImage2D.
1622 if (bound_pixel_unpack_transfer_buffer_id_) {
1623 GLuint offset = ToGLuint(data);
1624 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1625 bound_pixel_unpack_transfer_buffer_id_,
1626 "glCompressedTexSubImage2D", offset, image_size);
1627 if (buffer && buffer->shm_id() != -1) {
1628 helper_->CompressedTexSubImage2D(
1629 target, level, xoffset, yoffset, width, height, format, image_size,
1630 buffer->shm_id(), buffer->shm_offset() + offset);
1631 buffer->set_transfer_ready_token(helper_->InsertToken());
1632 CheckGLError();
1634 return;
1636 SetBucketContents(kResultBucketId, data, image_size);
1637 helper_->CompressedTexSubImage2DBucket(
1638 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1639 // Free the bucket. This is not required but it does free up the memory.
1640 // and we don't have to wait for the result so from the client's perspective
1641 // it's cheap.
1642 helper_->SetBucketSize(kResultBucketId, 0);
1643 CheckGLError();
1646 namespace {
1648 void CopyRectToBuffer(
1649 const void* pixels,
1650 uint32 height,
1651 uint32 unpadded_row_size,
1652 uint32 pixels_padded_row_size,
1653 bool flip_y,
1654 void* buffer,
1655 uint32 buffer_padded_row_size) {
1656 const int8* source = static_cast<const int8*>(pixels);
1657 int8* dest = static_cast<int8*>(buffer);
1658 if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
1659 if (flip_y) {
1660 dest += buffer_padded_row_size * (height - 1);
1662 // the last row is copied unpadded at the end
1663 for (; height > 1; --height) {
1664 memcpy(dest, source, buffer_padded_row_size);
1665 if (flip_y) {
1666 dest -= buffer_padded_row_size;
1667 } else {
1668 dest += buffer_padded_row_size;
1670 source += pixels_padded_row_size;
1672 memcpy(dest, source, unpadded_row_size);
1673 } else {
1674 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
1675 memcpy(dest, source, size);
1679 } // anonymous namespace
1681 void GLES2Implementation::TexImage2D(
1682 GLenum target, GLint level, GLint internalformat, GLsizei width,
1683 GLsizei height, GLint border, GLenum format, GLenum type,
1684 const void* pixels) {
1685 GPU_CLIENT_SINGLE_THREAD_CHECK();
1686 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1687 << GLES2Util::GetStringTextureTarget(target) << ", "
1688 << level << ", "
1689 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1690 << width << ", " << height << ", " << border << ", "
1691 << GLES2Util::GetStringTextureFormat(format) << ", "
1692 << GLES2Util::GetStringPixelType(type) << ", "
1693 << static_cast<const void*>(pixels) << ")");
1694 if (level < 0 || height < 0 || width < 0) {
1695 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
1696 return;
1698 uint32 size;
1699 uint32 unpadded_row_size;
1700 uint32 padded_row_size;
1701 if (!GLES2Util::ComputeImageDataSizes(
1702 width, height, format, type, unpack_alignment_, &size,
1703 &unpadded_row_size, &padded_row_size)) {
1704 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
1705 return;
1708 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1709 if (bound_pixel_unpack_transfer_buffer_id_) {
1710 GLuint offset = ToGLuint(pixels);
1711 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1712 bound_pixel_unpack_transfer_buffer_id_,
1713 "glTexImage2D", offset, size);
1714 if (buffer && buffer->shm_id() != -1) {
1715 helper_->TexImage2D(
1716 target, level, internalformat, width, height, border, format, type,
1717 buffer->shm_id(), buffer->shm_offset() + offset);
1718 buffer->set_transfer_ready_token(helper_->InsertToken());
1719 CheckGLError();
1721 return;
1724 // If there's no data just issue TexImage2D
1725 if (!pixels) {
1726 helper_->TexImage2D(
1727 target, level, internalformat, width, height, border, format, type,
1728 0, 0);
1729 CheckGLError();
1730 return;
1733 // compute the advance bytes per row for the src pixels
1734 uint32 src_padded_row_size;
1735 if (unpack_row_length_ > 0) {
1736 if (!GLES2Util::ComputeImagePaddedRowSize(
1737 unpack_row_length_, format, type, unpack_alignment_,
1738 &src_padded_row_size)) {
1739 SetGLError(
1740 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1741 return;
1743 } else {
1744 src_padded_row_size = padded_row_size;
1747 // advance pixels pointer past the skip rows and skip pixels
1748 pixels = reinterpret_cast<const int8*>(pixels) +
1749 unpack_skip_rows_ * src_padded_row_size;
1750 if (unpack_skip_pixels_) {
1751 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1752 pixels = reinterpret_cast<const int8*>(pixels) +
1753 unpack_skip_pixels_ * group_size;
1756 // Check if we can send it all at once.
1757 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1758 if (!buffer.valid()) {
1759 return;
1762 if (buffer.size() >= size) {
1763 CopyRectToBuffer(
1764 pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
1765 buffer.address(), padded_row_size);
1766 helper_->TexImage2D(
1767 target, level, internalformat, width, height, border, format, type,
1768 buffer.shm_id(), buffer.offset());
1769 CheckGLError();
1770 return;
1773 // No, so send it using TexSubImage2D.
1774 helper_->TexImage2D(
1775 target, level, internalformat, width, height, border, format, type,
1776 0, 0);
1777 TexSubImage2DImpl(
1778 target, level, 0, 0, width, height, format, type, unpadded_row_size,
1779 pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
1780 CheckGLError();
1783 void GLES2Implementation::TexSubImage2D(
1784 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1785 GLsizei height, GLenum format, GLenum type, const void* pixels) {
1786 GPU_CLIENT_SINGLE_THREAD_CHECK();
1787 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1788 << GLES2Util::GetStringTextureTarget(target) << ", "
1789 << level << ", "
1790 << xoffset << ", " << yoffset << ", "
1791 << width << ", " << height << ", "
1792 << GLES2Util::GetStringTextureFormat(format) << ", "
1793 << GLES2Util::GetStringPixelType(type) << ", "
1794 << static_cast<const void*>(pixels) << ")");
1796 if (level < 0 || height < 0 || width < 0) {
1797 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
1798 return;
1800 if (height == 0 || width == 0) {
1801 return;
1804 uint32 temp_size;
1805 uint32 unpadded_row_size;
1806 uint32 padded_row_size;
1807 if (!GLES2Util::ComputeImageDataSizes(
1808 width, height, format, type, unpack_alignment_, &temp_size,
1809 &unpadded_row_size, &padded_row_size)) {
1810 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
1811 return;
1814 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1815 if (bound_pixel_unpack_transfer_buffer_id_) {
1816 GLuint offset = ToGLuint(pixels);
1817 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1818 bound_pixel_unpack_transfer_buffer_id_,
1819 "glTexSubImage2D", offset, temp_size);
1820 if (buffer && buffer->shm_id() != -1) {
1821 helper_->TexSubImage2D(
1822 target, level, xoffset, yoffset, width, height, format, type,
1823 buffer->shm_id(), buffer->shm_offset() + offset, false);
1824 buffer->set_transfer_ready_token(helper_->InsertToken());
1825 CheckGLError();
1827 return;
1830 // compute the advance bytes per row for the src pixels
1831 uint32 src_padded_row_size;
1832 if (unpack_row_length_ > 0) {
1833 if (!GLES2Util::ComputeImagePaddedRowSize(
1834 unpack_row_length_, format, type, unpack_alignment_,
1835 &src_padded_row_size)) {
1836 SetGLError(
1837 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1838 return;
1840 } else {
1841 src_padded_row_size = padded_row_size;
1844 // advance pixels pointer past the skip rows and skip pixels
1845 pixels = reinterpret_cast<const int8*>(pixels) +
1846 unpack_skip_rows_ * src_padded_row_size;
1847 if (unpack_skip_pixels_) {
1848 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1849 pixels = reinterpret_cast<const int8*>(pixels) +
1850 unpack_skip_pixels_ * group_size;
1853 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
1854 TexSubImage2DImpl(
1855 target, level, xoffset, yoffset, width, height, format, type,
1856 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
1857 padded_row_size);
1858 CheckGLError();
1861 static GLint ComputeNumRowsThatFitInBuffer(
1862 GLsizeiptr padded_row_size, GLsizeiptr unpadded_row_size,
1863 unsigned int size) {
1864 DCHECK_GE(unpadded_row_size, 0);
1865 if (padded_row_size == 0) {
1866 return 1;
1868 GLint num_rows = size / padded_row_size;
1869 return num_rows + (size - num_rows * padded_row_size) / unpadded_row_size;
1872 void GLES2Implementation::TexSubImage2DImpl(
1873 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1874 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
1875 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
1876 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
1877 DCHECK(buffer);
1878 DCHECK_GE(level, 0);
1879 DCHECK_GT(height, 0);
1880 DCHECK_GT(width, 0);
1882 const int8* source = reinterpret_cast<const int8*>(pixels);
1883 GLint original_yoffset = yoffset;
1884 // Transfer by rows.
1885 while (height) {
1886 unsigned int desired_size =
1887 buffer_padded_row_size * (height - 1) + unpadded_row_size;
1888 if (!buffer->valid() || buffer->size() == 0) {
1889 buffer->Reset(desired_size);
1890 if (!buffer->valid()) {
1891 return;
1895 GLint num_rows = ComputeNumRowsThatFitInBuffer(
1896 buffer_padded_row_size, unpadded_row_size, buffer->size());
1897 num_rows = std::min(num_rows, height);
1898 CopyRectToBuffer(
1899 source, num_rows, unpadded_row_size, pixels_padded_row_size,
1900 unpack_flip_y_, buffer->address(), buffer_padded_row_size);
1901 GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
1902 helper_->TexSubImage2D(
1903 target, level, xoffset, y, width, num_rows, format, type,
1904 buffer->shm_id(), buffer->offset(), internal);
1905 buffer->Release();
1906 yoffset += num_rows;
1907 source += num_rows * pixels_padded_row_size;
1908 height -= num_rows;
1912 bool GLES2Implementation::GetActiveAttribHelper(
1913 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1914 GLenum* type, char* name) {
1915 // Clear the bucket so if the command fails nothing will be in it.
1916 helper_->SetBucketSize(kResultBucketId, 0);
1917 typedef cmds::GetActiveAttrib::Result Result;
1918 Result* result = GetResultAs<Result*>();
1919 if (!result) {
1920 return false;
1922 // Set as failed so if the command fails we'll recover.
1923 result->success = false;
1924 helper_->GetActiveAttrib(program, index, kResultBucketId,
1925 GetResultShmId(), GetResultShmOffset());
1926 WaitForCmd();
1927 if (result->success) {
1928 if (size) {
1929 *size = result->size;
1931 if (type) {
1932 *type = result->type;
1934 if (length || name) {
1935 std::vector<int8> str;
1936 GetBucketContents(kResultBucketId, &str);
1937 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
1938 std::max(static_cast<size_t>(0),
1939 str.size() - 1));
1940 if (length) {
1941 *length = max_size;
1943 if (name && bufsize > 0) {
1944 memcpy(name, &str[0], max_size);
1945 name[max_size] = '\0';
1949 return result->success != 0;
1952 void GLES2Implementation::GetActiveAttrib(
1953 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1954 GLenum* type, char* name) {
1955 GPU_CLIENT_SINGLE_THREAD_CHECK();
1956 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
1957 << program << ", " << index << ", " << bufsize << ", "
1958 << static_cast<const void*>(length) << ", "
1959 << static_cast<const void*>(size) << ", "
1960 << static_cast<const void*>(type) << ", "
1961 << static_cast<const void*>(name) << ", ");
1962 if (bufsize < 0) {
1963 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
1964 return;
1966 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
1967 bool success = share_group_->program_info_manager()->GetActiveAttrib(
1968 this, program, index, bufsize, length, size, type, name);
1969 if (success) {
1970 if (size) {
1971 GPU_CLIENT_LOG(" size: " << *size);
1973 if (type) {
1974 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
1976 if (name) {
1977 GPU_CLIENT_LOG(" name: " << name);
1980 CheckGLError();
1983 bool GLES2Implementation::GetActiveUniformHelper(
1984 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1985 GLenum* type, char* name) {
1986 // Clear the bucket so if the command fails nothing will be in it.
1987 helper_->SetBucketSize(kResultBucketId, 0);
1988 typedef cmds::GetActiveUniform::Result Result;
1989 Result* result = GetResultAs<Result*>();
1990 if (!result) {
1991 return false;
1993 // Set as failed so if the command fails we'll recover.
1994 result->success = false;
1995 helper_->GetActiveUniform(program, index, kResultBucketId,
1996 GetResultShmId(), GetResultShmOffset());
1997 WaitForCmd();
1998 if (result->success) {
1999 if (size) {
2000 *size = result->size;
2002 if (type) {
2003 *type = result->type;
2005 if (length || name) {
2006 std::vector<int8> str;
2007 GetBucketContents(kResultBucketId, &str);
2008 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
2009 std::max(static_cast<size_t>(0),
2010 str.size() - 1));
2011 if (length) {
2012 *length = max_size;
2014 if (name && bufsize > 0) {
2015 memcpy(name, &str[0], max_size);
2016 name[max_size] = '\0';
2020 return result->success != 0;
2023 void GLES2Implementation::GetActiveUniform(
2024 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2025 GLenum* type, char* name) {
2026 GPU_CLIENT_SINGLE_THREAD_CHECK();
2027 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2028 << program << ", " << index << ", " << bufsize << ", "
2029 << static_cast<const void*>(length) << ", "
2030 << static_cast<const void*>(size) << ", "
2031 << static_cast<const void*>(type) << ", "
2032 << static_cast<const void*>(name) << ", ");
2033 if (bufsize < 0) {
2034 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2035 return;
2037 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2038 bool success = share_group_->program_info_manager()->GetActiveUniform(
2039 this, program, index, bufsize, length, size, type, name);
2040 if (success) {
2041 if (size) {
2042 GPU_CLIENT_LOG(" size: " << *size);
2044 if (type) {
2045 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2047 if (name) {
2048 GPU_CLIENT_LOG(" name: " << name);
2051 CheckGLError();
2054 void GLES2Implementation::GetAttachedShaders(
2055 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
2056 GPU_CLIENT_SINGLE_THREAD_CHECK();
2057 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2058 << program << ", " << maxcount << ", "
2059 << static_cast<const void*>(count) << ", "
2060 << static_cast<const void*>(shaders) << ", ");
2061 if (maxcount < 0) {
2062 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
2063 return;
2065 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2066 typedef cmds::GetAttachedShaders::Result Result;
2067 uint32 size = Result::ComputeSize(maxcount);
2068 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
2069 if (!result) {
2070 return;
2072 result->SetNumResults(0);
2073 helper_->GetAttachedShaders(
2074 program,
2075 transfer_buffer_->GetShmId(),
2076 transfer_buffer_->GetOffset(result),
2077 size);
2078 int32 token = helper_->InsertToken();
2079 WaitForCmd();
2080 if (count) {
2081 *count = result->GetNumResults();
2083 result->CopyResult(shaders);
2084 GPU_CLIENT_LOG_CODE_BLOCK({
2085 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2086 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2089 transfer_buffer_->FreePendingToken(result, token);
2090 CheckGLError();
2093 void GLES2Implementation::GetShaderPrecisionFormat(
2094 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
2095 GPU_CLIENT_SINGLE_THREAD_CHECK();
2096 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2097 << GLES2Util::GetStringShaderType(shadertype) << ", "
2098 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
2099 << static_cast<const void*>(range) << ", "
2100 << static_cast<const void*>(precision) << ", ");
2101 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2102 typedef cmds::GetShaderPrecisionFormat::Result Result;
2103 Result* result = GetResultAs<Result*>();
2104 if (!result) {
2105 return;
2108 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
2109 GLStaticState::ShaderPrecisionMap::iterator i =
2110 static_state_.shader_precisions.find(key);
2111 if (i != static_state_.shader_precisions.end()) {
2112 *result = i->second;
2113 } else {
2114 result->success = false;
2115 helper_->GetShaderPrecisionFormat(
2116 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
2117 WaitForCmd();
2118 if (result->success)
2119 static_state_.shader_precisions[key] = *result;
2122 if (result->success) {
2123 if (range) {
2124 range[0] = result->min_range;
2125 range[1] = result->max_range;
2126 GPU_CLIENT_LOG(" min_range: " << range[0]);
2127 GPU_CLIENT_LOG(" min_range: " << range[1]);
2129 if (precision) {
2130 precision[0] = result->precision;
2131 GPU_CLIENT_LOG(" min_range: " << precision[0]);
2134 CheckGLError();
2137 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
2138 const char* result = NULL;
2139 // Clears the bucket so if the command fails nothing will be in it.
2140 helper_->SetBucketSize(kResultBucketId, 0);
2141 helper_->GetString(name, kResultBucketId);
2142 std::string str;
2143 if (GetBucketAsString(kResultBucketId, &str)) {
2144 // Adds extensions implemented on client side only.
2145 switch (name) {
2146 case GL_EXTENSIONS:
2147 str += std::string(str.empty() ? "" : " ") +
2148 "GL_CHROMIUM_flipy "
2149 "GL_EXT_unpack_subimage";
2150 if (capabilities_.map_image) {
2151 // The first space character is intentional.
2152 str += " GL_CHROMIUM_map_image";
2154 break;
2155 default:
2156 break;
2159 // Because of WebGL the extensions can change. We have to cache each unique
2160 // result since we don't know when the client will stop referring to a
2161 // previous one it queries.
2162 GLStringMap::iterator it = gl_strings_.find(name);
2163 if (it == gl_strings_.end()) {
2164 std::set<std::string> strings;
2165 std::pair<GLStringMap::iterator, bool> insert_result =
2166 gl_strings_.insert(std::make_pair(name, strings));
2167 DCHECK(insert_result.second);
2168 it = insert_result.first;
2170 std::set<std::string>& string_set = it->second;
2171 std::set<std::string>::const_iterator sit = string_set.find(str);
2172 if (sit != string_set.end()) {
2173 result = sit->c_str();
2174 } else {
2175 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2176 string_set.insert(str);
2177 DCHECK(insert_result.second);
2178 result = insert_result.first->c_str();
2181 return reinterpret_cast<const GLubyte*>(result);
2184 const GLubyte* GLES2Implementation::GetString(GLenum name) {
2185 GPU_CLIENT_SINGLE_THREAD_CHECK();
2186 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2187 << GLES2Util::GetStringStringType(name) << ")");
2188 TRACE_EVENT0("gpu", "GLES2::GetString");
2189 const GLubyte* result = GetStringHelper(name);
2190 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
2191 CheckGLError();
2192 return result;
2195 void GLES2Implementation::GetUniformfv(
2196 GLuint program, GLint location, GLfloat* params) {
2197 GPU_CLIENT_SINGLE_THREAD_CHECK();
2198 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2199 << program << ", " << location << ", "
2200 << static_cast<const void*>(params) << ")");
2201 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2202 typedef cmds::GetUniformfv::Result Result;
2203 Result* result = GetResultAs<Result*>();
2204 if (!result) {
2205 return;
2207 result->SetNumResults(0);
2208 helper_->GetUniformfv(
2209 program, location, GetResultShmId(), GetResultShmOffset());
2210 WaitForCmd();
2211 result->CopyResult(params);
2212 GPU_CLIENT_LOG_CODE_BLOCK({
2213 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2214 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2217 CheckGLError();
2220 void GLES2Implementation::GetUniformiv(
2221 GLuint program, GLint location, GLint* params) {
2222 GPU_CLIENT_SINGLE_THREAD_CHECK();
2223 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2224 << program << ", " << location << ", "
2225 << static_cast<const void*>(params) << ")");
2226 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2227 typedef cmds::GetUniformiv::Result Result;
2228 Result* result = GetResultAs<Result*>();
2229 if (!result) {
2230 return;
2232 result->SetNumResults(0);
2233 helper_->GetUniformiv(
2234 program, location, GetResultShmId(), GetResultShmOffset());
2235 WaitForCmd();
2236 GetResultAs<cmds::GetUniformfv::Result*>()->CopyResult(params);
2237 GPU_CLIENT_LOG_CODE_BLOCK({
2238 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2239 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2242 CheckGLError();
2245 void GLES2Implementation::ReadPixels(
2246 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
2247 GLenum type, void* pixels) {
2248 GPU_CLIENT_SINGLE_THREAD_CHECK();
2249 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2250 << xoffset << ", " << yoffset << ", "
2251 << width << ", " << height << ", "
2252 << GLES2Util::GetStringReadPixelFormat(format) << ", "
2253 << GLES2Util::GetStringPixelType(type) << ", "
2254 << static_cast<const void*>(pixels) << ")");
2255 if (width < 0 || height < 0) {
2256 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
2257 return;
2259 if (width == 0 || height == 0) {
2260 return;
2263 // glReadPixel pads the size of each row of pixels by an amount specified by
2264 // glPixelStorei. So, we have to take that into account both in the fact that
2265 // the pixels returned from the ReadPixel command will include that padding
2266 // and that when we copy the results to the user's buffer we need to not
2267 // write those padding bytes but leave them as they are.
2269 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2270 typedef cmds::ReadPixels::Result Result;
2272 int8* dest = reinterpret_cast<int8*>(pixels);
2273 uint32 temp_size;
2274 uint32 unpadded_row_size;
2275 uint32 padded_row_size;
2276 if (!GLES2Util::ComputeImageDataSizes(
2277 width, 2, format, type, pack_alignment_, &temp_size, &unpadded_row_size,
2278 &padded_row_size)) {
2279 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
2280 return;
2283 if (bound_pixel_pack_transfer_buffer_id_) {
2284 GLuint offset = ToGLuint(pixels);
2285 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2286 bound_pixel_pack_transfer_buffer_id_,
2287 "glReadPixels", offset, padded_row_size * height);
2288 if (buffer && buffer->shm_id() != -1) {
2289 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
2290 buffer->shm_id(), buffer->shm_offset(),
2291 0, 0, true);
2292 CheckGLError();
2294 return;
2297 if (!pixels) {
2298 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
2299 return;
2302 // Transfer by rows.
2303 // The max rows we can transfer.
2304 while (height) {
2305 GLsizei desired_size = padded_row_size * height - 1 + unpadded_row_size;
2306 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
2307 if (!buffer.valid()) {
2308 return;
2310 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2311 padded_row_size, unpadded_row_size, buffer.size());
2312 num_rows = std::min(num_rows, height);
2313 // NOTE: We must look up the address of the result area AFTER allocation
2314 // of the transfer buffer since the transfer buffer may be reallocated.
2315 Result* result = GetResultAs<Result*>();
2316 if (!result) {
2317 return;
2319 *result = 0; // mark as failed.
2320 helper_->ReadPixels(
2321 xoffset, yoffset, width, num_rows, format, type,
2322 buffer.shm_id(), buffer.offset(),
2323 GetResultShmId(), GetResultShmOffset(),
2324 false);
2325 WaitForCmd();
2326 if (*result != 0) {
2327 // when doing a y-flip we have to iterate through top-to-bottom chunks
2328 // of the dst. The service side handles reversing the rows within a
2329 // chunk.
2330 int8* rows_dst;
2331 if (pack_reverse_row_order_) {
2332 rows_dst = dest + (height - num_rows) * padded_row_size;
2333 } else {
2334 rows_dst = dest;
2336 // We have to copy 1 row at a time to avoid writing pad bytes.
2337 const int8* src = static_cast<const int8*>(buffer.address());
2338 for (GLint yy = 0; yy < num_rows; ++yy) {
2339 memcpy(rows_dst, src, unpadded_row_size);
2340 rows_dst += padded_row_size;
2341 src += padded_row_size;
2343 if (!pack_reverse_row_order_) {
2344 dest = rows_dst;
2347 // If it was not marked as successful exit.
2348 if (*result == 0) {
2349 return;
2351 yoffset += num_rows;
2352 height -= num_rows;
2354 CheckGLError();
2357 void GLES2Implementation::ActiveTexture(GLenum texture) {
2358 GPU_CLIENT_SINGLE_THREAD_CHECK();
2359 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2360 << GLES2Util::GetStringEnum(texture) << ")");
2361 GLuint texture_index = texture - GL_TEXTURE0;
2362 if (texture_index >= static_cast<GLuint>(
2363 static_state_.int_state.max_combined_texture_image_units)) {
2364 SetGLErrorInvalidEnum(
2365 "glActiveTexture", texture, "texture");
2366 return;
2369 active_texture_unit_ = texture_index;
2370 helper_->ActiveTexture(texture);
2371 CheckGLError();
2374 void GLES2Implementation::GenBuffersHelper(
2375 GLsizei /* n */, const GLuint* /* buffers */) {
2378 void GLES2Implementation::GenFramebuffersHelper(
2379 GLsizei /* n */, const GLuint* /* framebuffers */) {
2382 void GLES2Implementation::GenRenderbuffersHelper(
2383 GLsizei /* n */, const GLuint* /* renderbuffers */) {
2386 void GLES2Implementation::GenTexturesHelper(
2387 GLsizei /* n */, const GLuint* /* textures */) {
2390 void GLES2Implementation::GenVertexArraysOESHelper(
2391 GLsizei n, const GLuint* arrays) {
2392 vertex_array_object_manager_->GenVertexArrays(n, arrays);
2395 void GLES2Implementation::GenQueriesEXTHelper(
2396 GLsizei /* n */, const GLuint* /* queries */) {
2399 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
2400 // generates a new resource. On newer versions of OpenGL they don't. The code
2401 // related to binding below will need to change if we switch to the new OpenGL
2402 // model. Specifically it assumes a bind will succeed which is always true in
2403 // the old model but possibly not true in the new model if another context has
2404 // deleted the resource.
2406 bool GLES2Implementation::BindBufferHelper(
2407 GLenum target, GLuint buffer) {
2408 // TODO(gman): See note #1 above.
2409 bool changed = false;
2410 switch (target) {
2411 case GL_ARRAY_BUFFER:
2412 if (bound_array_buffer_id_ != buffer) {
2413 bound_array_buffer_id_ = buffer;
2414 changed = true;
2416 break;
2417 case GL_ELEMENT_ARRAY_BUFFER:
2418 changed = vertex_array_object_manager_->BindElementArray(buffer);
2419 break;
2420 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
2421 bound_pixel_pack_transfer_buffer_id_ = buffer;
2422 break;
2423 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
2424 bound_pixel_unpack_transfer_buffer_id_ = buffer;
2425 break;
2426 default:
2427 changed = true;
2428 break;
2430 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2431 // used even though it's marked it as used here.
2432 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(buffer);
2433 return changed;
2436 bool GLES2Implementation::BindFramebufferHelper(
2437 GLenum target, GLuint framebuffer) {
2438 // TODO(gman): See note #1 above.
2439 bool changed = false;
2440 switch (target) {
2441 case GL_FRAMEBUFFER:
2442 if (bound_framebuffer_ != framebuffer ||
2443 bound_read_framebuffer_ != framebuffer) {
2444 bound_framebuffer_ = framebuffer;
2445 bound_read_framebuffer_ = framebuffer;
2446 changed = true;
2448 break;
2449 case GL_READ_FRAMEBUFFER:
2450 if (!IsChromiumFramebufferMultisampleAvailable()) {
2451 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2452 return false;
2454 if (bound_read_framebuffer_ != framebuffer) {
2455 bound_read_framebuffer_ = framebuffer;
2456 changed = true;
2458 break;
2459 case GL_DRAW_FRAMEBUFFER:
2460 if (!IsChromiumFramebufferMultisampleAvailable()) {
2461 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2462 return false;
2464 if (bound_framebuffer_ != framebuffer) {
2465 bound_framebuffer_ = framebuffer;
2466 changed = true;
2468 break;
2469 default:
2470 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2471 return false;
2473 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(framebuffer);
2474 return changed;
2477 bool GLES2Implementation::BindRenderbufferHelper(
2478 GLenum target, GLuint renderbuffer) {
2479 // TODO(gman): See note #1 above.
2480 bool changed = false;
2481 switch (target) {
2482 case GL_RENDERBUFFER:
2483 if (bound_renderbuffer_ != renderbuffer) {
2484 bound_renderbuffer_ = renderbuffer;
2485 changed = true;
2487 break;
2488 default:
2489 changed = true;
2490 break;
2492 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2493 // used even though it's marked it as used here.
2494 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(renderbuffer);
2495 return changed;
2498 bool GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
2499 // TODO(gman): See note #1 above.
2500 // TODO(gman): Change this to false once we figure out why it's failing
2501 // on daisy.
2502 bool changed = true;
2503 TextureUnit& unit = texture_units_[active_texture_unit_];
2504 switch (target) {
2505 case GL_TEXTURE_2D:
2506 if (unit.bound_texture_2d != texture) {
2507 unit.bound_texture_2d = texture;
2508 changed = true;
2510 break;
2511 case GL_TEXTURE_CUBE_MAP:
2512 if (unit.bound_texture_cube_map != texture) {
2513 unit.bound_texture_cube_map = texture;
2514 changed = true;
2516 break;
2517 case GL_TEXTURE_EXTERNAL_OES:
2518 if (unit.bound_texture_external_oes != texture) {
2519 unit.bound_texture_external_oes = texture;
2520 changed = true;
2522 break;
2523 default:
2524 changed = true;
2525 break;
2527 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2528 // used. even though it's marked it as used here.
2529 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(texture);
2530 return changed;
2533 bool GLES2Implementation::BindVertexArrayHelper(GLuint array) {
2534 // TODO(gman): See note #1 above.
2535 bool changed = false;
2536 if (!vertex_array_object_manager_->BindVertexArray(array, &changed)) {
2537 SetGLError(
2538 GL_INVALID_OPERATION, "glBindVertexArrayOES",
2539 "id was not generated with glGenVertexArrayOES");
2541 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
2542 // because unlike other resources VertexArrayObject ids must
2543 // be generated by GenVertexArrays. A random id to Bind will not
2544 // generate a new object.
2545 return changed;
2548 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
2549 return vertex_array_object_manager_->IsReservedId(id);
2552 void GLES2Implementation::DeleteBuffersHelper(
2553 GLsizei n, const GLuint* buffers) {
2554 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
2555 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
2556 SetGLError(
2557 GL_INVALID_VALUE,
2558 "glDeleteBuffers", "id not created by this context.");
2559 return;
2561 for (GLsizei ii = 0; ii < n; ++ii) {
2562 if (buffers[ii] == bound_array_buffer_id_) {
2563 bound_array_buffer_id_ = 0;
2565 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
2566 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
2567 if (buffer) {
2568 // Free buffer memory, pending the passage of a token.
2569 buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
2570 // Remove buffer.
2571 buffer_tracker_->RemoveBuffer(buffers[ii]);
2573 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
2574 bound_pixel_unpack_transfer_buffer_id_ = 0;
2579 void GLES2Implementation::DeleteBuffersStub(
2580 GLsizei n, const GLuint* buffers) {
2581 helper_->DeleteBuffersImmediate(n, buffers);
2585 void GLES2Implementation::DeleteFramebuffersHelper(
2586 GLsizei n, const GLuint* framebuffers) {
2587 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
2588 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
2589 SetGLError(
2590 GL_INVALID_VALUE,
2591 "glDeleteFramebuffers", "id not created by this context.");
2592 return;
2594 for (GLsizei ii = 0; ii < n; ++ii) {
2595 if (framebuffers[ii] == bound_framebuffer_) {
2596 bound_framebuffer_ = 0;
2598 if (framebuffers[ii] == bound_read_framebuffer_) {
2599 bound_read_framebuffer_ = 0;
2604 void GLES2Implementation::DeleteFramebuffersStub(
2605 GLsizei n, const GLuint* framebuffers) {
2606 helper_->DeleteFramebuffersImmediate(n, framebuffers);
2609 void GLES2Implementation::DeleteRenderbuffersHelper(
2610 GLsizei n, const GLuint* renderbuffers) {
2611 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
2612 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
2613 SetGLError(
2614 GL_INVALID_VALUE,
2615 "glDeleteRenderbuffers", "id not created by this context.");
2616 return;
2618 for (GLsizei ii = 0; ii < n; ++ii) {
2619 if (renderbuffers[ii] == bound_renderbuffer_) {
2620 bound_renderbuffer_ = 0;
2625 void GLES2Implementation::DeleteRenderbuffersStub(
2626 GLsizei n, const GLuint* renderbuffers) {
2627 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
2630 void GLES2Implementation::DeleteTexturesHelper(
2631 GLsizei n, const GLuint* textures) {
2632 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
2633 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
2634 SetGLError(
2635 GL_INVALID_VALUE,
2636 "glDeleteTextures", "id not created by this context.");
2637 return;
2639 for (GLsizei ii = 0; ii < n; ++ii) {
2640 for (GLint tt = 0;
2641 tt < static_state_.int_state.max_combined_texture_image_units;
2642 ++tt) {
2643 TextureUnit& unit = texture_units_[tt];
2644 if (textures[ii] == unit.bound_texture_2d) {
2645 unit.bound_texture_2d = 0;
2647 if (textures[ii] == unit.bound_texture_cube_map) {
2648 unit.bound_texture_cube_map = 0;
2650 if (textures[ii] == unit.bound_texture_external_oes) {
2651 unit.bound_texture_external_oes = 0;
2657 void GLES2Implementation::DeleteVertexArraysOESHelper(
2658 GLsizei n, const GLuint* arrays) {
2659 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
2660 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
2661 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
2662 SetGLError(
2663 GL_INVALID_VALUE,
2664 "glDeleteVertexArraysOES", "id not created by this context.");
2665 return;
2669 void GLES2Implementation::DeleteVertexArraysOESStub(
2670 GLsizei n, const GLuint* arrays) {
2671 helper_->DeleteVertexArraysOESImmediate(n, arrays);
2674 void GLES2Implementation::DeleteTexturesStub(
2675 GLsizei n, const GLuint* textures) {
2676 helper_->DeleteTexturesImmediate(n, textures);
2679 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
2680 GPU_CLIENT_SINGLE_THREAD_CHECK();
2681 GPU_CLIENT_LOG(
2682 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
2683 vertex_array_object_manager_->SetAttribEnable(index, false);
2684 helper_->DisableVertexAttribArray(index);
2685 CheckGLError();
2688 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
2689 GPU_CLIENT_SINGLE_THREAD_CHECK();
2690 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
2691 << index << ")");
2692 vertex_array_object_manager_->SetAttribEnable(index, true);
2693 helper_->EnableVertexAttribArray(index);
2694 CheckGLError();
2697 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
2698 GPU_CLIENT_SINGLE_THREAD_CHECK();
2699 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
2700 << GLES2Util::GetStringDrawMode(mode) << ", "
2701 << first << ", " << count << ")");
2702 if (count < 0) {
2703 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
2704 return;
2706 bool simulated = false;
2707 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
2708 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
2709 return;
2711 helper_->DrawArrays(mode, first, count);
2712 RestoreArrayBuffer(simulated);
2713 CheckGLError();
2716 void GLES2Implementation::GetVertexAttribfv(
2717 GLuint index, GLenum pname, GLfloat* params) {
2718 GPU_CLIENT_SINGLE_THREAD_CHECK();
2719 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
2720 << index << ", "
2721 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2722 << static_cast<const void*>(params) << ")");
2723 uint32 value = 0;
2724 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2725 *params = static_cast<float>(value);
2726 return;
2728 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
2729 typedef cmds::GetVertexAttribfv::Result Result;
2730 Result* result = GetResultAs<Result*>();
2731 if (!result) {
2732 return;
2734 result->SetNumResults(0);
2735 helper_->GetVertexAttribfv(
2736 index, pname, GetResultShmId(), GetResultShmOffset());
2737 WaitForCmd();
2738 result->CopyResult(params);
2739 GPU_CLIENT_LOG_CODE_BLOCK({
2740 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2741 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2744 CheckGLError();
2747 void GLES2Implementation::GetVertexAttribiv(
2748 GLuint index, GLenum pname, GLint* params) {
2749 GPU_CLIENT_SINGLE_THREAD_CHECK();
2750 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
2751 << index << ", "
2752 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2753 << static_cast<const void*>(params) << ")");
2754 uint32 value = 0;
2755 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2756 *params = value;
2757 return;
2759 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
2760 typedef cmds::GetVertexAttribiv::Result Result;
2761 Result* result = GetResultAs<Result*>();
2762 if (!result) {
2763 return;
2765 result->SetNumResults(0);
2766 helper_->GetVertexAttribiv(
2767 index, pname, GetResultShmId(), GetResultShmOffset());
2768 WaitForCmd();
2769 result->CopyResult(params);
2770 GPU_CLIENT_LOG_CODE_BLOCK({
2771 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2772 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2775 CheckGLError();
2778 void GLES2Implementation::Swap() {
2779 SwapBuffers();
2780 gpu_control_->Echo(
2781 base::Bind(&GLES2Implementation::OnSwapBuffersComplete,
2782 weak_ptr_factory_.GetWeakPtr()));
2785 void GLES2Implementation::PartialSwapBuffers(gfx::Rect sub_buffer) {
2786 PostSubBufferCHROMIUM(sub_buffer.x(),
2787 sub_buffer.y(),
2788 sub_buffer.width(),
2789 sub_buffer.height());
2790 gpu_control_->Echo(base::Bind(&GLES2Implementation::OnSwapBuffersComplete,
2791 weak_ptr_factory_.GetWeakPtr()));
2794 void GLES2Implementation::SetSwapBuffersCompleteCallback(
2795 const base::Closure& swap_buffers_complete_callback) {
2796 swap_buffers_complete_callback_ = swap_buffers_complete_callback;
2799 void GLES2Implementation::OnSwapBuffersComplete() {
2800 if (!swap_buffers_complete_callback_.is_null())
2801 swap_buffers_complete_callback_.Run();
2804 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
2805 const char* feature) {
2806 GPU_CLIENT_SINGLE_THREAD_CHECK();
2807 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
2808 << feature << ")");
2809 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
2810 typedef cmds::EnableFeatureCHROMIUM::Result Result;
2811 Result* result = GetResultAs<Result*>();
2812 if (!result) {
2813 return false;
2815 *result = 0;
2816 SetBucketAsCString(kResultBucketId, feature);
2817 helper_->EnableFeatureCHROMIUM(
2818 kResultBucketId, GetResultShmId(), GetResultShmOffset());
2819 WaitForCmd();
2820 helper_->SetBucketSize(kResultBucketId, 0);
2821 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
2822 return *result;
2825 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
2826 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
2827 GPU_CLIENT_SINGLE_THREAD_CHECK();
2828 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
2829 << target << ", " << offset << ", " << size << ", "
2830 << GLES2Util::GetStringEnum(access) << ")");
2831 // NOTE: target is NOT checked because the service will check it
2832 // and we don't know what targets are valid.
2833 if (access != GL_WRITE_ONLY) {
2834 SetGLErrorInvalidEnum(
2835 "glMapBufferSubDataCHROMIUM", access, "access");
2836 return NULL;
2838 if (offset < 0 || size < 0) {
2839 SetGLError(GL_INVALID_VALUE, "glMapBufferSubDataCHROMIUM", "bad range");
2840 return NULL;
2842 int32 shm_id;
2843 unsigned int shm_offset;
2844 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2845 if (!mem) {
2846 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
2847 return NULL;
2850 std::pair<MappedBufferMap::iterator, bool> result =
2851 mapped_buffers_.insert(std::make_pair(
2852 mem,
2853 MappedBuffer(
2854 access, shm_id, mem, shm_offset, target, offset, size)));
2855 DCHECK(result.second);
2856 GPU_CLIENT_LOG(" returned " << mem);
2857 return mem;
2860 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
2861 GPU_CLIENT_SINGLE_THREAD_CHECK();
2862 GPU_CLIENT_LOG(
2863 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
2864 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
2865 if (it == mapped_buffers_.end()) {
2866 SetGLError(
2867 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
2868 return;
2870 const MappedBuffer& mb = it->second;
2871 helper_->BufferSubData(
2872 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
2873 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
2874 mapped_buffers_.erase(it);
2875 CheckGLError();
2878 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
2879 GLenum target,
2880 GLint level,
2881 GLint xoffset,
2882 GLint yoffset,
2883 GLsizei width,
2884 GLsizei height,
2885 GLenum format,
2886 GLenum type,
2887 GLenum access) {
2888 GPU_CLIENT_SINGLE_THREAD_CHECK();
2889 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
2890 << target << ", " << level << ", "
2891 << xoffset << ", " << yoffset << ", "
2892 << width << ", " << height << ", "
2893 << GLES2Util::GetStringTextureFormat(format) << ", "
2894 << GLES2Util::GetStringPixelType(type) << ", "
2895 << GLES2Util::GetStringEnum(access) << ")");
2896 if (access != GL_WRITE_ONLY) {
2897 SetGLErrorInvalidEnum(
2898 "glMapTexSubImage2DCHROMIUM", access, "access");
2899 return NULL;
2901 // NOTE: target is NOT checked because the service will check it
2902 // and we don't know what targets are valid.
2903 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
2904 SetGLError(
2905 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
2906 return NULL;
2908 uint32 size;
2909 if (!GLES2Util::ComputeImageDataSizes(
2910 width, height, format, type, unpack_alignment_, &size, NULL, NULL)) {
2911 SetGLError(
2912 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
2913 return NULL;
2915 int32 shm_id;
2916 unsigned int shm_offset;
2917 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2918 if (!mem) {
2919 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
2920 return NULL;
2923 std::pair<MappedTextureMap::iterator, bool> result =
2924 mapped_textures_.insert(std::make_pair(
2925 mem,
2926 MappedTexture(
2927 access, shm_id, mem, shm_offset,
2928 target, level, xoffset, yoffset, width, height, format, type)));
2929 DCHECK(result.second);
2930 GPU_CLIENT_LOG(" returned " << mem);
2931 return mem;
2934 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
2935 GPU_CLIENT_SINGLE_THREAD_CHECK();
2936 GPU_CLIENT_LOG(
2937 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
2938 MappedTextureMap::iterator it = mapped_textures_.find(mem);
2939 if (it == mapped_textures_.end()) {
2940 SetGLError(
2941 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
2942 return;
2944 const MappedTexture& mt = it->second;
2945 helper_->TexSubImage2D(
2946 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
2947 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
2948 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
2949 mapped_textures_.erase(it);
2950 CheckGLError();
2953 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
2954 float scale_factor) {
2955 GPU_CLIENT_SINGLE_THREAD_CHECK();
2956 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
2957 << width << ", " << height << ", " << scale_factor << ")");
2958 helper_->ResizeCHROMIUM(width, height, scale_factor);
2959 CheckGLError();
2962 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
2963 GPU_CLIENT_SINGLE_THREAD_CHECK();
2964 GPU_CLIENT_LOG("[" << GetLogPrefix()
2965 << "] glGetRequestableExtensionsCHROMIUM()");
2966 TRACE_EVENT0("gpu",
2967 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
2968 const char* result = NULL;
2969 // Clear the bucket so if the command fails nothing will be in it.
2970 helper_->SetBucketSize(kResultBucketId, 0);
2971 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
2972 std::string str;
2973 if (GetBucketAsString(kResultBucketId, &str)) {
2974 // The set of requestable extensions shrinks as we enable
2975 // them. Because we don't know when the client will stop referring
2976 // to a previous one it queries (see GetString) we need to cache
2977 // the unique results.
2978 std::set<std::string>::const_iterator sit =
2979 requestable_extensions_set_.find(str);
2980 if (sit != requestable_extensions_set_.end()) {
2981 result = sit->c_str();
2982 } else {
2983 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2984 requestable_extensions_set_.insert(str);
2985 DCHECK(insert_result.second);
2986 result = insert_result.first->c_str();
2989 GPU_CLIENT_LOG(" returned " << result);
2990 return reinterpret_cast<const GLchar*>(result);
2993 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
2994 // with VirtualGL contexts.
2995 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
2996 GPU_CLIENT_SINGLE_THREAD_CHECK();
2997 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
2998 << extension << ")");
2999 SetBucketAsCString(kResultBucketId, extension);
3000 helper_->RequestExtensionCHROMIUM(kResultBucketId);
3001 helper_->SetBucketSize(kResultBucketId, 0);
3003 struct ExtensionCheck {
3004 const char* extension;
3005 ExtensionStatus* status;
3007 const ExtensionCheck checks[] = {
3009 "GL_ANGLE_pack_reverse_row_order",
3010 &angle_pack_reverse_row_order_status_,
3013 "GL_CHROMIUM_framebuffer_multisample",
3014 &chromium_framebuffer_multisample_,
3017 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
3018 for (size_t ii = 0; ii < kNumChecks; ++ii) {
3019 const ExtensionCheck& check = checks[ii];
3020 if (*check.status == kUnavailableExtensionStatus &&
3021 !strcmp(extension, check.extension)) {
3022 *check.status = kUnknownExtensionStatus;
3027 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
3028 GPU_CLIENT_SINGLE_THREAD_CHECK();
3029 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
3030 // Wait if this would add too many rate limit tokens.
3031 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
3032 helper_->WaitForToken(rate_limit_tokens_.front());
3033 rate_limit_tokens_.pop();
3035 rate_limit_tokens_.push(helper_->InsertToken());
3038 void GLES2Implementation::GetMultipleIntegervCHROMIUM(
3039 const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size) {
3040 GPU_CLIENT_SINGLE_THREAD_CHECK();
3041 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMultipleIntegervCHROMIUM("
3042 << static_cast<const void*>(pnames) << ", "
3043 << count << ", " << results << ", "
3044 << size << ")");
3045 GPU_CLIENT_LOG_CODE_BLOCK({
3046 for (GLuint i = 0; i < count; ++i) {
3047 GPU_CLIENT_LOG(
3048 " " << i << ": " << GLES2Util::GetStringGLState(pnames[i]));
3052 GetMultipleIntegervState state(pnames, count, results, size);
3053 if (!GetMultipleIntegervSetup(&state)) {
3054 return;
3056 state.buffer = transfer_buffer_->Alloc(state.transfer_buffer_size_needed);
3057 if (!state.buffer) {
3058 SetGLError(GL_OUT_OF_MEMORY, "glGetMultipleIntegervCHROMIUM",
3059 "Transfer buffer allocation failed.");
3060 return;
3062 GetMultipleIntegervRequest(&state);
3063 WaitForCmd();
3064 GetMultipleIntegervOnCompleted(&state);
3066 GPU_CLIENT_LOG(" returned");
3067 GPU_CLIENT_LOG_CODE_BLOCK({
3068 for (int i = 0; i < state.num_results; ++i) {
3069 GPU_CLIENT_LOG(" " << i << ": " << (results[i]));
3073 // TODO(gman): We should be able to free without a token.
3074 transfer_buffer_->FreePendingToken(state.buffer, helper_->InsertToken());
3075 CheckGLError();
3078 bool GLES2Implementation::GetMultipleIntegervSetup(
3079 GetMultipleIntegervState* state) {
3080 state->num_results = 0;
3081 for (GLuint ii = 0; ii < state->pnames_count; ++ii) {
3082 int num = util_.GLGetNumValuesReturned(state->pnames[ii]);
3083 if (!num) {
3084 SetGLErrorInvalidEnum(
3085 "glGetMultipleIntegervCHROMIUM", state->pnames[ii], "pname");
3086 return false;
3088 state->num_results += num;
3090 if (static_cast<size_t>(state->results_size) !=
3091 state->num_results * sizeof(GLint)) {
3092 SetGLError(GL_INVALID_VALUE, "glGetMultipleIntegervCHROMIUM", "bad size");
3093 return false;
3095 for (int ii = 0; ii < state->num_results; ++ii) {
3096 if (state->results[ii] != 0) {
3097 SetGLError(GL_INVALID_VALUE,
3098 "glGetMultipleIntegervCHROMIUM", "results not set to zero.");
3099 return false;
3102 state->transfer_buffer_size_needed =
3103 state->pnames_count * sizeof(state->pnames[0]) +
3104 state->num_results * sizeof(state->results[0]);
3105 return true;
3108 void GLES2Implementation::GetMultipleIntegervRequest(
3109 GetMultipleIntegervState* state) {
3110 GLenum* pnames_buffer = static_cast<GLenum*>(state->buffer);
3111 state->results_buffer = pnames_buffer + state->pnames_count;
3112 memcpy(pnames_buffer, state->pnames, state->pnames_count * sizeof(GLenum));
3113 memset(state->results_buffer, 0, state->num_results * sizeof(GLint));
3114 helper_->GetMultipleIntegervCHROMIUM(
3115 transfer_buffer_->GetShmId(),
3116 transfer_buffer_->GetOffset(pnames_buffer),
3117 state->pnames_count,
3118 transfer_buffer_->GetShmId(),
3119 transfer_buffer_->GetOffset(state->results_buffer),
3120 state->results_size);
3123 void GLES2Implementation::GetMultipleIntegervOnCompleted(
3124 GetMultipleIntegervState* state) {
3125 memcpy(state->results, state->results_buffer, state->results_size);;
3128 void GLES2Implementation::GetAllShaderPrecisionFormatsSetup(
3129 GetAllShaderPrecisionFormatsState* state) {
3130 state->transfer_buffer_size_needed =
3131 state->precision_params_count *
3132 sizeof(cmds::GetShaderPrecisionFormat::Result);
3135 void GLES2Implementation::GetAllShaderPrecisionFormatsRequest(
3136 GetAllShaderPrecisionFormatsState* state) {
3137 typedef cmds::GetShaderPrecisionFormat::Result Result;
3138 Result* result = static_cast<Result*>(state->results_buffer);
3140 for (int i = 0; i < state->precision_params_count; i++) {
3141 result->success = false;
3142 helper_->GetShaderPrecisionFormat(state->precision_params[i][0],
3143 state->precision_params[i][1],
3144 transfer_buffer_->GetShmId(),
3145 transfer_buffer_->GetOffset(result));
3146 result++;
3150 void GLES2Implementation::GetAllShaderPrecisionFormatsOnCompleted(
3151 GetAllShaderPrecisionFormatsState* state) {
3152 typedef cmds::GetShaderPrecisionFormat::Result Result;
3153 Result* result = static_cast<Result*>(state->results_buffer);
3155 for (int i = 0; i < state->precision_params_count; i++) {
3156 if (result->success) {
3157 const GLStaticState::ShaderPrecisionKey key(
3158 state->precision_params[i][0], state->precision_params[i][1]);
3159 static_state_.shader_precisions[key] = *result;
3161 result++;
3165 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3166 GLuint program, std::vector<int8>* result) {
3167 DCHECK(result);
3168 // Clear the bucket so if the command fails nothing will be in it.
3169 helper_->SetBucketSize(kResultBucketId, 0);
3170 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
3171 GetBucketContents(kResultBucketId, result);
3174 void GLES2Implementation::GetProgramInfoCHROMIUM(
3175 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3176 GPU_CLIENT_SINGLE_THREAD_CHECK();
3177 if (bufsize < 0) {
3178 SetGLError(
3179 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3180 return;
3182 if (size == NULL) {
3183 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
3184 return;
3186 // Make sure they've set size to 0 else the value will be undefined on
3187 // lost context.
3188 DCHECK(*size == 0);
3189 std::vector<int8> result;
3190 GetProgramInfoCHROMIUMHelper(program, &result);
3191 if (result.empty()) {
3192 return;
3194 *size = result.size();
3195 if (!info) {
3196 return;
3198 if (static_cast<size_t>(bufsize) < result.size()) {
3199 SetGLError(GL_INVALID_OPERATION,
3200 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3201 return;
3203 memcpy(info, &result[0], result.size());
3206 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
3207 GPU_CLIENT_SINGLE_THREAD_CHECK();
3208 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
3209 << texture << ")");
3210 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
3211 typedef cmds::CreateStreamTextureCHROMIUM::Result Result;
3212 Result* result = GetResultAs<Result*>();
3213 if (!result) {
3214 return GL_ZERO;
3216 *result = GL_ZERO;
3218 helper_->CreateStreamTextureCHROMIUM(texture,
3219 GetResultShmId(),
3220 GetResultShmOffset());
3221 WaitForCmd();
3222 GLuint result_value = *result;
3223 CheckGLError();
3224 return result_value;
3227 void GLES2Implementation::DestroyStreamTextureCHROMIUM(GLuint texture) {
3228 GPU_CLIENT_SINGLE_THREAD_CHECK();
3229 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] DestroyStreamTextureCHROMIUM("
3230 << texture << ")");
3231 TRACE_EVENT0("gpu", "GLES2::DestroyStreamTextureCHROMIUM");
3232 helper_->DestroyStreamTextureCHROMIUM(texture);
3233 CheckGLError();
3236 void GLES2Implementation::PostSubBufferCHROMIUM(
3237 GLint x, GLint y, GLint width, GLint height) {
3238 GPU_CLIENT_SINGLE_THREAD_CHECK();
3239 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
3240 << x << ", " << y << ", " << width << ", " << height << ")");
3241 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
3242 "width", width, "height", height);
3244 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
3245 swap_buffers_tokens_.push(helper_->InsertToken());
3246 helper_->PostSubBufferCHROMIUM(x, y, width, height);
3247 helper_->CommandBufferHelper::Flush();
3248 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
3249 helper_->WaitForToken(swap_buffers_tokens_.front());
3250 swap_buffers_tokens_.pop();
3254 void GLES2Implementation::DeleteQueriesEXTHelper(
3255 GLsizei n, const GLuint* queries) {
3256 // TODO(gman): Remove this as queries are not shared resources.
3257 if (!GetIdHandler(id_namespaces::kQueries)->FreeIds(
3258 this, n, queries, &GLES2Implementation::DeleteQueriesStub)) {
3259 SetGLError(
3260 GL_INVALID_VALUE,
3261 "glDeleteTextures", "id not created by this context.");
3262 return;
3265 for (GLsizei ii = 0; ii < n; ++ii)
3266 query_tracker_->RemoveQuery(queries[ii]);
3268 helper_->DeleteQueriesEXTImmediate(n, queries);
3271 // TODO(gman): Remove this. Queries are not shared resources.
3272 void GLES2Implementation::DeleteQueriesStub(
3273 GLsizei /* n */, const GLuint* /* queries */) {
3276 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
3277 GPU_CLIENT_SINGLE_THREAD_CHECK();
3278 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
3280 // TODO(gman): To be spec compliant IDs from other contexts sharing
3281 // resources need to return true here even though you can't share
3282 // queries across contexts?
3283 return query_tracker_->GetQuery(id) != NULL;
3286 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
3287 GPU_CLIENT_SINGLE_THREAD_CHECK();
3288 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
3289 << GLES2Util::GetStringQueryTarget(target)
3290 << ", " << id << ")");
3292 // if any outstanding queries INV_OP
3293 if (current_query_) {
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_query_ = 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 if (!current_query_) {
3337 SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
3338 return;
3341 if (current_query_->target() != target) {
3342 SetGLError(GL_INVALID_OPERATION,
3343 "glEndQueryEXT", "target does not match active query");
3344 return;
3347 current_query_->End(this);
3348 current_query_ = NULL;
3349 CheckGLError();
3352 void GLES2Implementation::GetQueryivEXT(
3353 GLenum target, GLenum pname, GLint* params) {
3354 GPU_CLIENT_SINGLE_THREAD_CHECK();
3355 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
3356 << GLES2Util::GetStringQueryTarget(target) << ", "
3357 << GLES2Util::GetStringQueryParameter(pname) << ", "
3358 << static_cast<const void*>(params) << ")");
3360 if (pname != GL_CURRENT_QUERY_EXT) {
3361 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
3362 return;
3364 *params = (current_query_ && current_query_->target() == target) ?
3365 current_query_->id() : 0;
3366 GPU_CLIENT_LOG(" " << *params);
3367 CheckGLError();
3370 void GLES2Implementation::GetQueryObjectuivEXT(
3371 GLuint id, GLenum pname, GLuint* params) {
3372 GPU_CLIENT_SINGLE_THREAD_CHECK();
3373 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
3374 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
3375 << static_cast<const void*>(params) << ")");
3377 QueryTracker::Query* query = query_tracker_->GetQuery(id);
3378 if (!query) {
3379 SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
3380 return;
3383 if (query == current_query_) {
3384 SetGLError(
3385 GL_INVALID_OPERATION,
3386 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
3387 return;
3390 if (query->NeverUsed()) {
3391 SetGLError(
3392 GL_INVALID_OPERATION,
3393 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
3394 return;
3397 switch (pname) {
3398 case GL_QUERY_RESULT_EXT:
3399 if (!query->CheckResultsAvailable(helper_)) {
3400 helper_->WaitForToken(query->token());
3401 if (!query->CheckResultsAvailable(helper_)) {
3402 // TODO(gman): Speed this up.
3403 WaitForCmd();
3404 CHECK(query->CheckResultsAvailable(helper_));
3407 *params = query->GetResult();
3408 break;
3409 case GL_QUERY_RESULT_AVAILABLE_EXT:
3410 *params = query->CheckResultsAvailable(helper_);
3411 break;
3412 default:
3413 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
3414 break;
3416 GPU_CLIENT_LOG(" " << *params);
3417 CheckGLError();
3420 void GLES2Implementation::DrawArraysInstancedANGLE(
3421 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
3422 GPU_CLIENT_SINGLE_THREAD_CHECK();
3423 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
3424 << GLES2Util::GetStringDrawMode(mode) << ", "
3425 << first << ", " << count << ", " << primcount << ")");
3426 if (count < 0) {
3427 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
3428 return;
3430 if (primcount < 0) {
3431 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
3432 return;
3434 if (primcount == 0) {
3435 return;
3437 bool simulated = false;
3438 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
3439 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
3440 &simulated)) {
3441 return;
3443 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
3444 RestoreArrayBuffer(simulated);
3445 CheckGLError();
3448 void GLES2Implementation::DrawElementsInstancedANGLE(
3449 GLenum mode, GLsizei count, GLenum type, const void* indices,
3450 GLsizei primcount) {
3451 GPU_CLIENT_SINGLE_THREAD_CHECK();
3452 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
3453 << GLES2Util::GetStringDrawMode(mode) << ", "
3454 << count << ", "
3455 << GLES2Util::GetStringIndexType(type) << ", "
3456 << static_cast<const void*>(indices) << ", "
3457 << primcount << ")");
3458 if (count < 0) {
3459 SetGLError(GL_INVALID_VALUE,
3460 "glDrawElementsInstancedANGLE", "count less than 0.");
3461 return;
3463 if (count == 0) {
3464 return;
3466 if (primcount < 0) {
3467 SetGLError(GL_INVALID_VALUE,
3468 "glDrawElementsInstancedANGLE", "primcount < 0");
3469 return;
3471 if (primcount == 0) {
3472 return;
3474 GLuint offset = 0;
3475 bool simulated = false;
3476 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
3477 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
3478 indices, &offset, &simulated)) {
3479 return;
3481 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
3482 RestoreElementAndArrayBuffers(simulated);
3483 CheckGLError();
3486 void GLES2Implementation::GenMailboxCHROMIUM(
3487 GLbyte* mailbox) {
3488 GPU_CLIENT_SINGLE_THREAD_CHECK();
3489 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
3490 << static_cast<const void*>(mailbox) << ")");
3491 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
3493 std::vector<gpu::Mailbox> names;
3494 if (!gpu_control_->GenerateMailboxNames(1, &names)) {
3495 SetGLError(GL_OUT_OF_MEMORY, "glGenMailboxCHROMIUM", "Generate failed.");
3496 return;
3498 memcpy(mailbox, names[0].name, GL_MAILBOX_SIZE_CHROMIUM);
3501 void GLES2Implementation::PushGroupMarkerEXT(
3502 GLsizei length, const GLchar* marker) {
3503 GPU_CLIENT_SINGLE_THREAD_CHECK();
3504 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
3505 << length << ", " << marker << ")");
3506 if (!marker) {
3507 marker = "";
3509 SetBucketAsString(
3510 kResultBucketId,
3511 (length ? std::string(marker, length) : std::string(marker)));
3512 helper_->PushGroupMarkerEXT(kResultBucketId);
3513 helper_->SetBucketSize(kResultBucketId, 0);
3514 debug_marker_manager_.PushGroup(
3515 length ? std::string(marker, length) : std::string(marker));
3518 void GLES2Implementation::InsertEventMarkerEXT(
3519 GLsizei length, const GLchar* marker) {
3520 GPU_CLIENT_SINGLE_THREAD_CHECK();
3521 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
3522 << length << ", " << marker << ")");
3523 if (!marker) {
3524 marker = "";
3526 SetBucketAsString(
3527 kResultBucketId,
3528 (length ? std::string(marker, length) : std::string(marker)));
3529 helper_->InsertEventMarkerEXT(kResultBucketId);
3530 helper_->SetBucketSize(kResultBucketId, 0);
3531 debug_marker_manager_.SetMarker(
3532 length ? std::string(marker, length) : std::string(marker));
3535 void GLES2Implementation::PopGroupMarkerEXT() {
3536 GPU_CLIENT_SINGLE_THREAD_CHECK();
3537 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
3538 helper_->PopGroupMarkerEXT();
3539 debug_marker_manager_.PopGroup();
3542 void GLES2Implementation::TraceBeginCHROMIUM(const char* name) {
3543 GPU_CLIENT_SINGLE_THREAD_CHECK();
3544 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
3545 << name << ")");
3546 if (current_trace_name_.get()) {
3547 SetGLError(GL_INVALID_OPERATION, "glTraceBeginCHROMIUM",
3548 "trace already running");
3549 return;
3551 TRACE_EVENT_COPY_ASYNC_BEGIN0("gpu", name, this);
3552 SetBucketAsCString(kResultBucketId, name);
3553 helper_->TraceBeginCHROMIUM(kResultBucketId);
3554 helper_->SetBucketSize(kResultBucketId, 0);
3555 current_trace_name_.reset(new std::string(name));
3558 void GLES2Implementation::TraceEndCHROMIUM() {
3559 GPU_CLIENT_SINGLE_THREAD_CHECK();
3560 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
3561 if (!current_trace_name_.get()) {
3562 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
3563 "missing begin trace");
3564 return;
3566 helper_->TraceEndCHROMIUM();
3567 TRACE_EVENT_COPY_ASYNC_END0("gpu", current_trace_name_->c_str(), this);
3568 current_trace_name_.reset();
3571 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
3572 GPU_CLIENT_SINGLE_THREAD_CHECK();
3573 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
3574 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
3575 switch (target) {
3576 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3577 if (access != GL_READ_ONLY) {
3578 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3579 return NULL;
3581 break;
3582 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3583 if (access != GL_WRITE_ONLY) {
3584 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3585 return NULL;
3587 break;
3588 default:
3589 SetGLError(
3590 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
3591 return NULL;
3593 GLuint buffer_id;
3594 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
3595 if (!buffer_id) {
3596 return NULL;
3598 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3599 if (!buffer) {
3600 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
3601 return NULL;
3603 if (buffer->mapped()) {
3604 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
3605 return NULL;
3607 // Here we wait for previous transfer operations to be finished.
3608 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
3609 // with this method of synchronization. Until this is fixed,
3610 // MapBufferCHROMIUM will not block even if the transfer is not ready
3611 // for these calls.
3612 if (buffer->transfer_ready_token()) {
3613 helper_->WaitForToken(buffer->transfer_ready_token());
3614 buffer->set_transfer_ready_token(0);
3616 buffer->set_mapped(true);
3618 GPU_CLIENT_LOG(" returned " << buffer->address());
3619 CheckGLError();
3620 return buffer->address();
3623 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
3624 GPU_CLIENT_SINGLE_THREAD_CHECK();
3625 GPU_CLIENT_LOG(
3626 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
3627 GLuint buffer_id;
3628 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
3629 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
3631 if (!buffer_id) {
3632 return false;
3634 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3635 if (!buffer) {
3636 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
3637 return false;
3639 if (!buffer->mapped()) {
3640 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
3641 return false;
3643 buffer->set_mapped(false);
3644 CheckGLError();
3645 return true;
3648 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
3649 GLenum target, GLint level, GLint internalformat, GLsizei width,
3650 GLsizei height, GLint border, GLenum format, GLenum type,
3651 const void* pixels) {
3652 GPU_CLIENT_SINGLE_THREAD_CHECK();
3653 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
3654 << GLES2Util::GetStringTextureTarget(target) << ", "
3655 << level << ", "
3656 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
3657 << width << ", " << height << ", " << border << ", "
3658 << GLES2Util::GetStringTextureFormat(format) << ", "
3659 << GLES2Util::GetStringPixelType(type) << ", "
3660 << static_cast<const void*>(pixels) << ")");
3661 if (level < 0 || height < 0 || width < 0) {
3662 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
3663 return;
3665 uint32 size;
3666 uint32 unpadded_row_size;
3667 uint32 padded_row_size;
3668 if (!GLES2Util::ComputeImageDataSizes(
3669 width, height, format, type, unpack_alignment_, &size,
3670 &unpadded_row_size, &padded_row_size)) {
3671 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
3672 return;
3675 // If there's no data/buffer just issue the AsyncTexImage2D
3676 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
3677 helper_->AsyncTexImage2DCHROMIUM(
3678 target, level, internalformat, width, height, border, format, type,
3679 0, 0);
3680 return;
3683 // Otherwise, async uploads require a transfer buffer to be bound.
3684 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3685 // the buffer before the transfer is finished. (Currently such
3686 // synchronization has to be handled manually.)
3687 GLuint offset = ToGLuint(pixels);
3688 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3689 bound_pixel_unpack_transfer_buffer_id_,
3690 "glAsyncTexImage2DCHROMIUM", offset, size);
3691 if (buffer && buffer->shm_id() != -1) {
3692 helper_->AsyncTexImage2DCHROMIUM(
3693 target, level, internalformat, width, height, border, format, type,
3694 buffer->shm_id(), buffer->shm_offset() + offset);
3698 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
3699 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
3700 GLsizei height, GLenum format, GLenum type, const void* pixels) {
3701 GPU_CLIENT_SINGLE_THREAD_CHECK();
3702 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
3703 << GLES2Util::GetStringTextureTarget(target) << ", "
3704 << level << ", "
3705 << xoffset << ", " << yoffset << ", "
3706 << width << ", " << height << ", "
3707 << GLES2Util::GetStringTextureFormat(format) << ", "
3708 << GLES2Util::GetStringPixelType(type) << ", "
3709 << static_cast<const void*>(pixels) << ")");
3710 if (level < 0 || height < 0 || width < 0) {
3711 SetGLError(
3712 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
3713 return;
3716 uint32 size;
3717 uint32 unpadded_row_size;
3718 uint32 padded_row_size;
3719 if (!GLES2Util::ComputeImageDataSizes(
3720 width, height, format, type, unpack_alignment_, &size,
3721 &unpadded_row_size, &padded_row_size)) {
3722 SetGLError(
3723 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
3724 return;
3727 // Async uploads require a transfer buffer to be bound.
3728 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3729 // the buffer before the transfer is finished. (Currently such
3730 // synchronization has to be handled manually.)
3731 GLuint offset = ToGLuint(pixels);
3732 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3733 bound_pixel_unpack_transfer_buffer_id_,
3734 "glAsyncTexSubImage2DCHROMIUM", offset, size);
3735 if (buffer && buffer->shm_id() != -1) {
3736 helper_->AsyncTexSubImage2DCHROMIUM(
3737 target, level, xoffset, yoffset, width, height, format, type,
3738 buffer->shm_id(), buffer->shm_offset() + offset);
3742 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
3743 GPU_CLIENT_SINGLE_THREAD_CHECK();
3744 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
3745 << GLES2Util::GetStringTextureTarget(target) << ")");
3746 helper_->WaitAsyncTexImage2DCHROMIUM(target);
3747 CheckGLError();
3750 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
3751 GPU_CLIENT_SINGLE_THREAD_CHECK();
3752 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
3753 helper_->CommandBufferHelper::Flush();
3754 return gpu_control_->InsertSyncPoint();
3757 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(
3758 GLsizei width, GLsizei height, GLenum internalformat) {
3759 if (width <= 0) {
3760 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
3761 return 0;
3764 if (height <= 0) {
3765 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
3766 return 0;
3768 // Flush the command stream to ensure ordering in case the newly
3769 // returned image_id has recently been in use with a different buffer.
3770 helper_->CommandBufferHelper::Flush();
3772 // Create new buffer.
3773 GLuint buffer_id = gpu_memory_buffer_tracker_->CreateBuffer(
3774 width, height, internalformat);
3775 if (buffer_id == 0) {
3776 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "out of GPU memory.");
3777 return 0;
3779 return buffer_id;
3782 GLuint GLES2Implementation::CreateImageCHROMIUM(
3783 GLsizei width, GLsizei height, GLenum internalformat) {
3784 GPU_CLIENT_SINGLE_THREAD_CHECK();
3785 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM("
3786 << width << ", "
3787 << height << ", "
3788 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ")");
3789 GLuint image_id = CreateImageCHROMIUMHelper(width, height, internalformat);
3790 CheckGLError();
3791 return image_id;
3794 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
3795 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3796 image_id);
3797 if (!gpu_buffer) {
3798 SetGLError(GL_INVALID_OPERATION, "glDestroyImageCHROMIUM", "invalid image");
3799 return;
3802 // Flush the command stream to make sure all pending commands
3803 // that may refer to the image_id are executed on the service side.
3804 helper_->CommandBufferHelper::Flush();
3805 gpu_memory_buffer_tracker_->RemoveBuffer(image_id);
3808 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
3809 GPU_CLIENT_SINGLE_THREAD_CHECK();
3810 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
3811 << image_id << ")");
3812 DestroyImageCHROMIUMHelper(image_id);
3813 CheckGLError();
3816 void GLES2Implementation::UnmapImageCHROMIUMHelper(GLuint image_id) {
3817 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3818 image_id);
3819 if (!gpu_buffer) {
3820 SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "invalid image");
3821 return;
3824 if (!gpu_buffer->IsMapped()) {
3825 SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "not mapped");
3826 return;
3828 gpu_buffer->Unmap();
3831 void GLES2Implementation::UnmapImageCHROMIUM(GLuint image_id) {
3832 GPU_CLIENT_SINGLE_THREAD_CHECK();
3833 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapImageCHROMIUM("
3834 << image_id << ")");
3836 UnmapImageCHROMIUMHelper(image_id);
3837 CheckGLError();
3840 void* GLES2Implementation::MapImageCHROMIUMHelper(GLuint image_id,
3841 GLenum access) {
3842 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3843 image_id);
3844 if (!gpu_buffer) {
3845 SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "invalid image");
3846 return NULL;
3848 gfx::GpuMemoryBuffer::AccessMode mode;
3849 switch(access) {
3850 case GL_WRITE_ONLY:
3851 mode = gfx::GpuMemoryBuffer::WRITE_ONLY;
3852 break;
3853 case GL_READ_ONLY:
3854 mode = gfx::GpuMemoryBuffer::READ_ONLY;
3855 break;
3856 case GL_READ_WRITE:
3857 mode = gfx::GpuMemoryBuffer::READ_WRITE;
3858 break;
3859 default:
3860 SetGLError(GL_INVALID_ENUM, "glMapImageCHROMIUM",
3861 "invalid GPU access mode");
3862 return NULL;
3865 if (gpu_buffer->IsMapped()) {
3866 SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "already mapped");
3867 return NULL;
3870 void* mapped_buffer = NULL;
3871 gpu_buffer->Map(mode, &mapped_buffer);
3872 return mapped_buffer;
3875 void* GLES2Implementation::MapImageCHROMIUM(
3876 GLuint image_id, GLenum access) {
3877 GPU_CLIENT_SINGLE_THREAD_CHECK();
3878 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapImageCHROMIUM("
3879 << image_id << ", "
3880 << GLES2Util::GetStringEnum(access) << ")");
3882 void* mapped = MapImageCHROMIUMHelper(image_id, access);
3883 CheckGLError();
3884 return mapped;
3887 void GLES2Implementation::GetImageParameterivCHROMIUMHelper(
3888 GLuint image_id, GLenum pname, GLint* params) {
3889 if (pname != GL_IMAGE_ROWBYTES_CHROMIUM) {
3890 SetGLError(GL_INVALID_ENUM, "glGetImageParameterivCHROMIUM",
3891 "invalid parameter");
3892 return;
3895 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3896 image_id);
3897 if (!gpu_buffer) {
3898 SetGLError(GL_INVALID_OPERATION, "glGetImageParameterivCHROMIUM",
3899 "invalid image");
3900 return;
3903 *params = gpu_buffer->GetStride();
3906 void GLES2Implementation::GetImageParameterivCHROMIUM(
3907 GLuint image_id, GLenum pname, GLint* params) {
3908 GPU_CLIENT_SINGLE_THREAD_CHECK();
3909 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
3910 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glImageParameterivCHROMIUM("
3911 << image_id << ", "
3912 << GLES2Util::GetStringBufferParameter(pname) << ", "
3913 << static_cast<const void*>(params) << ")");
3914 GetImageParameterivCHROMIUMHelper(image_id, pname, params);
3915 CheckGLError();
3918 // Include the auto-generated part of this file. We split this because it means
3919 // we can easily edit the non-auto generated parts right here in this file
3920 // instead of having to edit some template or the code generator.
3921 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
3923 } // namespace gles2
3924 } // namespace gpu