cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / gpu / command_buffer / client / gles2_implementation.cc
blob0fde7d8b985652ae955d10fa59d06614e24a456b
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/trace_event.h"
26 #include "ui/gfx/gpu_memory_buffer.h"
28 #if defined(__native_client__) && !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
29 #define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS
30 #endif
32 #if defined(GPU_CLIENT_DEBUG)
33 #include "ui/gl/gl_switches.h"
34 #include "base/command_line.h"
35 #endif
37 namespace gpu {
38 namespace gles2 {
40 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
41 static GLuint ToGLuint(const void* ptr) {
42 return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
45 #if !defined(_MSC_VER)
46 const size_t GLES2Implementation::kMaxSizeOfSimpleResult;
47 const unsigned int GLES2Implementation::kStartingOffset;
48 #endif
50 GLES2Implementation::GLStaticState::GLStaticState() {
53 GLES2Implementation::GLStaticState::~GLStaticState() {
56 GLES2Implementation::GLStaticState::IntState::IntState()
57 : max_combined_texture_image_units(0),
58 max_cube_map_texture_size(0),
59 max_fragment_uniform_vectors(0),
60 max_renderbuffer_size(0),
61 max_texture_image_units(0),
62 max_texture_size(0),
63 max_varying_vectors(0),
64 max_vertex_attribs(0),
65 max_vertex_texture_image_units(0),
66 max_vertex_uniform_vectors(0),
67 num_compressed_texture_formats(0),
68 num_shader_binary_formats(0) {
71 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
72 GLES2Implementation* gles2_implementation)
73 : gles2_implementation_(gles2_implementation) {
74 GPU_CHECK_EQ(0, gles2_implementation_->use_count_);
75 ++gles2_implementation_->use_count_;
78 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
79 --gles2_implementation_->use_count_;
80 GPU_CHECK_EQ(0, gles2_implementation_->use_count_);
83 GLES2Implementation::GLES2Implementation(
84 GLES2CmdHelper* helper,
85 ShareGroup* share_group,
86 TransferBufferInterface* transfer_buffer,
87 bool bind_generates_resource,
88 GpuControl* gpu_control)
89 : helper_(helper),
90 transfer_buffer_(transfer_buffer),
91 angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
92 chromium_framebuffer_multisample_(kUnknownExtensionStatus),
93 pack_alignment_(4),
94 unpack_alignment_(4),
95 unpack_flip_y_(false),
96 unpack_row_length_(0),
97 unpack_skip_rows_(0),
98 unpack_skip_pixels_(0),
99 pack_reverse_row_order_(false),
100 active_texture_unit_(0),
101 bound_framebuffer_(0),
102 bound_read_framebuffer_(0),
103 bound_renderbuffer_(0),
104 current_program_(0),
105 bound_array_buffer_id_(0),
106 bound_pixel_pack_transfer_buffer_id_(0),
107 bound_pixel_unpack_transfer_buffer_id_(0),
108 error_bits_(0),
109 debug_(false),
110 use_count_(0),
111 current_query_(NULL),
112 error_message_callback_(NULL),
113 gpu_control_(gpu_control) {
114 GPU_DCHECK(helper);
115 GPU_DCHECK(transfer_buffer);
117 char temp[128];
118 sprintf(temp, "%p", static_cast<void*>(this));
119 this_in_hex_ = std::string(temp);
121 GPU_CLIENT_LOG_CODE_BLOCK({
122 debug_ = CommandLine::ForCurrentProcess()->HasSwitch(
123 switches::kEnableGPUClientLogging);
126 share_group_ =
127 (share_group ? share_group : new ShareGroup(bind_generates_resource));
129 memset(&reserved_ids_, 0, sizeof(reserved_ids_));
132 bool GLES2Implementation::Initialize(
133 unsigned int starting_transfer_buffer_size,
134 unsigned int min_transfer_buffer_size,
135 unsigned int max_transfer_buffer_size,
136 unsigned int mapped_memory_limit) {
137 GPU_DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
138 GPU_DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
139 GPU_DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
141 if (!transfer_buffer_->Initialize(
142 starting_transfer_buffer_size,
143 kStartingOffset,
144 min_transfer_buffer_size,
145 max_transfer_buffer_size,
146 kAlignment,
147 kSizeToFlush)) {
148 return false;
151 mapped_memory_.reset(new MappedMemoryManager(helper_, mapped_memory_limit));
152 mapped_memory_->set_chunk_size_multiple(2 * 1024 * 1024);
154 if (!QueryAndCacheStaticState())
155 return false;
157 util_.set_num_compressed_texture_formats(
158 static_state_.int_state.num_compressed_texture_formats);
159 util_.set_num_shader_binary_formats(
160 static_state_.int_state.num_shader_binary_formats);
162 texture_units_.reset(
163 new TextureUnit[
164 static_state_.int_state.max_combined_texture_image_units]);
166 query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
167 buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
168 gpu_memory_buffer_tracker_.reset(new GpuMemoryBufferTracker(gpu_control_));
170 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
171 GetIdHandler(id_namespaces::kBuffers)->MakeIds(
172 this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
173 #endif
175 vertex_array_object_manager_.reset(new VertexArrayObjectManager(
176 static_state_.int_state.max_vertex_attribs,
177 reserved_ids_[0],
178 reserved_ids_[1]));
180 return true;
183 bool GLES2Implementation::QueryAndCacheStaticState() {
184 // Setup query for multiple GetIntegerv's
185 static const GLenum pnames[] = {
186 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
187 GL_MAX_CUBE_MAP_TEXTURE_SIZE,
188 GL_MAX_FRAGMENT_UNIFORM_VECTORS,
189 GL_MAX_RENDERBUFFER_SIZE,
190 GL_MAX_TEXTURE_IMAGE_UNITS,
191 GL_MAX_TEXTURE_SIZE,
192 GL_MAX_VARYING_VECTORS,
193 GL_MAX_VERTEX_ATTRIBS,
194 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
195 GL_MAX_VERTEX_UNIFORM_VECTORS,
196 GL_NUM_COMPRESSED_TEXTURE_FORMATS,
197 GL_NUM_SHADER_BINARY_FORMATS,
200 GetMultipleIntegervState integerv_state(
201 pnames, arraysize(pnames),
202 &static_state_.int_state.max_combined_texture_image_units,
203 sizeof(static_state_.int_state));
204 if (!GetMultipleIntegervSetup(&integerv_state)) {
205 return false;
208 // Setup query for multiple GetShaderPrecisionFormat's
209 static const GLenum precision_params[][2] = {
210 { GL_VERTEX_SHADER, GL_LOW_INT },
211 { GL_VERTEX_SHADER, GL_MEDIUM_INT },
212 { GL_VERTEX_SHADER, GL_HIGH_INT },
213 { GL_VERTEX_SHADER, GL_LOW_FLOAT },
214 { GL_VERTEX_SHADER, GL_MEDIUM_FLOAT },
215 { GL_VERTEX_SHADER, GL_HIGH_FLOAT },
216 { GL_FRAGMENT_SHADER, GL_LOW_INT },
217 { GL_FRAGMENT_SHADER, GL_MEDIUM_INT },
218 { GL_FRAGMENT_SHADER, GL_HIGH_INT },
219 { GL_FRAGMENT_SHADER, GL_LOW_FLOAT },
220 { GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT },
221 { GL_FRAGMENT_SHADER, GL_HIGH_FLOAT },
224 GetAllShaderPrecisionFormatsState precision_state(
225 precision_params, arraysize(precision_params));
226 GetAllShaderPrecisionFormatsSetup(&precision_state);
228 // Allocate and partition transfer buffer for all requests
229 void* buffer = transfer_buffer_->Alloc(
230 integerv_state.transfer_buffer_size_needed +
231 precision_state.transfer_buffer_size_needed);
232 if (!buffer) {
233 SetGLError(GL_OUT_OF_MEMORY, "QueryAndCacheStaticState",
234 "Transfer buffer allocation failed.");
235 return false;
237 integerv_state.buffer = buffer;
238 precision_state.results_buffer =
239 static_cast<char*>(buffer) + integerv_state.transfer_buffer_size_needed;
241 // Make all the requests and wait once for all the results.
242 GetMultipleIntegervRequest(&integerv_state);
243 GetAllShaderPrecisionFormatsRequest(&precision_state);
244 WaitForCmd();
245 GetMultipleIntegervOnCompleted(&integerv_state);
246 GetAllShaderPrecisionFormatsOnCompleted(&precision_state);
248 // TODO(gman): We should be able to free without a token.
249 transfer_buffer_->FreePendingToken(buffer, helper_->InsertToken());
250 CheckGLError();
252 return true;
255 GLES2Implementation::~GLES2Implementation() {
256 // Make sure the queries are finished otherwise we'll delete the
257 // shared memory (mapped_memory_) which will free the memory used
258 // by the queries. The GPU process when validating that memory is still
259 // shared will fail and abort (ie, it will stop running).
260 WaitForCmd();
261 query_tracker_.reset();
263 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
264 DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
265 #endif
266 buffer_tracker_.reset();
268 // Make sure the commands make it the service.
269 WaitForCmd();
272 GLES2CmdHelper* GLES2Implementation::helper() const {
273 return helper_;
276 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
277 return share_group_->GetIdHandler(namespace_id);
280 void* GLES2Implementation::GetResultBuffer() {
281 return transfer_buffer_->GetResultBuffer();
284 int32 GLES2Implementation::GetResultShmId() {
285 return transfer_buffer_->GetShmId();
288 uint32 GLES2Implementation::GetResultShmOffset() {
289 return transfer_buffer_->GetResultOffset();
292 void GLES2Implementation::FreeUnusedSharedMemory() {
293 mapped_memory_->FreeUnused();
296 void GLES2Implementation::FreeEverything() {
297 WaitForCmd();
298 query_tracker_->Shrink();
299 FreeUnusedSharedMemory();
300 transfer_buffer_->Free();
301 helper_->FreeRingBuffer();
304 void GLES2Implementation::WaitForCmd() {
305 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
306 helper_->CommandBufferHelper::Finish();
309 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
310 const char* extensions =
311 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
312 if (!extensions)
313 return false;
315 int length = strlen(ext);
316 while (true) {
317 int n = strcspn(extensions, " ");
318 if (n == length && 0 == strncmp(ext, extensions, length)) {
319 return true;
321 if ('\0' == extensions[n]) {
322 return false;
324 extensions += n + 1;
328 bool GLES2Implementation::IsExtensionAvailableHelper(
329 const char* extension, ExtensionStatus* status) {
330 switch (*status) {
331 case kAvailableExtensionStatus:
332 return true;
333 case kUnavailableExtensionStatus:
334 return false;
335 default: {
336 bool available = IsExtensionAvailable(extension);
337 *status = available ? kAvailableExtensionStatus :
338 kUnavailableExtensionStatus;
339 return available;
344 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
345 return IsExtensionAvailableHelper(
346 "GL_ANGLE_pack_reverse_row_order",
347 &angle_pack_reverse_row_order_status_);
350 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
351 return IsExtensionAvailableHelper(
352 "GL_CHROMIUM_framebuffer_multisample",
353 &chromium_framebuffer_multisample_);
356 const std::string& GLES2Implementation::GetLogPrefix() const {
357 const std::string& prefix(debug_marker_manager_.GetMarker());
358 return prefix.empty() ? this_in_hex_ : prefix;
361 GLenum GLES2Implementation::GetError() {
362 GPU_CLIENT_SINGLE_THREAD_CHECK();
363 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
364 GLenum err = GetGLError();
365 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
366 return err;
369 GLenum GLES2Implementation::GetClientSideGLError() {
370 if (error_bits_ == 0) {
371 return GL_NO_ERROR;
374 GLenum error = GL_NO_ERROR;
375 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
376 if ((error_bits_ & mask) != 0) {
377 error = GLES2Util::GLErrorBitToGLError(mask);
378 break;
381 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
382 return error;
385 GLenum GLES2Implementation::GetGLError() {
386 TRACE_EVENT0("gpu", "GLES2::GetGLError");
387 // Check the GL error first, then our wrapped error.
388 typedef cmds::GetError::Result Result;
389 Result* result = GetResultAs<Result*>();
390 // If we couldn't allocate a result the context is lost.
391 if (!result) {
392 return GL_NO_ERROR;
394 *result = GL_NO_ERROR;
395 helper_->GetError(GetResultShmId(), GetResultShmOffset());
396 WaitForCmd();
397 GLenum error = *result;
398 if (error == GL_NO_ERROR) {
399 error = GetClientSideGLError();
400 } else {
401 // There was an error, clear the corresponding wrapped error.
402 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
404 return error;
407 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
408 void GLES2Implementation::FailGLError(GLenum error) {
409 if (error != GL_NO_ERROR) {
410 GPU_NOTREACHED() << "Error";
413 // NOTE: Calling GetGLError overwrites data in the result buffer.
414 void GLES2Implementation::CheckGLError() {
415 FailGLError(GetGLError());
417 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
419 void GLES2Implementation::SetGLError(
420 GLenum error, const char* function_name, const char* msg) {
421 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
422 << GLES2Util::GetStringError(error) << ": "
423 << function_name << ": " << msg);
424 FailGLError(error);
425 if (msg) {
426 last_error_ = msg;
428 if (error_message_callback_) {
429 std::string temp(GLES2Util::GetStringError(error) + " : " +
430 function_name + ": " + (msg ? msg : ""));
431 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
433 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
436 void GLES2Implementation::SetGLErrorInvalidEnum(
437 const char* function_name, GLenum value, const char* label) {
438 SetGLError(GL_INVALID_ENUM, function_name,
439 (std::string(label) + " was " +
440 GLES2Util::GetStringEnum(value)).c_str());
443 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
444 std::vector<int8>* data) {
445 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
446 GPU_DCHECK(data);
447 const uint32 kStartSize = 32 * 1024;
448 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
449 if (!buffer.valid()) {
450 return false;
452 typedef cmd::GetBucketStart::Result Result;
453 Result* result = GetResultAs<Result*>();
454 if (!result) {
455 return false;
457 *result = 0;
458 helper_->GetBucketStart(
459 bucket_id, GetResultShmId(), GetResultShmOffset(),
460 buffer.size(), buffer.shm_id(), buffer.offset());
461 WaitForCmd();
462 uint32 size = *result;
463 data->resize(size);
464 if (size > 0u) {
465 uint32 offset = 0;
466 while (size) {
467 if (!buffer.valid()) {
468 buffer.Reset(size);
469 if (!buffer.valid()) {
470 return false;
472 helper_->GetBucketData(
473 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
474 WaitForCmd();
476 uint32 size_to_copy = std::min(size, buffer.size());
477 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
478 offset += size_to_copy;
479 size -= size_to_copy;
480 buffer.Release();
482 // Free the bucket. This is not required but it does free up the memory.
483 // and we don't have to wait for the result so from the client's perspective
484 // it's cheap.
485 helper_->SetBucketSize(bucket_id, 0);
487 return true;
490 void GLES2Implementation::SetBucketContents(
491 uint32 bucket_id, const void* data, size_t size) {
492 GPU_DCHECK(data);
493 helper_->SetBucketSize(bucket_id, size);
494 if (size > 0u) {
495 uint32 offset = 0;
496 while (size) {
497 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
498 if (!buffer.valid()) {
499 return;
501 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
502 buffer.size());
503 helper_->SetBucketData(
504 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
505 offset += buffer.size();
506 size -= buffer.size();
511 void GLES2Implementation::SetBucketAsCString(
512 uint32 bucket_id, const char* str) {
513 // NOTE: strings are passed NULL terminated. That means the empty
514 // string will have a size of 1 and no-string will have a size of 0
515 if (str) {
516 SetBucketContents(bucket_id, str, strlen(str) + 1);
517 } else {
518 helper_->SetBucketSize(bucket_id, 0);
522 bool GLES2Implementation::GetBucketAsString(
523 uint32 bucket_id, std::string* str) {
524 GPU_DCHECK(str);
525 std::vector<int8> data;
526 // NOTE: strings are passed NULL terminated. That means the empty
527 // string will have a size of 1 and no-string will have a size of 0
528 if (!GetBucketContents(bucket_id, &data)) {
529 return false;
531 if (data.empty()) {
532 return false;
534 str->assign(&data[0], &data[0] + data.size() - 1);
535 return true;
538 void GLES2Implementation::SetBucketAsString(
539 uint32 bucket_id, const std::string& str) {
540 // NOTE: strings are passed NULL terminated. That means the empty
541 // string will have a size of 1 and no-string will have a size of 0
542 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
545 void GLES2Implementation::Disable(GLenum cap) {
546 GPU_CLIENT_SINGLE_THREAD_CHECK();
547 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
548 << GLES2Util::GetStringCapability(cap) << ")");
549 bool changed = false;
550 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
551 helper_->Disable(cap);
553 CheckGLError();
556 void GLES2Implementation::Enable(GLenum cap) {
557 GPU_CLIENT_SINGLE_THREAD_CHECK();
558 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
559 << GLES2Util::GetStringCapability(cap) << ")");
560 bool changed = false;
561 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
562 helper_->Enable(cap);
564 CheckGLError();
567 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
568 GPU_CLIENT_SINGLE_THREAD_CHECK();
569 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
570 << GLES2Util::GetStringCapability(cap) << ")");
571 bool state = false;
572 if (!state_.GetEnabled(cap, &state)) {
573 typedef cmds::IsEnabled::Result Result;
574 Result* result = GetResultAs<Result*>();
575 if (!result) {
576 return GL_FALSE;
578 *result = 0;
579 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
580 WaitForCmd();
581 state = (*result) != 0;
584 GPU_CLIENT_LOG("returned " << state);
585 CheckGLError();
586 return state;
589 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
590 switch (pname) {
591 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
592 *params = static_state_.int_state.max_combined_texture_image_units;
593 return true;
594 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
595 *params = static_state_.int_state.max_cube_map_texture_size;
596 return true;
597 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
598 *params = static_state_.int_state.max_fragment_uniform_vectors;
599 return true;
600 case GL_MAX_RENDERBUFFER_SIZE:
601 *params = static_state_.int_state.max_renderbuffer_size;
602 return true;
603 case GL_MAX_TEXTURE_IMAGE_UNITS:
604 *params = static_state_.int_state.max_texture_image_units;
605 return true;
606 case GL_MAX_TEXTURE_SIZE:
607 *params = static_state_.int_state.max_texture_size;
608 return true;
609 case GL_MAX_VARYING_VECTORS:
610 *params = static_state_.int_state.max_varying_vectors;
611 return true;
612 case GL_MAX_VERTEX_ATTRIBS:
613 *params = static_state_.int_state.max_vertex_attribs;
614 return true;
615 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
616 *params = static_state_.int_state.max_vertex_texture_image_units;
617 return true;
618 case GL_MAX_VERTEX_UNIFORM_VECTORS:
619 *params = static_state_.int_state.max_vertex_uniform_vectors;
620 return true;
621 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
622 *params = static_state_.int_state.num_compressed_texture_formats;
623 return true;
624 case GL_NUM_SHADER_BINARY_FORMATS:
625 *params = static_state_.int_state.num_shader_binary_formats;
626 return true;
627 case GL_ARRAY_BUFFER_BINDING:
628 if (share_group_->bind_generates_resource()) {
629 *params = bound_array_buffer_id_;
630 return true;
632 return false;
633 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
634 if (share_group_->bind_generates_resource()) {
635 *params =
636 vertex_array_object_manager_->bound_element_array_buffer();
637 return true;
639 return false;
640 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
641 *params = bound_pixel_pack_transfer_buffer_id_;
642 return true;
643 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
644 *params = bound_pixel_unpack_transfer_buffer_id_;
645 return true;
646 case GL_ACTIVE_TEXTURE:
647 *params = active_texture_unit_ + GL_TEXTURE0;
648 return true;
649 case GL_TEXTURE_BINDING_2D:
650 if (share_group_->bind_generates_resource()) {
651 *params = texture_units_[active_texture_unit_].bound_texture_2d;
652 return true;
654 return false;
655 case GL_TEXTURE_BINDING_CUBE_MAP:
656 if (share_group_->bind_generates_resource()) {
657 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
658 return true;
660 return false;
661 case GL_FRAMEBUFFER_BINDING:
662 if (share_group_->bind_generates_resource()) {
663 *params = bound_framebuffer_;
664 return true;
666 return false;
667 case GL_READ_FRAMEBUFFER_BINDING:
668 if (IsChromiumFramebufferMultisampleAvailable() &&
669 share_group_->bind_generates_resource()) {
670 *params = bound_read_framebuffer_;
671 return true;
673 return false;
674 case GL_RENDERBUFFER_BINDING:
675 if (share_group_->bind_generates_resource()) {
676 *params = bound_renderbuffer_;
677 return true;
679 return false;
680 default:
681 return false;
685 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
686 // TODO(gman): Make this handle pnames that return more than 1 value.
687 GLint value;
688 if (!GetHelper(pname, &value)) {
689 return false;
691 *params = static_cast<GLboolean>(value);
692 return true;
695 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
696 // TODO(gman): Make this handle pnames that return more than 1 value.
697 GLint value;
698 if (!GetHelper(pname, &value)) {
699 return false;
701 *params = static_cast<GLfloat>(value);
702 return true;
705 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
706 return GetHelper(pname, params);
709 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
710 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
711 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
712 Result* result = GetResultAs<Result*>();
713 if (!result) {
714 return 0;
716 *result = 0;
717 helper_->GetMaxValueInBufferCHROMIUM(
718 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
719 WaitForCmd();
720 return *result;
723 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
724 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
725 GPU_CLIENT_SINGLE_THREAD_CHECK();
726 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
727 << buffer_id << ", " << count << ", "
728 << GLES2Util::GetStringGetMaxIndexType(type)
729 << ", " << offset << ")");
730 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
731 buffer_id, count, type, offset);
732 GPU_CLIENT_LOG("returned " << result);
733 CheckGLError();
734 return result;
737 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
738 if (restore) {
739 RestoreArrayBuffer(restore);
740 // Restore the element array binding.
741 // We only need to restore it if it wasn't a client side array.
742 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
743 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
748 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
749 if (restore) {
750 // Restore the user's current binding.
751 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_);
755 void GLES2Implementation::DrawElements(
756 GLenum mode, GLsizei count, GLenum type, const void* indices) {
757 GPU_CLIENT_SINGLE_THREAD_CHECK();
758 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
759 << GLES2Util::GetStringDrawMode(mode) << ", "
760 << count << ", "
761 << GLES2Util::GetStringIndexType(type) << ", "
762 << static_cast<const void*>(indices) << ")");
763 if (count < 0) {
764 SetGLError(GL_INVALID_VALUE, "glDrawElements", "count less than 0.");
765 return;
767 if (count == 0) {
768 return;
770 GLuint offset = 0;
771 bool simulated = false;
772 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
773 "glDrawElements", this, helper_, count, type, 0, indices,
774 &offset, &simulated)) {
775 return;
777 helper_->DrawElements(mode, count, type, offset);
778 RestoreElementAndArrayBuffers(simulated);
779 CheckGLError();
782 void GLES2Implementation::Flush() {
783 GPU_CLIENT_SINGLE_THREAD_CHECK();
784 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
785 // Insert the cmd to call glFlush
786 helper_->Flush();
787 // Flush our command buffer
788 // (tell the service to execute up to the flush cmd.)
789 helper_->CommandBufferHelper::Flush();
792 void GLES2Implementation::ShallowFlushCHROMIUM() {
793 GPU_CLIENT_SINGLE_THREAD_CHECK();
794 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
795 // Flush our command buffer
796 // (tell the service to execute up to the flush cmd.)
797 helper_->CommandBufferHelper::Flush();
800 void GLES2Implementation::Finish() {
801 GPU_CLIENT_SINGLE_THREAD_CHECK();
802 FinishHelper();
805 void GLES2Implementation::ShallowFinishCHROMIUM() {
806 GPU_CLIENT_SINGLE_THREAD_CHECK();
807 // Flush our command buffer (tell the service to execute up to the flush cmd
808 // and don't return until it completes).
809 helper_->CommandBufferHelper::Finish();
812 bool GLES2Implementation::MustBeContextLost() {
813 bool context_lost = helper_->IsContextLost();
814 if (!context_lost) {
815 WaitForCmd();
816 context_lost = helper_->IsContextLost();
818 GPU_CHECK(context_lost);
819 return context_lost;
822 void GLES2Implementation::FinishHelper() {
823 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
824 TRACE_EVENT0("gpu", "GLES2::Finish");
825 // Insert the cmd to call glFinish
826 helper_->Finish();
827 // Finish our command buffer
828 // (tell the service to execute up to the Finish cmd and wait for it to
829 // execute.)
830 helper_->CommandBufferHelper::Finish();
833 void GLES2Implementation::SwapBuffers() {
834 GPU_CLIENT_SINGLE_THREAD_CHECK();
835 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
836 // TODO(piman): Strictly speaking we'd want to insert the token after the
837 // swap, but the state update with the updated token might not have happened
838 // by the time the SwapBuffer callback gets called, forcing us to synchronize
839 // with the GPU process more than needed. So instead, make it happen before.
840 // All it means is that we could be slightly looser on the kMaxSwapBuffers
841 // semantics if the client doesn't use the callback mechanism, and by chance
842 // the scheduler yields between the InsertToken and the SwapBuffers.
843 swap_buffers_tokens_.push(helper_->InsertToken());
844 helper_->SwapBuffers();
845 helper_->CommandBufferHelper::Flush();
846 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
847 // compensate for TODO above.
848 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
849 helper_->WaitForToken(swap_buffers_tokens_.front());
850 swap_buffers_tokens_.pop();
854 void GLES2Implementation::GenSharedIdsCHROMIUM(
855 GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) {
856 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenSharedIdsCHROMIUM("
857 << namespace_id << ", " << id_offset << ", " << n << ", " <<
858 static_cast<void*>(ids) << ")");
859 TRACE_EVENT0("gpu", "GLES2::GenSharedIdsCHROMIUM");
860 GLsizei num = n;
861 GLuint* dst = ids;
862 while (num) {
863 ScopedTransferBufferArray<GLint> id_buffer(num, helper_, transfer_buffer_);
864 if (!id_buffer.valid()) {
865 return;
867 helper_->GenSharedIdsCHROMIUM(
868 namespace_id, id_offset, id_buffer.num_elements(),
869 id_buffer.shm_id(), id_buffer.offset());
870 WaitForCmd();
871 memcpy(dst, id_buffer.address(), sizeof(*dst) * id_buffer.num_elements());
872 num -= id_buffer.num_elements();
873 dst += id_buffer.num_elements();
875 GPU_CLIENT_LOG_CODE_BLOCK({
876 for (GLsizei i = 0; i < n; ++i) {
877 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
882 void GLES2Implementation::DeleteSharedIdsCHROMIUM(
883 GLuint namespace_id, GLsizei n, const GLuint* ids) {
884 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteSharedIdsCHROMIUM("
885 << namespace_id << ", " << n << ", "
886 << static_cast<const void*>(ids) << ")");
887 GPU_CLIENT_LOG_CODE_BLOCK({
888 for (GLsizei i = 0; i < n; ++i) {
889 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
892 TRACE_EVENT0("gpu", "GLES2::DeleteSharedIdsCHROMIUM");
893 while (n) {
894 ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
895 if (!id_buffer.valid()) {
896 return;
898 memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
899 helper_->DeleteSharedIdsCHROMIUM(
900 namespace_id, id_buffer.num_elements(),
901 id_buffer.shm_id(), id_buffer.offset());
902 WaitForCmd();
903 n -= id_buffer.num_elements();
904 ids += id_buffer.num_elements();
908 void GLES2Implementation::RegisterSharedIdsCHROMIUM(
909 GLuint namespace_id, GLsizei n, const GLuint* ids) {
910 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRegisterSharedIdsCHROMIUM("
911 << namespace_id << ", " << n << ", "
912 << static_cast<const void*>(ids) << ")");
913 GPU_CLIENT_LOG_CODE_BLOCK({
914 for (GLsizei i = 0; i < n; ++i) {
915 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
918 TRACE_EVENT0("gpu", "GLES2::RegisterSharedIdsCHROMIUM");
919 while (n) {
920 ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
921 if (!id_buffer.valid()) {
922 return;
924 memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
925 helper_->RegisterSharedIdsCHROMIUM(
926 namespace_id, id_buffer.num_elements(),
927 id_buffer.shm_id(), id_buffer.offset());
928 WaitForCmd();
929 n -= id_buffer.num_elements();
930 ids += id_buffer.num_elements();
934 void GLES2Implementation::BindAttribLocation(
935 GLuint program, GLuint index, const char* name) {
936 GPU_CLIENT_SINGLE_THREAD_CHECK();
937 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
938 << program << ", " << index << ", " << name << ")");
939 SetBucketAsString(kResultBucketId, name);
940 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
941 helper_->SetBucketSize(kResultBucketId, 0);
942 CheckGLError();
945 void GLES2Implementation::BindUniformLocationCHROMIUM(
946 GLuint program, GLint location, const char* name) {
947 GPU_CLIENT_SINGLE_THREAD_CHECK();
948 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
949 << program << ", " << location << ", " << name << ")");
950 SetBucketAsString(kResultBucketId, name);
951 helper_->BindUniformLocationCHROMIUMBucket(
952 program, location, kResultBucketId);
953 helper_->SetBucketSize(kResultBucketId, 0);
954 CheckGLError();
957 void GLES2Implementation::GetVertexAttribPointerv(
958 GLuint index, GLenum pname, void** ptr) {
959 GPU_CLIENT_SINGLE_THREAD_CHECK();
960 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
961 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
962 << static_cast<void*>(ptr) << ")");
963 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
964 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
965 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
966 typedef cmds::GetVertexAttribPointerv::Result Result;
967 Result* result = GetResultAs<Result*>();
968 if (!result) {
969 return;
971 result->SetNumResults(0);
972 helper_->GetVertexAttribPointerv(
973 index, pname, GetResultShmId(), GetResultShmOffset());
974 WaitForCmd();
975 result->CopyResult(ptr);
976 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
978 GPU_CLIENT_LOG_CODE_BLOCK({
979 for (int32 i = 0; i < num_results; ++i) {
980 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
983 CheckGLError();
986 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
987 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
988 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
989 SetGLError(
990 GL_INVALID_VALUE,
991 "glDeleteProgram", "id not created by this context.");
992 return false;
994 if (program == current_program_) {
995 current_program_ = 0;
997 return true;
1000 void GLES2Implementation::DeleteProgramStub(
1001 GLsizei n, const GLuint* programs) {
1002 GPU_DCHECK_EQ(1, n);
1003 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1004 helper_->DeleteProgram(programs[0]);
1007 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1008 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1009 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1010 SetGLError(
1011 GL_INVALID_VALUE,
1012 "glDeleteShader", "id not created by this context.");
1013 return false;
1015 return true;
1018 void GLES2Implementation::DeleteShaderStub(
1019 GLsizei n, const GLuint* shaders) {
1020 GPU_DCHECK_EQ(1, n);
1021 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1022 helper_->DeleteShader(shaders[0]);
1026 GLint GLES2Implementation::GetAttribLocationHelper(
1027 GLuint program, const char* name) {
1028 typedef cmds::GetAttribLocationBucket::Result Result;
1029 Result* result = GetResultAs<Result*>();
1030 if (!result) {
1031 return -1;
1033 *result = -1;
1034 SetBucketAsCString(kResultBucketId, name);
1035 helper_->GetAttribLocationBucket(
1036 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1037 WaitForCmd();
1038 helper_->SetBucketSize(kResultBucketId, 0);
1039 return *result;
1042 GLint GLES2Implementation::GetAttribLocation(
1043 GLuint program, const char* name) {
1044 GPU_CLIENT_SINGLE_THREAD_CHECK();
1045 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1046 << ", " << name << ")");
1047 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1048 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1049 this, program, name);
1050 GPU_CLIENT_LOG("returned " << loc);
1051 CheckGLError();
1052 return loc;
1055 GLint GLES2Implementation::GetUniformLocationHelper(
1056 GLuint program, const char* name) {
1057 typedef cmds::GetUniformLocationBucket::Result Result;
1058 Result* result = GetResultAs<Result*>();
1059 if (!result) {
1060 return -1;
1062 *result = -1;
1063 SetBucketAsCString(kResultBucketId, name);
1064 helper_->GetUniformLocationBucket(program, kResultBucketId,
1065 GetResultShmId(), GetResultShmOffset());
1066 WaitForCmd();
1067 helper_->SetBucketSize(kResultBucketId, 0);
1068 return *result;
1071 GLint GLES2Implementation::GetUniformLocation(
1072 GLuint program, const char* name) {
1073 GPU_CLIENT_SINGLE_THREAD_CHECK();
1074 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1075 << ", " << name << ")");
1076 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1077 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1078 this, program, name);
1079 GPU_CLIENT_LOG("returned " << loc);
1080 CheckGLError();
1081 return loc;
1084 void GLES2Implementation::UseProgram(GLuint program) {
1085 GPU_CLIENT_SINGLE_THREAD_CHECK();
1086 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUseProgram(" << program << ")");
1087 if (current_program_ != program) {
1088 current_program_ = program;
1089 helper_->UseProgram(program);
1091 CheckGLError();
1094 bool GLES2Implementation::GetProgramivHelper(
1095 GLuint program, GLenum pname, GLint* params) {
1096 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1097 this, program, pname, params);
1098 GPU_CLIENT_LOG_CODE_BLOCK({
1099 if (got_value) {
1100 GPU_CLIENT_LOG(" 0: " << *params);
1103 return got_value;
1106 void GLES2Implementation::LinkProgram(GLuint program) {
1107 GPU_CLIENT_SINGLE_THREAD_CHECK();
1108 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1109 helper_->LinkProgram(program);
1110 share_group_->program_info_manager()->CreateInfo(program);
1111 CheckGLError();
1114 void GLES2Implementation::ShaderBinary(
1115 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1116 GLsizei length) {
1117 GPU_CLIENT_SINGLE_THREAD_CHECK();
1118 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1119 << static_cast<const void*>(shaders) << ", "
1120 << GLES2Util::GetStringEnum(binaryformat) << ", "
1121 << static_cast<const void*>(binary) << ", "
1122 << length << ")");
1123 if (n < 0) {
1124 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1125 return;
1127 if (length < 0) {
1128 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1129 return;
1131 // TODO(gman): ShaderBinary should use buckets.
1132 unsigned int shader_id_size = n * sizeof(*shaders);
1133 ScopedTransferBufferArray<GLint> buffer(
1134 shader_id_size + length, helper_, transfer_buffer_);
1135 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1136 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1137 return;
1139 void* shader_ids = buffer.elements();
1140 void* shader_data = buffer.elements() + shader_id_size;
1141 memcpy(shader_ids, shaders, shader_id_size);
1142 memcpy(shader_data, binary, length);
1143 helper_->ShaderBinary(
1145 buffer.shm_id(),
1146 buffer.offset(),
1147 binaryformat,
1148 buffer.shm_id(),
1149 buffer.offset() + shader_id_size,
1150 length);
1151 CheckGLError();
1154 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1155 GPU_CLIENT_SINGLE_THREAD_CHECK();
1156 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1157 << GLES2Util::GetStringPixelStore(pname) << ", "
1158 << param << ")");
1159 switch (pname) {
1160 case GL_PACK_ALIGNMENT:
1161 pack_alignment_ = param;
1162 break;
1163 case GL_UNPACK_ALIGNMENT:
1164 unpack_alignment_ = param;
1165 break;
1166 case GL_UNPACK_ROW_LENGTH:
1167 unpack_row_length_ = param;
1168 return;
1169 case GL_UNPACK_SKIP_ROWS:
1170 unpack_skip_rows_ = param;
1171 return;
1172 case GL_UNPACK_SKIP_PIXELS:
1173 unpack_skip_pixels_ = param;
1174 return;
1175 case GL_UNPACK_FLIP_Y_CHROMIUM:
1176 unpack_flip_y_ = (param != 0);
1177 break;
1178 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1179 pack_reverse_row_order_ =
1180 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1181 break;
1182 default:
1183 break;
1185 helper_->PixelStorei(pname, param);
1186 CheckGLError();
1190 void GLES2Implementation::VertexAttribPointer(
1191 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1192 const void* ptr) {
1193 GPU_CLIENT_SINGLE_THREAD_CHECK();
1194 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1195 << index << ", "
1196 << size << ", "
1197 << GLES2Util::GetStringVertexAttribType(type) << ", "
1198 << GLES2Util::GetStringBool(normalized) << ", "
1199 << stride << ", "
1200 << static_cast<const void*>(ptr) << ")");
1201 // Record the info on the client side.
1202 if (!vertex_array_object_manager_->SetAttribPointer(
1203 bound_array_buffer_id_, index, size, type, normalized, stride, ptr)) {
1204 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1205 "client side arrays are not allowed in vertex array objects.");
1206 return;
1208 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1209 if (bound_array_buffer_id_ != 0) {
1210 // Only report NON client side buffers to the service.
1211 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1212 ToGLuint(ptr));
1214 #else // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1215 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1216 ToGLuint(ptr));
1217 #endif // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1218 CheckGLError();
1221 void GLES2Implementation::VertexAttribDivisorANGLE(
1222 GLuint index, GLuint divisor) {
1223 GPU_CLIENT_SINGLE_THREAD_CHECK();
1224 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1225 << index << ", "
1226 << divisor << ") ");
1227 // Record the info on the client side.
1228 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1229 helper_->VertexAttribDivisorANGLE(index, divisor);
1230 CheckGLError();
1233 void GLES2Implementation::ShaderSource(
1234 GLuint shader, GLsizei count, const GLchar* const* source, const GLint* length) {
1235 GPU_CLIENT_SINGLE_THREAD_CHECK();
1236 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderSource("
1237 << shader << ", " << count << ", "
1238 << static_cast<const void*>(source) << ", "
1239 << static_cast<const void*>(length) << ")");
1240 GPU_CLIENT_LOG_CODE_BLOCK({
1241 for (GLsizei ii = 0; ii < count; ++ii) {
1242 if (source[ii]) {
1243 if (length && length[ii] >= 0) {
1244 std::string str(source[ii], length[ii]);
1245 GPU_CLIENT_LOG(" " << ii << ": ---\n" << str << "\n---");
1246 } else {
1247 GPU_CLIENT_LOG(" " << ii << ": ---\n" << source[ii] << "\n---");
1249 } else {
1250 GPU_CLIENT_LOG(" " << ii << ": NULL");
1254 if (count < 0) {
1255 SetGLError(GL_INVALID_VALUE, "glShaderSource", "count < 0");
1256 return;
1258 if (shader == 0) {
1259 SetGLError(GL_INVALID_VALUE, "glShaderSource", "shader == 0");
1260 return;
1263 // Compute the total size.
1264 uint32 total_size = 1;
1265 for (GLsizei ii = 0; ii < count; ++ii) {
1266 if (source[ii]) {
1267 total_size += (length && length[ii] >= 0) ?
1268 static_cast<size_t>(length[ii]) : strlen(source[ii]);
1272 // Concatenate all the strings in to a bucket on the service.
1273 helper_->SetBucketSize(kResultBucketId, total_size);
1274 uint32 offset = 0;
1275 for (GLsizei ii = 0; ii <= count; ++ii) {
1276 const char* src = ii < count ? source[ii] : "";
1277 if (src) {
1278 uint32 size = ii < count ?
1279 (length ? static_cast<size_t>(length[ii]) : strlen(src)) : 1;
1280 while (size) {
1281 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1282 if (!buffer.valid()) {
1283 return;
1285 memcpy(buffer.address(), src, buffer.size());
1286 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
1287 buffer.shm_id(), buffer.offset());
1288 offset += buffer.size();
1289 src += buffer.size();
1290 size -= buffer.size();
1295 GPU_DCHECK_EQ(total_size, offset);
1297 helper_->ShaderSourceBucket(shader, kResultBucketId);
1298 helper_->SetBucketSize(kResultBucketId, 0);
1299 CheckGLError();
1302 void GLES2Implementation::BufferDataHelper(
1303 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1304 if (size < 0) {
1305 SetGLError(GL_INVALID_VALUE, "glBufferData", "size < 0");
1306 return;
1309 GLuint buffer_id;
1310 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1311 if (!buffer_id) {
1312 return;
1315 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1316 if (buffer) {
1317 // Free buffer memory, pending the passage of a token.
1318 buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
1320 // Remove old buffer.
1321 buffer_tracker_->RemoveBuffer(buffer_id);
1324 // Create new buffer.
1325 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1326 GPU_DCHECK(buffer);
1327 if (buffer->address() && data)
1328 memcpy(buffer->address(), data, size);
1329 return;
1332 if (size == 0) {
1333 return;
1336 // If there is no data just send BufferData
1337 if (!data) {
1338 helper_->BufferData(target, size, 0, 0, usage);
1339 return;
1342 // See if we can send all at once.
1343 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1344 if (!buffer.valid()) {
1345 return;
1348 if (buffer.size() >= static_cast<unsigned int>(size)) {
1349 memcpy(buffer.address(), data, size);
1350 helper_->BufferData(
1351 target,
1352 size,
1353 buffer.shm_id(),
1354 buffer.offset(),
1355 usage);
1356 return;
1359 // Make the buffer with BufferData then send via BufferSubData
1360 helper_->BufferData(target, size, 0, 0, usage);
1361 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1362 CheckGLError();
1365 void GLES2Implementation::BufferData(
1366 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1367 GPU_CLIENT_SINGLE_THREAD_CHECK();
1368 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1369 << GLES2Util::GetStringBufferTarget(target) << ", "
1370 << size << ", "
1371 << static_cast<const void*>(data) << ", "
1372 << GLES2Util::GetStringBufferUsage(usage) << ")");
1373 BufferDataHelper(target, size, data, usage);
1374 CheckGLError();
1377 void GLES2Implementation::BufferSubDataHelper(
1378 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1379 if (size == 0) {
1380 return;
1383 if (size < 0) {
1384 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "size < 0");
1385 return;
1388 GLuint buffer_id;
1389 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1390 if (!buffer_id) {
1391 return;
1393 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1394 if (!buffer) {
1395 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1396 return;
1399 int32 end = 0;
1400 int32 buffer_size = buffer->size();
1401 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1402 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1403 return;
1406 if (buffer->address() && data)
1407 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1408 return;
1411 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1412 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1415 void GLES2Implementation::BufferSubDataHelperImpl(
1416 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1417 ScopedTransferBufferPtr* buffer) {
1418 GPU_DCHECK(buffer);
1419 GPU_DCHECK_GT(size, 0);
1421 const int8* source = static_cast<const int8*>(data);
1422 while (size) {
1423 if (!buffer->valid() || buffer->size() == 0) {
1424 buffer->Reset(size);
1425 if (!buffer->valid()) {
1426 return;
1429 memcpy(buffer->address(), source, buffer->size());
1430 helper_->BufferSubData(
1431 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1432 offset += buffer->size();
1433 source += buffer->size();
1434 size -= buffer->size();
1435 buffer->Release();
1439 void GLES2Implementation::BufferSubData(
1440 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1441 GPU_CLIENT_SINGLE_THREAD_CHECK();
1442 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1443 << GLES2Util::GetStringBufferTarget(target) << ", "
1444 << offset << ", " << size << ", "
1445 << static_cast<const void*>(data) << ")");
1446 BufferSubDataHelper(target, offset, size, data);
1447 CheckGLError();
1450 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1451 GLenum target,
1452 const char* function_name,
1453 GLuint* buffer_id) {
1454 *buffer_id = 0;
1456 switch (target) {
1457 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1458 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1459 break;
1460 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1461 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1462 break;
1463 default:
1464 // Unknown target
1465 return false;
1467 if (!*buffer_id) {
1468 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1470 return true;
1473 BufferTracker::Buffer*
1474 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1475 GLuint buffer_id,
1476 const char* function_name,
1477 GLuint offset, GLsizei size)
1479 DCHECK(buffer_id);
1480 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1481 if (!buffer) {
1482 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1483 return NULL;
1485 if (buffer->mapped()) {
1486 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1487 return NULL;
1489 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1490 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1491 return NULL;
1493 return buffer;
1496 void GLES2Implementation::CompressedTexImage2D(
1497 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1498 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1499 GPU_CLIENT_SINGLE_THREAD_CHECK();
1500 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1501 << GLES2Util::GetStringTextureTarget(target) << ", "
1502 << level << ", "
1503 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1504 << width << ", " << height << ", " << border << ", "
1505 << image_size << ", "
1506 << static_cast<const void*>(data) << ")");
1507 if (width < 0 || height < 0 || level < 0) {
1508 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1509 return;
1511 if (height == 0 || width == 0) {
1512 return;
1514 // If there's a pixel unpack buffer bound use it when issuing
1515 // CompressedTexImage2D.
1516 if (bound_pixel_unpack_transfer_buffer_id_) {
1517 GLuint offset = ToGLuint(data);
1518 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1519 bound_pixel_unpack_transfer_buffer_id_,
1520 "glCompressedTexImage2D", offset, image_size);
1521 if (buffer && buffer->shm_id() != -1) {
1522 helper_->CompressedTexImage2D(
1523 target, level, internalformat, width, height, border, image_size,
1524 buffer->shm_id(), buffer->shm_offset() + offset);
1525 buffer->set_transfer_ready_token(helper_->InsertToken());
1527 return;
1529 SetBucketContents(kResultBucketId, data, image_size);
1530 helper_->CompressedTexImage2DBucket(
1531 target, level, internalformat, width, height, border, kResultBucketId);
1532 // Free the bucket. This is not required but it does free up the memory.
1533 // and we don't have to wait for the result so from the client's perspective
1534 // it's cheap.
1535 helper_->SetBucketSize(kResultBucketId, 0);
1536 CheckGLError();
1539 void GLES2Implementation::CompressedTexSubImage2D(
1540 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1541 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1542 GPU_CLIENT_SINGLE_THREAD_CHECK();
1543 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1544 << GLES2Util::GetStringTextureTarget(target) << ", "
1545 << level << ", "
1546 << xoffset << ", " << yoffset << ", "
1547 << width << ", " << height << ", "
1548 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1549 << image_size << ", "
1550 << static_cast<const void*>(data) << ")");
1551 if (width < 0 || height < 0 || level < 0) {
1552 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1553 return;
1555 // If there's a pixel unpack buffer bound use it when issuing
1556 // CompressedTexSubImage2D.
1557 if (bound_pixel_unpack_transfer_buffer_id_) {
1558 GLuint offset = ToGLuint(data);
1559 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1560 bound_pixel_unpack_transfer_buffer_id_,
1561 "glCompressedTexSubImage2D", offset, image_size);
1562 if (buffer && buffer->shm_id() != -1) {
1563 helper_->CompressedTexSubImage2D(
1564 target, level, xoffset, yoffset, width, height, format, image_size,
1565 buffer->shm_id(), buffer->shm_offset() + offset);
1566 buffer->set_transfer_ready_token(helper_->InsertToken());
1567 CheckGLError();
1569 return;
1571 SetBucketContents(kResultBucketId, data, image_size);
1572 helper_->CompressedTexSubImage2DBucket(
1573 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1574 // Free the bucket. This is not required but it does free up the memory.
1575 // and we don't have to wait for the result so from the client's perspective
1576 // it's cheap.
1577 helper_->SetBucketSize(kResultBucketId, 0);
1578 CheckGLError();
1581 namespace {
1583 void CopyRectToBuffer(
1584 const void* pixels,
1585 uint32 height,
1586 uint32 unpadded_row_size,
1587 uint32 pixels_padded_row_size,
1588 bool flip_y,
1589 void* buffer,
1590 uint32 buffer_padded_row_size) {
1591 const int8* source = static_cast<const int8*>(pixels);
1592 int8* dest = static_cast<int8*>(buffer);
1593 if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
1594 if (flip_y) {
1595 dest += buffer_padded_row_size * (height - 1);
1597 // the last row is copied unpadded at the end
1598 for (; height > 1; --height) {
1599 memcpy(dest, source, buffer_padded_row_size);
1600 if (flip_y) {
1601 dest -= buffer_padded_row_size;
1602 } else {
1603 dest += buffer_padded_row_size;
1605 source += pixels_padded_row_size;
1607 memcpy(dest, source, unpadded_row_size);
1608 } else {
1609 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
1610 memcpy(dest, source, size);
1614 } // anonymous namespace
1616 void GLES2Implementation::TexImage2D(
1617 GLenum target, GLint level, GLint internalformat, GLsizei width,
1618 GLsizei height, GLint border, GLenum format, GLenum type,
1619 const void* pixels) {
1620 GPU_CLIENT_SINGLE_THREAD_CHECK();
1621 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1622 << GLES2Util::GetStringTextureTarget(target) << ", "
1623 << level << ", "
1624 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1625 << width << ", " << height << ", " << border << ", "
1626 << GLES2Util::GetStringTextureFormat(format) << ", "
1627 << GLES2Util::GetStringPixelType(type) << ", "
1628 << static_cast<const void*>(pixels) << ")");
1629 if (level < 0 || height < 0 || width < 0) {
1630 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
1631 return;
1633 uint32 size;
1634 uint32 unpadded_row_size;
1635 uint32 padded_row_size;
1636 if (!GLES2Util::ComputeImageDataSizes(
1637 width, height, format, type, unpack_alignment_, &size,
1638 &unpadded_row_size, &padded_row_size)) {
1639 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
1640 return;
1643 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1644 if (bound_pixel_unpack_transfer_buffer_id_) {
1645 GLuint offset = ToGLuint(pixels);
1646 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1647 bound_pixel_unpack_transfer_buffer_id_,
1648 "glTexImage2D", offset, size);
1649 if (buffer && buffer->shm_id() != -1) {
1650 helper_->TexImage2D(
1651 target, level, internalformat, width, height, border, format, type,
1652 buffer->shm_id(), buffer->shm_offset() + offset);
1653 buffer->set_transfer_ready_token(helper_->InsertToken());
1654 CheckGLError();
1656 return;
1659 // If there's no data just issue TexImage2D
1660 if (!pixels) {
1661 helper_->TexImage2D(
1662 target, level, internalformat, width, height, border, format, type,
1663 0, 0);
1664 CheckGLError();
1665 return;
1668 // compute the advance bytes per row for the src pixels
1669 uint32 src_padded_row_size;
1670 if (unpack_row_length_ > 0) {
1671 if (!GLES2Util::ComputeImagePaddedRowSize(
1672 unpack_row_length_, format, type, unpack_alignment_,
1673 &src_padded_row_size)) {
1674 SetGLError(
1675 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1676 return;
1678 } else {
1679 src_padded_row_size = padded_row_size;
1682 // advance pixels pointer past the skip rows and skip pixels
1683 pixels = reinterpret_cast<const int8*>(pixels) +
1684 unpack_skip_rows_ * src_padded_row_size;
1685 if (unpack_skip_pixels_) {
1686 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1687 pixels = reinterpret_cast<const int8*>(pixels) +
1688 unpack_skip_pixels_ * group_size;
1691 // Check if we can send it all at once.
1692 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1693 if (!buffer.valid()) {
1694 return;
1697 if (buffer.size() >= size) {
1698 CopyRectToBuffer(
1699 pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
1700 buffer.address(), padded_row_size);
1701 helper_->TexImage2D(
1702 target, level, internalformat, width, height, border, format, type,
1703 buffer.shm_id(), buffer.offset());
1704 CheckGLError();
1705 return;
1708 // No, so send it using TexSubImage2D.
1709 helper_->TexImage2D(
1710 target, level, internalformat, width, height, border, format, type,
1711 0, 0);
1712 TexSubImage2DImpl(
1713 target, level, 0, 0, width, height, format, type, unpadded_row_size,
1714 pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
1715 CheckGLError();
1718 void GLES2Implementation::TexSubImage2D(
1719 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1720 GLsizei height, GLenum format, GLenum type, const void* pixels) {
1721 GPU_CLIENT_SINGLE_THREAD_CHECK();
1722 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1723 << GLES2Util::GetStringTextureTarget(target) << ", "
1724 << level << ", "
1725 << xoffset << ", " << yoffset << ", "
1726 << width << ", " << height << ", "
1727 << GLES2Util::GetStringTextureFormat(format) << ", "
1728 << GLES2Util::GetStringPixelType(type) << ", "
1729 << static_cast<const void*>(pixels) << ")");
1731 if (level < 0 || height < 0 || width < 0) {
1732 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
1733 return;
1735 if (height == 0 || width == 0) {
1736 return;
1739 uint32 temp_size;
1740 uint32 unpadded_row_size;
1741 uint32 padded_row_size;
1742 if (!GLES2Util::ComputeImageDataSizes(
1743 width, height, format, type, unpack_alignment_, &temp_size,
1744 &unpadded_row_size, &padded_row_size)) {
1745 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
1746 return;
1749 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1750 if (bound_pixel_unpack_transfer_buffer_id_) {
1751 GLuint offset = ToGLuint(pixels);
1752 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1753 bound_pixel_unpack_transfer_buffer_id_,
1754 "glTexSubImage2D", offset, temp_size);
1755 if (buffer && buffer->shm_id() != -1) {
1756 helper_->TexSubImage2D(
1757 target, level, xoffset, yoffset, width, height, format, type,
1758 buffer->shm_id(), buffer->shm_offset() + offset, false);
1759 buffer->set_transfer_ready_token(helper_->InsertToken());
1760 CheckGLError();
1762 return;
1765 // compute the advance bytes per row for the src pixels
1766 uint32 src_padded_row_size;
1767 if (unpack_row_length_ > 0) {
1768 if (!GLES2Util::ComputeImagePaddedRowSize(
1769 unpack_row_length_, format, type, unpack_alignment_,
1770 &src_padded_row_size)) {
1771 SetGLError(
1772 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1773 return;
1775 } else {
1776 src_padded_row_size = padded_row_size;
1779 // advance pixels pointer past the skip rows and skip pixels
1780 pixels = reinterpret_cast<const int8*>(pixels) +
1781 unpack_skip_rows_ * src_padded_row_size;
1782 if (unpack_skip_pixels_) {
1783 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1784 pixels = reinterpret_cast<const int8*>(pixels) +
1785 unpack_skip_pixels_ * group_size;
1788 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
1789 TexSubImage2DImpl(
1790 target, level, xoffset, yoffset, width, height, format, type,
1791 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
1792 padded_row_size);
1793 CheckGLError();
1796 static GLint ComputeNumRowsThatFitInBuffer(
1797 GLsizeiptr padded_row_size, GLsizeiptr unpadded_row_size,
1798 unsigned int size) {
1799 GPU_DCHECK_GE(unpadded_row_size, 0);
1800 if (padded_row_size == 0) {
1801 return 1;
1803 GLint num_rows = size / padded_row_size;
1804 return num_rows + (size - num_rows * padded_row_size) / unpadded_row_size;
1807 void GLES2Implementation::TexSubImage2DImpl(
1808 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1809 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
1810 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
1811 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
1812 GPU_DCHECK(buffer);
1813 GPU_DCHECK_GE(level, 0);
1814 GPU_DCHECK_GT(height, 0);
1815 GPU_DCHECK_GT(width, 0);
1817 const int8* source = reinterpret_cast<const int8*>(pixels);
1818 GLint original_yoffset = yoffset;
1819 // Transfer by rows.
1820 while (height) {
1821 unsigned int desired_size =
1822 buffer_padded_row_size * (height - 1) + unpadded_row_size;
1823 if (!buffer->valid() || buffer->size() == 0) {
1824 buffer->Reset(desired_size);
1825 if (!buffer->valid()) {
1826 return;
1830 GLint num_rows = ComputeNumRowsThatFitInBuffer(
1831 buffer_padded_row_size, unpadded_row_size, buffer->size());
1832 num_rows = std::min(num_rows, height);
1833 CopyRectToBuffer(
1834 source, num_rows, unpadded_row_size, pixels_padded_row_size,
1835 unpack_flip_y_, buffer->address(), buffer_padded_row_size);
1836 GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
1837 helper_->TexSubImage2D(
1838 target, level, xoffset, y, width, num_rows, format, type,
1839 buffer->shm_id(), buffer->offset(), internal);
1840 buffer->Release();
1841 yoffset += num_rows;
1842 source += num_rows * pixels_padded_row_size;
1843 height -= num_rows;
1847 bool GLES2Implementation::GetActiveAttribHelper(
1848 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1849 GLenum* type, char* name) {
1850 // Clear the bucket so if the command fails nothing will be in it.
1851 helper_->SetBucketSize(kResultBucketId, 0);
1852 typedef cmds::GetActiveAttrib::Result Result;
1853 Result* result = GetResultAs<Result*>();
1854 if (!result) {
1855 return false;
1857 // Set as failed so if the command fails we'll recover.
1858 result->success = false;
1859 helper_->GetActiveAttrib(program, index, kResultBucketId,
1860 GetResultShmId(), GetResultShmOffset());
1861 WaitForCmd();
1862 if (result->success) {
1863 if (size) {
1864 *size = result->size;
1866 if (type) {
1867 *type = result->type;
1869 if (length || name) {
1870 std::vector<int8> str;
1871 GetBucketContents(kResultBucketId, &str);
1872 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
1873 std::max(static_cast<size_t>(0),
1874 str.size() - 1));
1875 if (length) {
1876 *length = max_size;
1878 if (name && bufsize > 0) {
1879 memcpy(name, &str[0], max_size);
1880 name[max_size] = '\0';
1884 return result->success != 0;
1887 void GLES2Implementation::GetActiveAttrib(
1888 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1889 GLenum* type, char* name) {
1890 GPU_CLIENT_SINGLE_THREAD_CHECK();
1891 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
1892 << program << ", " << index << ", " << bufsize << ", "
1893 << static_cast<const void*>(length) << ", "
1894 << static_cast<const void*>(size) << ", "
1895 << static_cast<const void*>(type) << ", "
1896 << static_cast<const void*>(name) << ", ");
1897 if (bufsize < 0) {
1898 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
1899 return;
1901 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
1902 bool success = share_group_->program_info_manager()->GetActiveAttrib(
1903 this, program, index, bufsize, length, size, type, name);
1904 if (success) {
1905 if (size) {
1906 GPU_CLIENT_LOG(" size: " << *size);
1908 if (type) {
1909 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
1911 if (name) {
1912 GPU_CLIENT_LOG(" name: " << name);
1915 CheckGLError();
1918 bool GLES2Implementation::GetActiveUniformHelper(
1919 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1920 GLenum* type, char* name) {
1921 // Clear the bucket so if the command fails nothing will be in it.
1922 helper_->SetBucketSize(kResultBucketId, 0);
1923 typedef cmds::GetActiveUniform::Result Result;
1924 Result* result = GetResultAs<Result*>();
1925 if (!result) {
1926 return false;
1928 // Set as failed so if the command fails we'll recover.
1929 result->success = false;
1930 helper_->GetActiveUniform(program, index, kResultBucketId,
1931 GetResultShmId(), GetResultShmOffset());
1932 WaitForCmd();
1933 if (result->success) {
1934 if (size) {
1935 *size = result->size;
1937 if (type) {
1938 *type = result->type;
1940 if (length || name) {
1941 std::vector<int8> str;
1942 GetBucketContents(kResultBucketId, &str);
1943 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
1944 std::max(static_cast<size_t>(0),
1945 str.size() - 1));
1946 if (length) {
1947 *length = max_size;
1949 if (name && bufsize > 0) {
1950 memcpy(name, &str[0], max_size);
1951 name[max_size] = '\0';
1955 return result->success != 0;
1958 void GLES2Implementation::GetActiveUniform(
1959 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1960 GLenum* type, char* name) {
1961 GPU_CLIENT_SINGLE_THREAD_CHECK();
1962 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
1963 << program << ", " << index << ", " << bufsize << ", "
1964 << static_cast<const void*>(length) << ", "
1965 << static_cast<const void*>(size) << ", "
1966 << static_cast<const void*>(type) << ", "
1967 << static_cast<const void*>(name) << ", ");
1968 if (bufsize < 0) {
1969 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
1970 return;
1972 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
1973 bool success = share_group_->program_info_manager()->GetActiveUniform(
1974 this, program, index, bufsize, length, size, type, name);
1975 if (success) {
1976 if (size) {
1977 GPU_CLIENT_LOG(" size: " << *size);
1979 if (type) {
1980 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
1982 if (name) {
1983 GPU_CLIENT_LOG(" name: " << name);
1986 CheckGLError();
1989 void GLES2Implementation::GetAttachedShaders(
1990 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
1991 GPU_CLIENT_SINGLE_THREAD_CHECK();
1992 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
1993 << program << ", " << maxcount << ", "
1994 << static_cast<const void*>(count) << ", "
1995 << static_cast<const void*>(shaders) << ", ");
1996 if (maxcount < 0) {
1997 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
1998 return;
2000 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2001 typedef cmds::GetAttachedShaders::Result Result;
2002 uint32 size = Result::ComputeSize(maxcount);
2003 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
2004 if (!result) {
2005 return;
2007 result->SetNumResults(0);
2008 helper_->GetAttachedShaders(
2009 program,
2010 transfer_buffer_->GetShmId(),
2011 transfer_buffer_->GetOffset(result),
2012 size);
2013 int32 token = helper_->InsertToken();
2014 WaitForCmd();
2015 if (count) {
2016 *count = result->GetNumResults();
2018 result->CopyResult(shaders);
2019 GPU_CLIENT_LOG_CODE_BLOCK({
2020 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2021 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2024 transfer_buffer_->FreePendingToken(result, token);
2025 CheckGLError();
2028 void GLES2Implementation::GetShaderPrecisionFormat(
2029 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
2030 GPU_CLIENT_SINGLE_THREAD_CHECK();
2031 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2032 << GLES2Util::GetStringShaderType(shadertype) << ", "
2033 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
2034 << static_cast<const void*>(range) << ", "
2035 << static_cast<const void*>(precision) << ", ");
2036 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2037 typedef cmds::GetShaderPrecisionFormat::Result Result;
2038 Result* result = GetResultAs<Result*>();
2039 if (!result) {
2040 return;
2043 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
2044 GLStaticState::ShaderPrecisionMap::iterator i =
2045 static_state_.shader_precisions.find(key);
2046 if (i != static_state_.shader_precisions.end()) {
2047 *result = i->second;
2048 } else {
2049 result->success = false;
2050 helper_->GetShaderPrecisionFormat(
2051 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
2052 WaitForCmd();
2053 if (result->success)
2054 static_state_.shader_precisions[key] = *result;
2057 if (result->success) {
2058 if (range) {
2059 range[0] = result->min_range;
2060 range[1] = result->max_range;
2061 GPU_CLIENT_LOG(" min_range: " << range[0]);
2062 GPU_CLIENT_LOG(" min_range: " << range[1]);
2064 if (precision) {
2065 precision[0] = result->precision;
2066 GPU_CLIENT_LOG(" min_range: " << precision[0]);
2069 CheckGLError();
2072 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
2073 const char* result = NULL;
2074 // Clears the bucket so if the command fails nothing will be in it.
2075 helper_->SetBucketSize(kResultBucketId, 0);
2076 helper_->GetString(name, kResultBucketId);
2077 std::string str;
2078 if (GetBucketAsString(kResultBucketId, &str)) {
2079 // Adds extensions implemented on client side only.
2080 switch (name) {
2081 case GL_EXTENSIONS:
2082 str += std::string(str.empty() ? "" : " ") +
2083 "GL_CHROMIUM_flipy "
2084 "GL_CHROMIUM_map_sub "
2085 "GL_CHROMIUM_shallow_flush "
2086 "GL_EXT_unpack_subimage";
2087 if (gpu_control_ != NULL) {
2088 // The first space character is intentional.
2089 str += " GL_CHROMIUM_map_image";
2091 break;
2092 default:
2093 break;
2096 // Because of WebGL the extensions can change. We have to cache each unique
2097 // result since we don't know when the client will stop referring to a
2098 // previous one it queries.
2099 GLStringMap::iterator it = gl_strings_.find(name);
2100 if (it == gl_strings_.end()) {
2101 std::set<std::string> strings;
2102 std::pair<GLStringMap::iterator, bool> insert_result =
2103 gl_strings_.insert(std::make_pair(name, strings));
2104 GPU_DCHECK(insert_result.second);
2105 it = insert_result.first;
2107 std::set<std::string>& string_set = it->second;
2108 std::set<std::string>::const_iterator sit = string_set.find(str);
2109 if (sit != string_set.end()) {
2110 result = sit->c_str();
2111 } else {
2112 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2113 string_set.insert(str);
2114 GPU_DCHECK(insert_result.second);
2115 result = insert_result.first->c_str();
2118 return reinterpret_cast<const GLubyte*>(result);
2121 const GLubyte* GLES2Implementation::GetString(GLenum name) {
2122 GPU_CLIENT_SINGLE_THREAD_CHECK();
2123 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2124 << GLES2Util::GetStringStringType(name) << ")");
2125 TRACE_EVENT0("gpu", "GLES2::GetString");
2126 const GLubyte* result = GetStringHelper(name);
2127 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
2128 CheckGLError();
2129 return result;
2132 void GLES2Implementation::GetUniformfv(
2133 GLuint program, GLint location, GLfloat* params) {
2134 GPU_CLIENT_SINGLE_THREAD_CHECK();
2135 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2136 << program << ", " << location << ", "
2137 << static_cast<const void*>(params) << ")");
2138 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2139 typedef cmds::GetUniformfv::Result Result;
2140 Result* result = GetResultAs<Result*>();
2141 if (!result) {
2142 return;
2144 result->SetNumResults(0);
2145 helper_->GetUniformfv(
2146 program, location, GetResultShmId(), GetResultShmOffset());
2147 WaitForCmd();
2148 result->CopyResult(params);
2149 GPU_CLIENT_LOG_CODE_BLOCK({
2150 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2151 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2154 CheckGLError();
2157 void GLES2Implementation::GetUniformiv(
2158 GLuint program, GLint location, GLint* params) {
2159 GPU_CLIENT_SINGLE_THREAD_CHECK();
2160 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2161 << program << ", " << location << ", "
2162 << static_cast<const void*>(params) << ")");
2163 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2164 typedef cmds::GetUniformiv::Result Result;
2165 Result* result = GetResultAs<Result*>();
2166 if (!result) {
2167 return;
2169 result->SetNumResults(0);
2170 helper_->GetUniformiv(
2171 program, location, GetResultShmId(), GetResultShmOffset());
2172 WaitForCmd();
2173 GetResultAs<cmds::GetUniformfv::Result*>()->CopyResult(params);
2174 GPU_CLIENT_LOG_CODE_BLOCK({
2175 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2176 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2179 CheckGLError();
2182 void GLES2Implementation::ReadPixels(
2183 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
2184 GLenum type, void* pixels) {
2185 GPU_CLIENT_SINGLE_THREAD_CHECK();
2186 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2187 << xoffset << ", " << yoffset << ", "
2188 << width << ", " << height << ", "
2189 << GLES2Util::GetStringReadPixelFormat(format) << ", "
2190 << GLES2Util::GetStringPixelType(type) << ", "
2191 << static_cast<const void*>(pixels) << ")");
2192 if (width < 0 || height < 0) {
2193 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
2194 return;
2196 if (width == 0 || height == 0) {
2197 return;
2200 // glReadPixel pads the size of each row of pixels by an amount specified by
2201 // glPixelStorei. So, we have to take that into account both in the fact that
2202 // the pixels returned from the ReadPixel command will include that padding
2203 // and that when we copy the results to the user's buffer we need to not
2204 // write those padding bytes but leave them as they are.
2206 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2207 typedef cmds::ReadPixels::Result Result;
2209 int8* dest = reinterpret_cast<int8*>(pixels);
2210 uint32 temp_size;
2211 uint32 unpadded_row_size;
2212 uint32 padded_row_size;
2213 if (!GLES2Util::ComputeImageDataSizes(
2214 width, 2, format, type, pack_alignment_, &temp_size, &unpadded_row_size,
2215 &padded_row_size)) {
2216 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
2217 return;
2220 if (bound_pixel_pack_transfer_buffer_id_) {
2221 GLuint offset = ToGLuint(pixels);
2222 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2223 bound_pixel_pack_transfer_buffer_id_,
2224 "glReadPixels", offset, padded_row_size * height);
2225 if (buffer && buffer->shm_id() != -1) {
2226 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
2227 buffer->shm_id(), buffer->shm_offset(),
2228 0, 0, true);
2229 CheckGLError();
2231 return;
2234 if (!pixels) {
2235 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
2236 return;
2239 // Transfer by rows.
2240 // The max rows we can transfer.
2241 while (height) {
2242 GLsizei desired_size = padded_row_size * height - 1 + unpadded_row_size;
2243 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
2244 if (!buffer.valid()) {
2245 return;
2247 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2248 padded_row_size, unpadded_row_size, buffer.size());
2249 num_rows = std::min(num_rows, height);
2250 // NOTE: We must look up the address of the result area AFTER allocation
2251 // of the transfer buffer since the transfer buffer may be reallocated.
2252 Result* result = GetResultAs<Result*>();
2253 if (!result) {
2254 return;
2256 *result = 0; // mark as failed.
2257 helper_->ReadPixels(
2258 xoffset, yoffset, width, num_rows, format, type,
2259 buffer.shm_id(), buffer.offset(),
2260 GetResultShmId(), GetResultShmOffset(),
2261 false);
2262 WaitForCmd();
2263 if (*result != 0) {
2264 // when doing a y-flip we have to iterate through top-to-bottom chunks
2265 // of the dst. The service side handles reversing the rows within a
2266 // chunk.
2267 int8* rows_dst;
2268 if (pack_reverse_row_order_) {
2269 rows_dst = dest + (height - num_rows) * padded_row_size;
2270 } else {
2271 rows_dst = dest;
2273 // We have to copy 1 row at a time to avoid writing pad bytes.
2274 const int8* src = static_cast<const int8*>(buffer.address());
2275 for (GLint yy = 0; yy < num_rows; ++yy) {
2276 memcpy(rows_dst, src, unpadded_row_size);
2277 rows_dst += padded_row_size;
2278 src += padded_row_size;
2280 if (!pack_reverse_row_order_) {
2281 dest = rows_dst;
2284 // If it was not marked as successful exit.
2285 if (*result == 0) {
2286 return;
2288 yoffset += num_rows;
2289 height -= num_rows;
2291 CheckGLError();
2294 void GLES2Implementation::ActiveTexture(GLenum texture) {
2295 GPU_CLIENT_SINGLE_THREAD_CHECK();
2296 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2297 << GLES2Util::GetStringEnum(texture) << ")");
2298 GLuint texture_index = texture - GL_TEXTURE0;
2299 if (texture_index >= static_cast<GLuint>(
2300 static_state_.int_state.max_combined_texture_image_units)) {
2301 SetGLErrorInvalidEnum(
2302 "glActiveTexture", texture, "texture");
2303 return;
2306 active_texture_unit_ = texture_index;
2307 helper_->ActiveTexture(texture);
2308 CheckGLError();
2311 void GLES2Implementation::GenBuffersHelper(
2312 GLsizei /* n */, const GLuint* /* buffers */) {
2315 void GLES2Implementation::GenFramebuffersHelper(
2316 GLsizei /* n */, const GLuint* /* framebuffers */) {
2319 void GLES2Implementation::GenRenderbuffersHelper(
2320 GLsizei /* n */, const GLuint* /* renderbuffers */) {
2323 void GLES2Implementation::GenTexturesHelper(
2324 GLsizei /* n */, const GLuint* /* textures */) {
2327 void GLES2Implementation::GenVertexArraysOESHelper(
2328 GLsizei n, const GLuint* arrays) {
2329 vertex_array_object_manager_->GenVertexArrays(n, arrays);
2332 void GLES2Implementation::GenQueriesEXTHelper(
2333 GLsizei /* n */, const GLuint* /* queries */) {
2336 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
2337 // generates a new resource. On newer versions of OpenGL they don't. The code
2338 // related to binding below will need to change if we switch to the new OpenGL
2339 // model. Specifically it assumes a bind will succeed which is always true in
2340 // the old model but possibly not true in the new model if another context has
2341 // deleted the resource.
2343 bool GLES2Implementation::BindBufferHelper(
2344 GLenum target, GLuint buffer) {
2345 // TODO(gman): See note #1 above.
2346 bool changed = false;
2347 switch (target) {
2348 case GL_ARRAY_BUFFER:
2349 if (bound_array_buffer_id_ != buffer) {
2350 bound_array_buffer_id_ = buffer;
2351 changed = true;
2353 break;
2354 case GL_ELEMENT_ARRAY_BUFFER:
2355 changed = vertex_array_object_manager_->BindElementArray(buffer);
2356 break;
2357 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
2358 bound_pixel_pack_transfer_buffer_id_ = buffer;
2359 break;
2360 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
2361 bound_pixel_unpack_transfer_buffer_id_ = buffer;
2362 break;
2363 default:
2364 changed = true;
2365 break;
2367 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2368 // used even though it's marked it as used here.
2369 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(buffer);
2370 return changed;
2373 bool GLES2Implementation::BindFramebufferHelper(
2374 GLenum target, GLuint framebuffer) {
2375 // TODO(gman): See note #1 above.
2376 bool changed = false;
2377 switch (target) {
2378 case GL_FRAMEBUFFER:
2379 if (bound_framebuffer_ != framebuffer ||
2380 bound_read_framebuffer_ != framebuffer) {
2381 bound_framebuffer_ = framebuffer;
2382 bound_read_framebuffer_ = framebuffer;
2383 changed = true;
2385 break;
2386 case GL_READ_FRAMEBUFFER:
2387 if (!IsChromiumFramebufferMultisampleAvailable()) {
2388 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2389 return false;
2391 if (bound_read_framebuffer_ != framebuffer) {
2392 bound_read_framebuffer_ = framebuffer;
2393 changed = true;
2395 break;
2396 case GL_DRAW_FRAMEBUFFER:
2397 if (!IsChromiumFramebufferMultisampleAvailable()) {
2398 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2399 return false;
2401 if (bound_framebuffer_ != framebuffer) {
2402 bound_framebuffer_ = framebuffer;
2403 changed = true;
2405 break;
2406 default:
2407 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2408 return false;
2410 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(framebuffer);
2411 return changed;
2414 bool GLES2Implementation::BindRenderbufferHelper(
2415 GLenum target, GLuint renderbuffer) {
2416 // TODO(gman): See note #1 above.
2417 bool changed = false;
2418 switch (target) {
2419 case GL_RENDERBUFFER:
2420 if (bound_renderbuffer_ != renderbuffer) {
2421 bound_renderbuffer_ = renderbuffer;
2422 changed = true;
2424 break;
2425 default:
2426 changed = true;
2427 break;
2429 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2430 // used even though it's marked it as used here.
2431 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(renderbuffer);
2432 return changed;
2435 bool GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
2436 // TODO(gman): See note #1 above.
2437 // TODO(gman): Change this to false once we figure out why it's failing
2438 // on daisy.
2439 bool changed = true;
2440 TextureUnit& unit = texture_units_[active_texture_unit_];
2441 switch (target) {
2442 case GL_TEXTURE_2D:
2443 if (unit.bound_texture_2d != texture) {
2444 unit.bound_texture_2d = texture;
2445 changed = true;
2447 break;
2448 case GL_TEXTURE_CUBE_MAP:
2449 if (unit.bound_texture_cube_map != texture) {
2450 unit.bound_texture_cube_map = texture;
2451 changed = true;
2453 break;
2454 default:
2455 changed = true;
2456 break;
2458 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2459 // used. even though it's marked it as used here.
2460 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(texture);
2461 return changed;
2464 bool GLES2Implementation::BindVertexArrayHelper(GLuint array) {
2465 // TODO(gman): See note #1 above.
2466 bool changed = false;
2467 if (!vertex_array_object_manager_->BindVertexArray(array, &changed)) {
2468 SetGLError(
2469 GL_INVALID_OPERATION, "glBindVertexArrayOES",
2470 "id was not generated with glGenVertexArrayOES");
2472 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
2473 // because unlike other resources VertexArrayObject ids must
2474 // be generated by GenVertexArrays. A random id to Bind will not
2475 // generate a new object.
2476 return changed;
2479 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
2480 return vertex_array_object_manager_->IsReservedId(id);
2483 void GLES2Implementation::DeleteBuffersHelper(
2484 GLsizei n, const GLuint* buffers) {
2485 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
2486 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
2487 SetGLError(
2488 GL_INVALID_VALUE,
2489 "glDeleteBuffers", "id not created by this context.");
2490 return;
2492 for (GLsizei ii = 0; ii < n; ++ii) {
2493 if (buffers[ii] == bound_array_buffer_id_) {
2494 bound_array_buffer_id_ = 0;
2496 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
2497 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
2498 if (buffer) {
2499 // Free buffer memory, pending the passage of a token.
2500 buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
2501 // Remove buffer.
2502 buffer_tracker_->RemoveBuffer(buffers[ii]);
2504 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
2505 bound_pixel_unpack_transfer_buffer_id_ = 0;
2510 void GLES2Implementation::DeleteBuffersStub(
2511 GLsizei n, const GLuint* buffers) {
2512 helper_->DeleteBuffersImmediate(n, buffers);
2516 void GLES2Implementation::DeleteFramebuffersHelper(
2517 GLsizei n, const GLuint* framebuffers) {
2518 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
2519 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
2520 SetGLError(
2521 GL_INVALID_VALUE,
2522 "glDeleteFramebuffers", "id not created by this context.");
2523 return;
2525 for (GLsizei ii = 0; ii < n; ++ii) {
2526 if (framebuffers[ii] == bound_framebuffer_) {
2527 bound_framebuffer_ = 0;
2529 if (framebuffers[ii] == bound_read_framebuffer_) {
2530 bound_read_framebuffer_ = 0;
2535 void GLES2Implementation::DeleteFramebuffersStub(
2536 GLsizei n, const GLuint* framebuffers) {
2537 helper_->DeleteFramebuffersImmediate(n, framebuffers);
2540 void GLES2Implementation::DeleteRenderbuffersHelper(
2541 GLsizei n, const GLuint* renderbuffers) {
2542 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
2543 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
2544 SetGLError(
2545 GL_INVALID_VALUE,
2546 "glDeleteRenderbuffers", "id not created by this context.");
2547 return;
2549 for (GLsizei ii = 0; ii < n; ++ii) {
2550 if (renderbuffers[ii] == bound_renderbuffer_) {
2551 bound_renderbuffer_ = 0;
2556 void GLES2Implementation::DeleteRenderbuffersStub(
2557 GLsizei n, const GLuint* renderbuffers) {
2558 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
2561 void GLES2Implementation::DeleteTexturesHelper(
2562 GLsizei n, const GLuint* textures) {
2563 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
2564 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
2565 SetGLError(
2566 GL_INVALID_VALUE,
2567 "glDeleteTextures", "id not created by this context.");
2568 return;
2570 for (GLsizei ii = 0; ii < n; ++ii) {
2571 for (GLint tt = 0;
2572 tt < static_state_.int_state.max_combined_texture_image_units;
2573 ++tt) {
2574 TextureUnit& unit = texture_units_[tt];
2575 if (textures[ii] == unit.bound_texture_2d) {
2576 unit.bound_texture_2d = 0;
2578 if (textures[ii] == unit.bound_texture_cube_map) {
2579 unit.bound_texture_cube_map = 0;
2585 void GLES2Implementation::DeleteVertexArraysOESHelper(
2586 GLsizei n, const GLuint* arrays) {
2587 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
2588 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
2589 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
2590 SetGLError(
2591 GL_INVALID_VALUE,
2592 "glDeleteVertexArraysOES", "id not created by this context.");
2593 return;
2597 void GLES2Implementation::DeleteVertexArraysOESStub(
2598 GLsizei n, const GLuint* arrays) {
2599 helper_->DeleteVertexArraysOESImmediate(n, arrays);
2602 void GLES2Implementation::DeleteTexturesStub(
2603 GLsizei n, const GLuint* textures) {
2604 helper_->DeleteTexturesImmediate(n, textures);
2607 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
2608 GPU_CLIENT_SINGLE_THREAD_CHECK();
2609 GPU_CLIENT_LOG(
2610 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
2611 vertex_array_object_manager_->SetAttribEnable(index, false);
2612 helper_->DisableVertexAttribArray(index);
2613 CheckGLError();
2616 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
2617 GPU_CLIENT_SINGLE_THREAD_CHECK();
2618 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
2619 << index << ")");
2620 vertex_array_object_manager_->SetAttribEnable(index, true);
2621 helper_->EnableVertexAttribArray(index);
2622 CheckGLError();
2625 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
2626 GPU_CLIENT_SINGLE_THREAD_CHECK();
2627 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
2628 << GLES2Util::GetStringDrawMode(mode) << ", "
2629 << first << ", " << count << ")");
2630 if (count < 0) {
2631 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
2632 return;
2634 bool simulated = false;
2635 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
2636 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
2637 return;
2639 helper_->DrawArrays(mode, first, count);
2640 RestoreArrayBuffer(simulated);
2641 CheckGLError();
2644 void GLES2Implementation::GetVertexAttribfv(
2645 GLuint index, GLenum pname, GLfloat* params) {
2646 GPU_CLIENT_SINGLE_THREAD_CHECK();
2647 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
2648 << index << ", "
2649 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2650 << static_cast<const void*>(params) << ")");
2651 uint32 value = 0;
2652 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2653 *params = static_cast<float>(value);
2654 return;
2656 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
2657 typedef cmds::GetVertexAttribfv::Result Result;
2658 Result* result = GetResultAs<Result*>();
2659 if (!result) {
2660 return;
2662 result->SetNumResults(0);
2663 helper_->GetVertexAttribfv(
2664 index, pname, GetResultShmId(), GetResultShmOffset());
2665 WaitForCmd();
2666 result->CopyResult(params);
2667 GPU_CLIENT_LOG_CODE_BLOCK({
2668 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2669 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2672 CheckGLError();
2675 void GLES2Implementation::GetVertexAttribiv(
2676 GLuint index, GLenum pname, GLint* params) {
2677 GPU_CLIENT_SINGLE_THREAD_CHECK();
2678 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
2679 << index << ", "
2680 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2681 << static_cast<const void*>(params) << ")");
2682 uint32 value = 0;
2683 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2684 *params = value;
2685 return;
2687 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
2688 typedef cmds::GetVertexAttribiv::Result Result;
2689 Result* result = GetResultAs<Result*>();
2690 if (!result) {
2691 return;
2693 result->SetNumResults(0);
2694 helper_->GetVertexAttribiv(
2695 index, pname, GetResultShmId(), GetResultShmOffset());
2696 WaitForCmd();
2697 result->CopyResult(params);
2698 GPU_CLIENT_LOG_CODE_BLOCK({
2699 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2700 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2703 CheckGLError();
2706 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
2707 const char* feature) {
2708 GPU_CLIENT_SINGLE_THREAD_CHECK();
2709 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
2710 << feature << ")");
2711 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
2712 typedef cmds::EnableFeatureCHROMIUM::Result Result;
2713 Result* result = GetResultAs<Result*>();
2714 if (!result) {
2715 return false;
2717 *result = 0;
2718 SetBucketAsCString(kResultBucketId, feature);
2719 helper_->EnableFeatureCHROMIUM(
2720 kResultBucketId, GetResultShmId(), GetResultShmOffset());
2721 WaitForCmd();
2722 helper_->SetBucketSize(kResultBucketId, 0);
2723 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
2724 return *result;
2727 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
2728 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
2729 GPU_CLIENT_SINGLE_THREAD_CHECK();
2730 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
2731 << target << ", " << offset << ", " << size << ", "
2732 << GLES2Util::GetStringEnum(access) << ")");
2733 // NOTE: target is NOT checked because the service will check it
2734 // and we don't know what targets are valid.
2735 if (access != GL_WRITE_ONLY) {
2736 SetGLErrorInvalidEnum(
2737 "glMapBufferSubDataCHROMIUM", access, "access");
2738 return NULL;
2740 if (offset < 0 || size < 0) {
2741 SetGLError(GL_INVALID_VALUE, "glMapBufferSubDataCHROMIUM", "bad range");
2742 return NULL;
2744 int32 shm_id;
2745 unsigned int shm_offset;
2746 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2747 if (!mem) {
2748 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
2749 return NULL;
2752 std::pair<MappedBufferMap::iterator, bool> result =
2753 mapped_buffers_.insert(std::make_pair(
2754 mem,
2755 MappedBuffer(
2756 access, shm_id, mem, shm_offset, target, offset, size)));
2757 GPU_DCHECK(result.second);
2758 GPU_CLIENT_LOG(" returned " << mem);
2759 return mem;
2762 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
2763 GPU_CLIENT_SINGLE_THREAD_CHECK();
2764 GPU_CLIENT_LOG(
2765 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
2766 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
2767 if (it == mapped_buffers_.end()) {
2768 SetGLError(
2769 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
2770 return;
2772 const MappedBuffer& mb = it->second;
2773 helper_->BufferSubData(
2774 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
2775 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
2776 mapped_buffers_.erase(it);
2777 CheckGLError();
2780 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
2781 GLenum target,
2782 GLint level,
2783 GLint xoffset,
2784 GLint yoffset,
2785 GLsizei width,
2786 GLsizei height,
2787 GLenum format,
2788 GLenum type,
2789 GLenum access) {
2790 GPU_CLIENT_SINGLE_THREAD_CHECK();
2791 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
2792 << target << ", " << level << ", "
2793 << xoffset << ", " << yoffset << ", "
2794 << width << ", " << height << ", "
2795 << GLES2Util::GetStringTextureFormat(format) << ", "
2796 << GLES2Util::GetStringPixelType(type) << ", "
2797 << GLES2Util::GetStringEnum(access) << ")");
2798 if (access != GL_WRITE_ONLY) {
2799 SetGLErrorInvalidEnum(
2800 "glMapTexSubImage2DCHROMIUM", access, "access");
2801 return NULL;
2803 // NOTE: target is NOT checked because the service will check it
2804 // and we don't know what targets are valid.
2805 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
2806 SetGLError(
2807 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
2808 return NULL;
2810 uint32 size;
2811 if (!GLES2Util::ComputeImageDataSizes(
2812 width, height, format, type, unpack_alignment_, &size, NULL, NULL)) {
2813 SetGLError(
2814 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
2815 return NULL;
2817 int32 shm_id;
2818 unsigned int shm_offset;
2819 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2820 if (!mem) {
2821 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
2822 return NULL;
2825 std::pair<MappedTextureMap::iterator, bool> result =
2826 mapped_textures_.insert(std::make_pair(
2827 mem,
2828 MappedTexture(
2829 access, shm_id, mem, shm_offset,
2830 target, level, xoffset, yoffset, width, height, format, type)));
2831 GPU_DCHECK(result.second);
2832 GPU_CLIENT_LOG(" returned " << mem);
2833 return mem;
2836 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
2837 GPU_CLIENT_SINGLE_THREAD_CHECK();
2838 GPU_CLIENT_LOG(
2839 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
2840 MappedTextureMap::iterator it = mapped_textures_.find(mem);
2841 if (it == mapped_textures_.end()) {
2842 SetGLError(
2843 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
2844 return;
2846 const MappedTexture& mt = it->second;
2847 helper_->TexSubImage2D(
2848 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
2849 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
2850 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
2851 mapped_textures_.erase(it);
2852 CheckGLError();
2855 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
2856 float scale_factor) {
2857 GPU_CLIENT_SINGLE_THREAD_CHECK();
2858 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
2859 << width << ", " << height << ", " << scale_factor << ")");
2860 helper_->ResizeCHROMIUM(width, height, scale_factor);
2861 CheckGLError();
2864 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
2865 GPU_CLIENT_SINGLE_THREAD_CHECK();
2866 GPU_CLIENT_LOG("[" << GetLogPrefix()
2867 << "] glGetRequestableExtensionsCHROMIUM()");
2868 TRACE_EVENT0("gpu",
2869 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
2870 const char* result = NULL;
2871 // Clear the bucket so if the command fails nothing will be in it.
2872 helper_->SetBucketSize(kResultBucketId, 0);
2873 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
2874 std::string str;
2875 if (GetBucketAsString(kResultBucketId, &str)) {
2876 // The set of requestable extensions shrinks as we enable
2877 // them. Because we don't know when the client will stop referring
2878 // to a previous one it queries (see GetString) we need to cache
2879 // the unique results.
2880 std::set<std::string>::const_iterator sit =
2881 requestable_extensions_set_.find(str);
2882 if (sit != requestable_extensions_set_.end()) {
2883 result = sit->c_str();
2884 } else {
2885 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2886 requestable_extensions_set_.insert(str);
2887 GPU_DCHECK(insert_result.second);
2888 result = insert_result.first->c_str();
2891 GPU_CLIENT_LOG(" returned " << result);
2892 return reinterpret_cast<const GLchar*>(result);
2895 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
2896 // with VirtualGL contexts.
2897 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
2898 GPU_CLIENT_SINGLE_THREAD_CHECK();
2899 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
2900 << extension << ")");
2901 SetBucketAsCString(kResultBucketId, extension);
2902 helper_->RequestExtensionCHROMIUM(kResultBucketId);
2903 helper_->SetBucketSize(kResultBucketId, 0);
2905 struct ExtensionCheck {
2906 const char* extension;
2907 ExtensionStatus* status;
2909 const ExtensionCheck checks[] = {
2911 "GL_ANGLE_pack_reverse_row_order",
2912 &angle_pack_reverse_row_order_status_,
2915 "GL_CHROMIUM_framebuffer_multisample",
2916 &chromium_framebuffer_multisample_,
2919 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
2920 for (size_t ii = 0; ii < kNumChecks; ++ii) {
2921 const ExtensionCheck& check = checks[ii];
2922 if (*check.status == kUnavailableExtensionStatus &&
2923 !strcmp(extension, check.extension)) {
2924 *check.status = kUnknownExtensionStatus;
2929 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
2930 GPU_CLIENT_SINGLE_THREAD_CHECK();
2931 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
2932 // Wait if this would add too many rate limit tokens.
2933 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
2934 helper_->WaitForToken(rate_limit_tokens_.front());
2935 rate_limit_tokens_.pop();
2937 rate_limit_tokens_.push(helper_->InsertToken());
2940 void GLES2Implementation::GetMultipleIntegervCHROMIUM(
2941 const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size) {
2942 GPU_CLIENT_SINGLE_THREAD_CHECK();
2943 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMultipleIntegervCHROMIUM("
2944 << static_cast<const void*>(pnames) << ", "
2945 << count << ", " << results << ", "
2946 << size << ")");
2947 GPU_CLIENT_LOG_CODE_BLOCK({
2948 for (GLuint i = 0; i < count; ++i) {
2949 GPU_CLIENT_LOG(
2950 " " << i << ": " << GLES2Util::GetStringGLState(pnames[i]));
2954 GetMultipleIntegervState state(pnames, count, results, size);
2955 if (!GetMultipleIntegervSetup(&state)) {
2956 return;
2958 state.buffer = transfer_buffer_->Alloc(state.transfer_buffer_size_needed);
2959 if (!state.buffer) {
2960 SetGLError(GL_OUT_OF_MEMORY, "glGetMultipleIntegervCHROMIUM",
2961 "Transfer buffer allocation failed.");
2962 return;
2964 GetMultipleIntegervRequest(&state);
2965 WaitForCmd();
2966 GetMultipleIntegervOnCompleted(&state);
2968 GPU_CLIENT_LOG(" returned");
2969 GPU_CLIENT_LOG_CODE_BLOCK({
2970 for (int i = 0; i < state.num_results; ++i) {
2971 GPU_CLIENT_LOG(" " << i << ": " << (results[i]));
2975 // TODO(gman): We should be able to free without a token.
2976 transfer_buffer_->FreePendingToken(state.buffer, helper_->InsertToken());
2977 CheckGLError();
2980 bool GLES2Implementation::GetMultipleIntegervSetup(
2981 GetMultipleIntegervState* state) {
2982 state->num_results = 0;
2983 for (GLuint ii = 0; ii < state->pnames_count; ++ii) {
2984 int num = util_.GLGetNumValuesReturned(state->pnames[ii]);
2985 if (!num) {
2986 SetGLErrorInvalidEnum(
2987 "glGetMultipleIntegervCHROMIUM", state->pnames[ii], "pname");
2988 return false;
2990 state->num_results += num;
2992 if (static_cast<size_t>(state->results_size) !=
2993 state->num_results * sizeof(GLint)) {
2994 SetGLError(GL_INVALID_VALUE, "glGetMultipleIntegervCHROMIUM", "bad size");
2995 return false;
2997 for (int ii = 0; ii < state->num_results; ++ii) {
2998 if (state->results[ii] != 0) {
2999 SetGLError(GL_INVALID_VALUE,
3000 "glGetMultipleIntegervCHROMIUM", "results not set to zero.");
3001 return false;
3004 state->transfer_buffer_size_needed =
3005 state->pnames_count * sizeof(state->pnames[0]) +
3006 state->num_results * sizeof(state->results[0]);
3007 return true;
3010 void GLES2Implementation::GetMultipleIntegervRequest(
3011 GetMultipleIntegervState* state) {
3012 GLenum* pnames_buffer = static_cast<GLenum*>(state->buffer);
3013 state->results_buffer = pnames_buffer + state->pnames_count;
3014 memcpy(pnames_buffer, state->pnames, state->pnames_count * sizeof(GLenum));
3015 memset(state->results_buffer, 0, state->num_results * sizeof(GLint));
3016 helper_->GetMultipleIntegervCHROMIUM(
3017 transfer_buffer_->GetShmId(),
3018 transfer_buffer_->GetOffset(pnames_buffer),
3019 state->pnames_count,
3020 transfer_buffer_->GetShmId(),
3021 transfer_buffer_->GetOffset(state->results_buffer),
3022 state->results_size);
3025 void GLES2Implementation::GetMultipleIntegervOnCompleted(
3026 GetMultipleIntegervState* state) {
3027 memcpy(state->results, state->results_buffer, state->results_size);;
3030 void GLES2Implementation::GetAllShaderPrecisionFormatsSetup(
3031 GetAllShaderPrecisionFormatsState* state) {
3032 state->transfer_buffer_size_needed =
3033 state->precision_params_count *
3034 sizeof(cmds::GetShaderPrecisionFormat::Result);
3037 void GLES2Implementation::GetAllShaderPrecisionFormatsRequest(
3038 GetAllShaderPrecisionFormatsState* state) {
3039 typedef cmds::GetShaderPrecisionFormat::Result Result;
3040 Result* result = static_cast<Result*>(state->results_buffer);
3042 for (int i = 0; i < state->precision_params_count; i++) {
3043 result->success = false;
3044 helper_->GetShaderPrecisionFormat(state->precision_params[i][0],
3045 state->precision_params[i][1],
3046 transfer_buffer_->GetShmId(),
3047 transfer_buffer_->GetOffset(result));
3048 result++;
3052 void GLES2Implementation::GetAllShaderPrecisionFormatsOnCompleted(
3053 GetAllShaderPrecisionFormatsState* state) {
3054 typedef cmds::GetShaderPrecisionFormat::Result Result;
3055 Result* result = static_cast<Result*>(state->results_buffer);
3057 for (int i = 0; i < state->precision_params_count; i++) {
3058 if (result->success) {
3059 const GLStaticState::ShaderPrecisionKey key(
3060 state->precision_params[i][0], state->precision_params[i][1]);
3061 static_state_.shader_precisions[key] = *result;
3063 result++;
3067 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3068 GLuint program, std::vector<int8>* result) {
3069 GPU_DCHECK(result);
3070 // Clear the bucket so if the command fails nothing will be in it.
3071 helper_->SetBucketSize(kResultBucketId, 0);
3072 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
3073 GetBucketContents(kResultBucketId, result);
3076 void GLES2Implementation::GetProgramInfoCHROMIUM(
3077 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3078 GPU_CLIENT_SINGLE_THREAD_CHECK();
3079 if (bufsize < 0) {
3080 SetGLError(
3081 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3082 return;
3084 if (size == NULL) {
3085 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
3086 return;
3088 // Make sure they've set size to 0 else the value will be undefined on
3089 // lost context.
3090 GPU_DCHECK(*size == 0);
3091 std::vector<int8> result;
3092 GetProgramInfoCHROMIUMHelper(program, &result);
3093 if (result.empty()) {
3094 return;
3096 *size = result.size();
3097 if (!info) {
3098 return;
3100 if (static_cast<size_t>(bufsize) < result.size()) {
3101 SetGLError(GL_INVALID_OPERATION,
3102 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3103 return;
3105 memcpy(info, &result[0], result.size());
3108 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
3109 GPU_CLIENT_SINGLE_THREAD_CHECK();
3110 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
3111 << texture << ")");
3112 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
3113 typedef cmds::CreateStreamTextureCHROMIUM::Result Result;
3114 Result* result = GetResultAs<Result*>();
3115 if (!result) {
3116 return GL_ZERO;
3118 *result = GL_ZERO;
3120 helper_->CreateStreamTextureCHROMIUM(texture,
3121 GetResultShmId(),
3122 GetResultShmOffset());
3123 WaitForCmd();
3124 GLuint result_value = *result;
3125 CheckGLError();
3126 return result_value;
3129 void GLES2Implementation::DestroyStreamTextureCHROMIUM(GLuint texture) {
3130 GPU_CLIENT_SINGLE_THREAD_CHECK();
3131 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] DestroyStreamTextureCHROMIUM("
3132 << texture << ")");
3133 TRACE_EVENT0("gpu", "GLES2::DestroyStreamTextureCHROMIUM");
3134 helper_->DestroyStreamTextureCHROMIUM(texture);
3135 CheckGLError();
3138 void GLES2Implementation::PostSubBufferCHROMIUM(
3139 GLint x, GLint y, GLint width, GLint height) {
3140 GPU_CLIENT_SINGLE_THREAD_CHECK();
3141 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
3142 << x << ", " << y << ", " << width << ", " << height << ")");
3143 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
3144 "width", width, "height", height);
3146 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
3147 swap_buffers_tokens_.push(helper_->InsertToken());
3148 helper_->PostSubBufferCHROMIUM(x, y, width, height);
3149 helper_->CommandBufferHelper::Flush();
3150 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
3151 helper_->WaitForToken(swap_buffers_tokens_.front());
3152 swap_buffers_tokens_.pop();
3156 void GLES2Implementation::DeleteQueriesEXTHelper(
3157 GLsizei n, const GLuint* queries) {
3158 // TODO(gman): Remove this as queries are not shared resources.
3159 if (!GetIdHandler(id_namespaces::kQueries)->FreeIds(
3160 this, n, queries, &GLES2Implementation::DeleteQueriesStub)) {
3161 SetGLError(
3162 GL_INVALID_VALUE,
3163 "glDeleteTextures", "id not created by this context.");
3164 return;
3167 for (GLsizei ii = 0; ii < n; ++ii)
3168 query_tracker_->RemoveQuery(queries[ii]);
3170 helper_->DeleteQueriesEXTImmediate(n, queries);
3173 // TODO(gman): Remove this. Queries are not shared resources.
3174 void GLES2Implementation::DeleteQueriesStub(
3175 GLsizei /* n */, const GLuint* /* queries */) {
3178 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
3179 GPU_CLIENT_SINGLE_THREAD_CHECK();
3180 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
3182 // TODO(gman): To be spec compliant IDs from other contexts sharing
3183 // resources need to return true here even though you can't share
3184 // queries across contexts?
3185 return query_tracker_->GetQuery(id) != NULL;
3188 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
3189 GPU_CLIENT_SINGLE_THREAD_CHECK();
3190 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
3191 << GLES2Util::GetStringQueryTarget(target)
3192 << ", " << id << ")");
3194 // if any outstanding queries INV_OP
3195 if (current_query_) {
3196 SetGLError(
3197 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
3198 return;
3201 // id = 0 INV_OP
3202 if (id == 0) {
3203 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
3204 return;
3207 // TODO(gman) if id not GENned INV_OPERATION
3209 // if id does not have an object
3210 QueryTracker::Query* query = query_tracker_->GetQuery(id);
3211 if (!query) {
3212 query = query_tracker_->CreateQuery(id, target);
3213 if (!query) {
3214 MustBeContextLost();
3215 return;
3217 } else if (query->target() != target) {
3218 SetGLError(
3219 GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
3220 return;
3223 current_query_ = query;
3225 query->Begin(this);
3226 CheckGLError();
3229 void GLES2Implementation::EndQueryEXT(GLenum target) {
3230 GPU_CLIENT_SINGLE_THREAD_CHECK();
3231 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
3232 << GLES2Util::GetStringQueryTarget(target) << ")");
3233 // Don't do anything if the context is lost.
3234 if (helper_->IsContextLost()) {
3235 return;
3238 if (!current_query_) {
3239 SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
3240 return;
3243 if (current_query_->target() != target) {
3244 SetGLError(GL_INVALID_OPERATION,
3245 "glEndQueryEXT", "target does not match active query");
3246 return;
3249 current_query_->End(this);
3250 current_query_ = NULL;
3251 CheckGLError();
3254 void GLES2Implementation::GetQueryivEXT(
3255 GLenum target, GLenum pname, GLint* params) {
3256 GPU_CLIENT_SINGLE_THREAD_CHECK();
3257 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
3258 << GLES2Util::GetStringQueryTarget(target) << ", "
3259 << GLES2Util::GetStringQueryParameter(pname) << ", "
3260 << static_cast<const void*>(params) << ")");
3262 if (pname != GL_CURRENT_QUERY_EXT) {
3263 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
3264 return;
3266 *params = (current_query_ && current_query_->target() == target) ?
3267 current_query_->id() : 0;
3268 GPU_CLIENT_LOG(" " << *params);
3269 CheckGLError();
3272 void GLES2Implementation::GetQueryObjectuivEXT(
3273 GLuint id, GLenum pname, GLuint* params) {
3274 GPU_CLIENT_SINGLE_THREAD_CHECK();
3275 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
3276 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
3277 << static_cast<const void*>(params) << ")");
3279 QueryTracker::Query* query = query_tracker_->GetQuery(id);
3280 if (!query) {
3281 SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
3282 return;
3285 if (query == current_query_) {
3286 SetGLError(
3287 GL_INVALID_OPERATION,
3288 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
3289 return;
3292 if (query->NeverUsed()) {
3293 SetGLError(
3294 GL_INVALID_OPERATION,
3295 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
3296 return;
3299 switch (pname) {
3300 case GL_QUERY_RESULT_EXT:
3301 if (!query->CheckResultsAvailable(helper_)) {
3302 helper_->WaitForToken(query->token());
3303 if (!query->CheckResultsAvailable(helper_)) {
3304 // TODO(gman): Speed this up.
3305 WaitForCmd();
3306 GPU_CHECK(query->CheckResultsAvailable(helper_));
3309 *params = query->GetResult();
3310 break;
3311 case GL_QUERY_RESULT_AVAILABLE_EXT:
3312 *params = query->CheckResultsAvailable(helper_);
3313 break;
3314 default:
3315 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
3316 break;
3318 GPU_CLIENT_LOG(" " << *params);
3319 CheckGLError();
3322 void GLES2Implementation::DrawArraysInstancedANGLE(
3323 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
3324 GPU_CLIENT_SINGLE_THREAD_CHECK();
3325 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
3326 << GLES2Util::GetStringDrawMode(mode) << ", "
3327 << first << ", " << count << ", " << primcount << ")");
3328 if (count < 0) {
3329 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
3330 return;
3332 if (primcount < 0) {
3333 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
3334 return;
3336 if (primcount == 0) {
3337 return;
3339 bool simulated = false;
3340 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
3341 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
3342 &simulated)) {
3343 return;
3345 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
3346 RestoreArrayBuffer(simulated);
3347 CheckGLError();
3350 void GLES2Implementation::DrawElementsInstancedANGLE(
3351 GLenum mode, GLsizei count, GLenum type, const void* indices,
3352 GLsizei primcount) {
3353 GPU_CLIENT_SINGLE_THREAD_CHECK();
3354 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
3355 << GLES2Util::GetStringDrawMode(mode) << ", "
3356 << count << ", "
3357 << GLES2Util::GetStringIndexType(type) << ", "
3358 << static_cast<const void*>(indices) << ", "
3359 << primcount << ")");
3360 if (count < 0) {
3361 SetGLError(GL_INVALID_VALUE,
3362 "glDrawElementsInstancedANGLE", "count less than 0.");
3363 return;
3365 if (count == 0) {
3366 return;
3368 if (primcount < 0) {
3369 SetGLError(GL_INVALID_VALUE,
3370 "glDrawElementsInstancedANGLE", "primcount < 0");
3371 return;
3373 if (primcount == 0) {
3374 return;
3376 GLuint offset = 0;
3377 bool simulated = false;
3378 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
3379 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
3380 indices, &offset, &simulated)) {
3381 return;
3383 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
3384 RestoreElementAndArrayBuffers(simulated);
3385 CheckGLError();
3388 void GLES2Implementation::GenMailboxCHROMIUM(
3389 GLbyte* mailbox) {
3390 GPU_CLIENT_SINGLE_THREAD_CHECK();
3391 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
3392 << static_cast<const void*>(mailbox) << ")");
3393 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
3395 helper_->GenMailboxCHROMIUM(kResultBucketId);
3397 std::vector<GLbyte> result;
3398 GetBucketContents(kResultBucketId, &result);
3400 std::copy(result.begin(), result.end(), mailbox);
3401 CheckGLError();
3404 void GLES2Implementation::PushGroupMarkerEXT(
3405 GLsizei length, const GLchar* marker) {
3406 GPU_CLIENT_SINGLE_THREAD_CHECK();
3407 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
3408 << length << ", " << marker << ")");
3409 if (!marker) {
3410 marker = "";
3412 SetBucketAsString(
3413 kResultBucketId,
3414 (length ? std::string(marker, length) : std::string(marker)));
3415 helper_->PushGroupMarkerEXT(kResultBucketId);
3416 helper_->SetBucketSize(kResultBucketId, 0);
3417 debug_marker_manager_.PushGroup(
3418 length ? std::string(marker, length) : std::string(marker));
3421 void GLES2Implementation::InsertEventMarkerEXT(
3422 GLsizei length, const GLchar* marker) {
3423 GPU_CLIENT_SINGLE_THREAD_CHECK();
3424 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
3425 << length << ", " << marker << ")");
3426 if (!marker) {
3427 marker = "";
3429 SetBucketAsString(
3430 kResultBucketId,
3431 (length ? std::string(marker, length) : std::string(marker)));
3432 helper_->InsertEventMarkerEXT(kResultBucketId);
3433 helper_->SetBucketSize(kResultBucketId, 0);
3434 debug_marker_manager_.SetMarker(
3435 length ? std::string(marker, length) : std::string(marker));
3438 void GLES2Implementation::PopGroupMarkerEXT() {
3439 GPU_CLIENT_SINGLE_THREAD_CHECK();
3440 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
3441 helper_->PopGroupMarkerEXT();
3442 debug_marker_manager_.PopGroup();
3445 void GLES2Implementation::TraceBeginCHROMIUM(const char* name) {
3446 GPU_CLIENT_SINGLE_THREAD_CHECK();
3447 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
3448 << name << ")");
3449 if (current_trace_name_.get()) {
3450 SetGLError(GL_INVALID_OPERATION, "glTraceBeginCHROMIUM",
3451 "trace already running");
3452 return;
3454 TRACE_EVENT_COPY_ASYNC_BEGIN0("gpu", name, this);
3455 SetBucketAsCString(kResultBucketId, name);
3456 helper_->TraceBeginCHROMIUM(kResultBucketId);
3457 helper_->SetBucketSize(kResultBucketId, 0);
3458 current_trace_name_.reset(new std::string(name));
3461 void GLES2Implementation::TraceEndCHROMIUM() {
3462 GPU_CLIENT_SINGLE_THREAD_CHECK();
3463 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
3464 if (!current_trace_name_.get()) {
3465 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
3466 "missing begin trace");
3467 return;
3469 helper_->TraceEndCHROMIUM();
3470 TRACE_EVENT_COPY_ASYNC_END0("gpu", current_trace_name_->c_str(), this);
3471 current_trace_name_.reset();
3474 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
3475 GPU_CLIENT_SINGLE_THREAD_CHECK();
3476 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
3477 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
3478 switch (target) {
3479 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3480 if (access != GL_READ_ONLY) {
3481 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3482 return NULL;
3484 break;
3485 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3486 if (access != GL_WRITE_ONLY) {
3487 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3488 return NULL;
3490 break;
3491 default:
3492 SetGLError(
3493 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
3494 return NULL;
3496 GLuint buffer_id;
3497 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
3498 if (!buffer_id) {
3499 return NULL;
3501 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3502 if (!buffer) {
3503 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
3504 return NULL;
3506 if (buffer->mapped()) {
3507 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
3508 return NULL;
3510 // Here we wait for previous transfer operations to be finished.
3511 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
3512 // with this method of synchronization. Until this is fixed,
3513 // MapBufferCHROMIUM will not block even if the transfer is not ready
3514 // for these calls.
3515 if (buffer->transfer_ready_token()) {
3516 helper_->WaitForToken(buffer->transfer_ready_token());
3517 buffer->set_transfer_ready_token(0);
3519 buffer->set_mapped(true);
3521 GPU_CLIENT_LOG(" returned " << buffer->address());
3522 CheckGLError();
3523 return buffer->address();
3526 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
3527 GPU_CLIENT_SINGLE_THREAD_CHECK();
3528 GPU_CLIENT_LOG(
3529 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
3530 GLuint buffer_id;
3531 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
3532 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
3534 if (!buffer_id) {
3535 return false;
3537 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3538 if (!buffer) {
3539 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
3540 return false;
3542 if (!buffer->mapped()) {
3543 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
3544 return false;
3546 buffer->set_mapped(false);
3547 CheckGLError();
3548 return true;
3551 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
3552 GLenum target, GLint level, GLint internalformat, GLsizei width,
3553 GLsizei height, GLint border, GLenum format, GLenum type,
3554 const void* pixels) {
3555 GPU_CLIENT_SINGLE_THREAD_CHECK();
3556 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
3557 << GLES2Util::GetStringTextureTarget(target) << ", "
3558 << level << ", "
3559 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
3560 << width << ", " << height << ", " << border << ", "
3561 << GLES2Util::GetStringTextureFormat(format) << ", "
3562 << GLES2Util::GetStringPixelType(type) << ", "
3563 << static_cast<const void*>(pixels) << ")");
3564 if (level < 0 || height < 0 || width < 0) {
3565 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
3566 return;
3568 uint32 size;
3569 uint32 unpadded_row_size;
3570 uint32 padded_row_size;
3571 if (!GLES2Util::ComputeImageDataSizes(
3572 width, height, format, type, unpack_alignment_, &size,
3573 &unpadded_row_size, &padded_row_size)) {
3574 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
3575 return;
3578 // If there's no data/buffer just issue the AsyncTexImage2D
3579 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
3580 helper_->AsyncTexImage2DCHROMIUM(
3581 target, level, internalformat, width, height, border, format, type,
3582 0, 0);
3583 return;
3586 // Otherwise, async uploads require a transfer buffer to be bound.
3587 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3588 // the buffer before the transfer is finished. (Currently such
3589 // synchronization has to be handled manually.)
3590 GLuint offset = ToGLuint(pixels);
3591 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3592 bound_pixel_unpack_transfer_buffer_id_,
3593 "glAsyncTexImage2DCHROMIUM", offset, size);
3594 if (buffer && buffer->shm_id() != -1) {
3595 helper_->AsyncTexImage2DCHROMIUM(
3596 target, level, internalformat, width, height, border, format, type,
3597 buffer->shm_id(), buffer->shm_offset() + offset);
3601 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
3602 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
3603 GLsizei height, GLenum format, GLenum type, const void* pixels) {
3604 GPU_CLIENT_SINGLE_THREAD_CHECK();
3605 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
3606 << GLES2Util::GetStringTextureTarget(target) << ", "
3607 << level << ", "
3608 << xoffset << ", " << yoffset << ", "
3609 << width << ", " << height << ", "
3610 << GLES2Util::GetStringTextureFormat(format) << ", "
3611 << GLES2Util::GetStringPixelType(type) << ", "
3612 << static_cast<const void*>(pixels) << ")");
3613 if (level < 0 || height < 0 || width < 0) {
3614 SetGLError(
3615 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
3616 return;
3619 uint32 size;
3620 uint32 unpadded_row_size;
3621 uint32 padded_row_size;
3622 if (!GLES2Util::ComputeImageDataSizes(
3623 width, height, format, type, unpack_alignment_, &size,
3624 &unpadded_row_size, &padded_row_size)) {
3625 SetGLError(
3626 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
3627 return;
3630 // Async uploads require a transfer buffer to be bound.
3631 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3632 // the buffer before the transfer is finished. (Currently such
3633 // synchronization has to be handled manually.)
3634 GLuint offset = ToGLuint(pixels);
3635 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3636 bound_pixel_unpack_transfer_buffer_id_,
3637 "glAsyncTexSubImage2DCHROMIUM", offset, size);
3638 if (buffer && buffer->shm_id() != -1) {
3639 helper_->AsyncTexSubImage2DCHROMIUM(
3640 target, level, xoffset, yoffset, width, height, format, type,
3641 buffer->shm_id(), buffer->shm_offset() + offset);
3645 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
3646 GPU_CLIENT_SINGLE_THREAD_CHECK();
3647 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
3648 << GLES2Util::GetStringTextureTarget(target) << ")");
3649 helper_->WaitAsyncTexImage2DCHROMIUM(target);
3650 CheckGLError();
3653 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
3654 GPU_CLIENT_SINGLE_THREAD_CHECK();
3655 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
3656 return helper_->InsertSyncPointCHROMIUM();
3659 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(
3660 GLsizei width, GLsizei height, GLenum internalformat) {
3661 if (width <= 0) {
3662 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
3663 return 0;
3666 if (height <= 0) {
3667 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
3668 return 0;
3670 // Flush the command stream to ensure ordering in case the newly
3671 // returned image_id has recently been in use with a different buffer.
3672 helper_->CommandBufferHelper::Flush();
3674 // Create new buffer.
3675 GLuint buffer_id = gpu_memory_buffer_tracker_->CreateBuffer(
3676 width, height, internalformat);
3677 if (buffer_id == 0) {
3678 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "out of GPU memory.");
3679 return 0;
3681 return buffer_id;
3684 GLuint GLES2Implementation::CreateImageCHROMIUM(
3685 GLsizei width, GLsizei height, GLenum internalformat) {
3686 GPU_CLIENT_SINGLE_THREAD_CHECK();
3687 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM("
3688 << width << ", "
3689 << height << ", "
3690 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ")");
3691 GLuint image_id = CreateImageCHROMIUMHelper(width, height, internalformat);
3692 CheckGLError();
3693 return image_id;
3696 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
3697 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3698 image_id);
3699 if (!gpu_buffer) {
3700 SetGLError(GL_INVALID_OPERATION, "glDestroyImageCHROMIUM", "invalid image");
3701 return;
3704 // Flush the command stream to make sure all pending commands
3705 // that may refer to the image_id are executed on the service side.
3706 helper_->CommandBufferHelper::Flush();
3707 gpu_memory_buffer_tracker_->RemoveBuffer(image_id);
3710 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
3711 GPU_CLIENT_SINGLE_THREAD_CHECK();
3712 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
3713 << image_id << ")");
3714 DestroyImageCHROMIUMHelper(image_id);
3715 CheckGLError();
3718 void GLES2Implementation::UnmapImageCHROMIUMHelper(GLuint image_id) {
3719 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3720 image_id);
3721 if (!gpu_buffer) {
3722 SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "invalid image");
3723 return;
3726 if (!gpu_buffer->IsMapped()) {
3727 SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "not mapped");
3728 return;
3730 gpu_buffer->Unmap();
3733 void GLES2Implementation::UnmapImageCHROMIUM(GLuint image_id) {
3734 GPU_CLIENT_SINGLE_THREAD_CHECK();
3735 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapImageCHROMIUM("
3736 << image_id << ")");
3738 UnmapImageCHROMIUMHelper(image_id);
3739 CheckGLError();
3742 void* GLES2Implementation::MapImageCHROMIUMHelper(GLuint image_id,
3743 GLenum access) {
3744 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3745 image_id);
3746 if (!gpu_buffer) {
3747 SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "invalid image");
3748 return NULL;
3750 gfx::GpuMemoryBuffer::AccessMode mode;
3751 switch(access) {
3752 case GL_WRITE_ONLY:
3753 mode = gfx::GpuMemoryBuffer::WRITE_ONLY;
3754 break;
3755 case GL_READ_ONLY:
3756 mode = gfx::GpuMemoryBuffer::READ_ONLY;
3757 break;
3758 case GL_READ_WRITE:
3759 mode = gfx::GpuMemoryBuffer::READ_WRITE;
3760 break;
3761 default:
3762 SetGLError(GL_INVALID_ENUM, "glMapImageCHROMIUM",
3763 "invalid GPU access mode");
3764 return NULL;
3767 if (gpu_buffer->IsMapped()) {
3768 SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "already mapped");
3769 return NULL;
3772 void* mapped_buffer = NULL;
3773 gpu_buffer->Map(mode, &mapped_buffer);
3774 return mapped_buffer;
3777 void* GLES2Implementation::MapImageCHROMIUM(
3778 GLuint image_id, GLenum access) {
3779 GPU_CLIENT_SINGLE_THREAD_CHECK();
3780 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapImageCHROMIUM("
3781 << image_id << ", "
3782 << GLES2Util::GetStringEnum(access) << ")");
3784 void* mapped = MapImageCHROMIUMHelper(image_id, access);
3785 CheckGLError();
3786 return mapped;
3789 void GLES2Implementation::GetImageParameterivCHROMIUMHelper(
3790 GLuint image_id, GLenum pname, GLint* params) {
3791 if (pname != GL_IMAGE_ROWBYTES_CHROMIUM) {
3792 SetGLError(GL_INVALID_ENUM, "glGetImageParameterivCHROMIUM",
3793 "invalid parameter");
3794 return;
3797 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3798 image_id);
3799 if (!gpu_buffer) {
3800 SetGLError(GL_INVALID_OPERATION, "glGetImageParameterivCHROMIUM",
3801 "invalid image");
3802 return;
3805 *params = gpu_buffer->GetStride();
3808 void GLES2Implementation::GetImageParameterivCHROMIUM(
3809 GLuint image_id, GLenum pname, GLint* params) {
3810 GPU_CLIENT_SINGLE_THREAD_CHECK();
3811 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
3812 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glImageParameterivCHROMIUM("
3813 << image_id << ", "
3814 << GLES2Util::GetStringBufferParameter(pname) << ", "
3815 << static_cast<const void*>(params) << ")");
3816 GetImageParameterivCHROMIUMHelper(image_id, pname, params);
3817 CheckGLError();
3820 // Include the auto-generated part of this file. We split this because it means
3821 // we can easily edit the non-auto generated parts right here in this file
3822 // instead of having to edit some template or the code generator.
3823 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
3825 } // namespace gles2
3826 } // namespace gpu