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"
16 #include <GLES2/gl2ext.h>
17 #include <GLES2/gl2extchromium.h>
18 #include "gpu/command_buffer/client/buffer_tracker.h"
19 #include "gpu/command_buffer/client/gpu_memory_buffer_tracker.h"
20 #include "gpu/command_buffer/client/program_info_manager.h"
21 #include "gpu/command_buffer/client/query_tracker.h"
22 #include "gpu/command_buffer/client/transfer_buffer.h"
23 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
24 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
25 #include "gpu/command_buffer/common/gpu_control.h"
26 #include "gpu/command_buffer/common/trace_event.h"
27 #include "ui/gfx/gpu_memory_buffer.h"
29 #if defined(__native_client__) && !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
30 #define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS
33 #if defined(GPU_CLIENT_DEBUG)
34 #include "ui/gl/gl_switches.h"
35 #include "base/command_line.h"
41 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
42 static GLuint ToGLuint(const void* ptr) {
43 return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
46 #if !defined(_MSC_VER)
47 const size_t GLES2Implementation::kMaxSizeOfSimpleResult;
48 const unsigned int GLES2Implementation::kStartingOffset;
51 GLES2Implementation::GLStaticState::GLStaticState() {
54 GLES2Implementation::GLStaticState::~GLStaticState() {
57 GLES2Implementation::GLStaticState::IntState::IntState()
58 : max_combined_texture_image_units(0),
59 max_cube_map_texture_size(0),
60 max_fragment_uniform_vectors(0),
61 max_renderbuffer_size(0),
62 max_texture_image_units(0),
64 max_varying_vectors(0),
65 max_vertex_attribs(0),
66 max_vertex_texture_image_units(0),
67 max_vertex_uniform_vectors(0),
68 num_compressed_texture_formats(0),
69 num_shader_binary_formats(0) {
72 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
73 GLES2Implementation* gles2_implementation)
74 : gles2_implementation_(gles2_implementation) {
75 GPU_CHECK_EQ(0, gles2_implementation_->use_count_);
76 ++gles2_implementation_->use_count_;
79 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
80 --gles2_implementation_->use_count_;
81 GPU_CHECK_EQ(0, gles2_implementation_->use_count_);
84 GLES2Implementation::GLES2Implementation(
85 GLES2CmdHelper* helper,
86 ShareGroup* share_group,
87 TransferBufferInterface* transfer_buffer,
88 bool bind_generates_resource,
89 GpuControl* gpu_control)
91 transfer_buffer_(transfer_buffer),
92 angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
93 chromium_framebuffer_multisample_(kUnknownExtensionStatus),
96 unpack_flip_y_(false),
97 unpack_row_length_(0),
99 unpack_skip_pixels_(0),
100 pack_reverse_row_order_(false),
101 active_texture_unit_(0),
102 bound_framebuffer_(0),
103 bound_read_framebuffer_(0),
104 bound_renderbuffer_(0),
106 bound_array_buffer_id_(0),
107 bound_pixel_pack_transfer_buffer_id_(0),
108 bound_pixel_unpack_transfer_buffer_id_(0),
112 current_query_(NULL),
113 error_message_callback_(NULL),
114 gpu_control_(gpu_control),
115 weak_ptr_factory_(this) {
117 GPU_DCHECK(transfer_buffer);
118 GPU_DCHECK(gpu_control);
121 sprintf(temp, "%p", static_cast<void*>(this));
122 this_in_hex_ = std::string(temp);
124 GPU_CLIENT_LOG_CODE_BLOCK({
125 debug_ = CommandLine::ForCurrentProcess()->HasSwitch(
126 switches::kEnableGPUClientLogging);
130 (share_group ? share_group : new ShareGroup(bind_generates_resource));
132 memset(&reserved_ids_, 0, sizeof(reserved_ids_));
135 bool GLES2Implementation::Initialize(
136 unsigned int starting_transfer_buffer_size,
137 unsigned int min_transfer_buffer_size,
138 unsigned int max_transfer_buffer_size,
139 unsigned int mapped_memory_limit) {
140 GPU_DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
141 GPU_DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
142 GPU_DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
144 if (!transfer_buffer_->Initialize(
145 starting_transfer_buffer_size,
147 min_transfer_buffer_size,
148 max_transfer_buffer_size,
154 mapped_memory_.reset(new MappedMemoryManager(helper_, mapped_memory_limit));
156 unsigned chunk_size = 2 * 1024 * 1024;
157 if (mapped_memory_limit != kNoLimit) {
158 // Use smaller chunks if the client is very memory conscientious.
159 chunk_size = std::min(mapped_memory_limit / 4, chunk_size);
161 mapped_memory_->set_chunk_size_multiple(chunk_size);
163 if (!QueryAndCacheStaticState())
166 util_.set_num_compressed_texture_formats(
167 static_state_.int_state.num_compressed_texture_formats);
168 util_.set_num_shader_binary_formats(
169 static_state_.int_state.num_shader_binary_formats);
171 texture_units_.reset(
173 static_state_.int_state.max_combined_texture_image_units]);
175 query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
176 buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
177 gpu_memory_buffer_tracker_.reset(new GpuMemoryBufferTracker(gpu_control_));
179 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
180 GetIdHandler(id_namespaces::kBuffers)->MakeIds(
181 this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
184 vertex_array_object_manager_.reset(new VertexArrayObjectManager(
185 static_state_.int_state.max_vertex_attribs,
192 bool GLES2Implementation::QueryAndCacheStaticState() {
193 // Setup query for multiple GetIntegerv's
194 static const GLenum pnames[] = {
195 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
196 GL_MAX_CUBE_MAP_TEXTURE_SIZE,
197 GL_MAX_FRAGMENT_UNIFORM_VECTORS,
198 GL_MAX_RENDERBUFFER_SIZE,
199 GL_MAX_TEXTURE_IMAGE_UNITS,
201 GL_MAX_VARYING_VECTORS,
202 GL_MAX_VERTEX_ATTRIBS,
203 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
204 GL_MAX_VERTEX_UNIFORM_VECTORS,
205 GL_NUM_COMPRESSED_TEXTURE_FORMATS,
206 GL_NUM_SHADER_BINARY_FORMATS,
209 GetMultipleIntegervState integerv_state(
210 pnames, arraysize(pnames),
211 &static_state_.int_state.max_combined_texture_image_units,
212 sizeof(static_state_.int_state));
213 if (!GetMultipleIntegervSetup(&integerv_state)) {
217 // Setup query for multiple GetShaderPrecisionFormat's
218 static const GLenum precision_params[][2] = {
219 { GL_VERTEX_SHADER, GL_LOW_INT },
220 { GL_VERTEX_SHADER, GL_MEDIUM_INT },
221 { GL_VERTEX_SHADER, GL_HIGH_INT },
222 { GL_VERTEX_SHADER, GL_LOW_FLOAT },
223 { GL_VERTEX_SHADER, GL_MEDIUM_FLOAT },
224 { GL_VERTEX_SHADER, GL_HIGH_FLOAT },
225 { GL_FRAGMENT_SHADER, GL_LOW_INT },
226 { GL_FRAGMENT_SHADER, GL_MEDIUM_INT },
227 { GL_FRAGMENT_SHADER, GL_HIGH_INT },
228 { GL_FRAGMENT_SHADER, GL_LOW_FLOAT },
229 { GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT },
230 { GL_FRAGMENT_SHADER, GL_HIGH_FLOAT },
233 GetAllShaderPrecisionFormatsState precision_state(
234 precision_params, arraysize(precision_params));
235 GetAllShaderPrecisionFormatsSetup(&precision_state);
237 // Allocate and partition transfer buffer for all requests
238 void* buffer = transfer_buffer_->Alloc(
239 integerv_state.transfer_buffer_size_needed +
240 precision_state.transfer_buffer_size_needed);
242 SetGLError(GL_OUT_OF_MEMORY, "QueryAndCacheStaticState",
243 "Transfer buffer allocation failed.");
246 integerv_state.buffer = buffer;
247 precision_state.results_buffer =
248 static_cast<char*>(buffer) + integerv_state.transfer_buffer_size_needed;
250 // Make all the requests and wait once for all the results.
251 GetMultipleIntegervRequest(&integerv_state);
252 GetAllShaderPrecisionFormatsRequest(&precision_state);
254 GetMultipleIntegervOnCompleted(&integerv_state);
255 GetAllShaderPrecisionFormatsOnCompleted(&precision_state);
257 // TODO(gman): We should be able to free without a token.
258 transfer_buffer_->FreePendingToken(buffer, helper_->InsertToken());
264 GLES2Implementation::~GLES2Implementation() {
265 // Make sure the queries are finished otherwise we'll delete the
266 // shared memory (mapped_memory_) which will free the memory used
267 // by the queries. The GPU process when validating that memory is still
268 // shared will fail and abort (ie, it will stop running).
270 query_tracker_.reset();
272 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
273 DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
275 buffer_tracker_.reset();
277 // Make sure the commands make it the service.
281 GLES2CmdHelper* GLES2Implementation::helper() const {
285 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
286 return share_group_->GetIdHandler(namespace_id);
289 void* GLES2Implementation::GetResultBuffer() {
290 return transfer_buffer_->GetResultBuffer();
293 int32 GLES2Implementation::GetResultShmId() {
294 return transfer_buffer_->GetShmId();
297 uint32 GLES2Implementation::GetResultShmOffset() {
298 return transfer_buffer_->GetResultOffset();
301 void GLES2Implementation::FreeUnusedSharedMemory() {
302 mapped_memory_->FreeUnused();
305 void GLES2Implementation::FreeEverything() {
307 query_tracker_->Shrink();
308 FreeUnusedSharedMemory();
309 transfer_buffer_->Free();
310 helper_->FreeRingBuffer();
313 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
314 if (!helper_->IsContextLost())
318 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
319 const base::Closure& callback) {
320 gpu_control_->SignalSyncPoint(
322 base::Bind(&GLES2Implementation::RunIfContextNotLost,
323 weak_ptr_factory_.GetWeakPtr(),
327 void GLES2Implementation::SignalQuery(uint32 query,
328 const base::Closure& callback) {
329 // Flush previously entered commands to ensure ordering with any
330 // glBeginQueryEXT() calls that may have been put into the context.
331 ShallowFlushCHROMIUM();
332 gpu_control_->SignalQuery(
334 base::Bind(&GLES2Implementation::RunIfContextNotLost,
335 weak_ptr_factory_.GetWeakPtr(),
339 void GLES2Implementation::SendManagedMemoryStats(
340 const ManagedMemoryStats& stats) {
341 gpu_control_->SendManagedMemoryStats(stats);
344 void GLES2Implementation::WaitForCmd() {
345 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
346 helper_->CommandBufferHelper::Finish();
349 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
350 const char* extensions =
351 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
355 int length = strlen(ext);
357 int n = strcspn(extensions, " ");
358 if (n == length && 0 == strncmp(ext, extensions, length)) {
361 if ('\0' == extensions[n]) {
368 bool GLES2Implementation::IsExtensionAvailableHelper(
369 const char* extension, ExtensionStatus* status) {
371 case kAvailableExtensionStatus:
373 case kUnavailableExtensionStatus:
376 bool available = IsExtensionAvailable(extension);
377 *status = available ? kAvailableExtensionStatus :
378 kUnavailableExtensionStatus;
384 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
385 return IsExtensionAvailableHelper(
386 "GL_ANGLE_pack_reverse_row_order",
387 &angle_pack_reverse_row_order_status_);
390 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
391 return IsExtensionAvailableHelper(
392 "GL_CHROMIUM_framebuffer_multisample",
393 &chromium_framebuffer_multisample_);
396 const std::string& GLES2Implementation::GetLogPrefix() const {
397 const std::string& prefix(debug_marker_manager_.GetMarker());
398 return prefix.empty() ? this_in_hex_ : prefix;
401 GLenum GLES2Implementation::GetError() {
402 GPU_CLIENT_SINGLE_THREAD_CHECK();
403 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
404 GLenum err = GetGLError();
405 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
409 GLenum GLES2Implementation::GetClientSideGLError() {
410 if (error_bits_ == 0) {
414 GLenum error = GL_NO_ERROR;
415 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
416 if ((error_bits_ & mask) != 0) {
417 error = GLES2Util::GLErrorBitToGLError(mask);
421 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
425 GLenum GLES2Implementation::GetGLError() {
426 TRACE_EVENT0("gpu", "GLES2::GetGLError");
427 // Check the GL error first, then our wrapped error.
428 typedef cmds::GetError::Result Result;
429 Result* result = GetResultAs<Result*>();
430 // If we couldn't allocate a result the context is lost.
434 *result = GL_NO_ERROR;
435 helper_->GetError(GetResultShmId(), GetResultShmOffset());
437 GLenum error = *result;
438 if (error == GL_NO_ERROR) {
439 error = GetClientSideGLError();
441 // There was an error, clear the corresponding wrapped error.
442 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
447 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
448 void GLES2Implementation::FailGLError(GLenum error) {
449 if (error != GL_NO_ERROR) {
450 GPU_NOTREACHED() << "Error";
453 // NOTE: Calling GetGLError overwrites data in the result buffer.
454 void GLES2Implementation::CheckGLError() {
455 FailGLError(GetGLError());
457 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
459 void GLES2Implementation::SetGLError(
460 GLenum error, const char* function_name, const char* msg) {
461 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
462 << GLES2Util::GetStringError(error) << ": "
463 << function_name << ": " << msg);
468 if (error_message_callback_) {
469 std::string temp(GLES2Util::GetStringError(error) + " : " +
470 function_name + ": " + (msg ? msg : ""));
471 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
473 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
476 void GLES2Implementation::SetGLErrorInvalidEnum(
477 const char* function_name, GLenum value, const char* label) {
478 SetGLError(GL_INVALID_ENUM, function_name,
479 (std::string(label) + " was " +
480 GLES2Util::GetStringEnum(value)).c_str());
483 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
484 std::vector<int8>* data) {
485 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
487 const uint32 kStartSize = 32 * 1024;
488 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
489 if (!buffer.valid()) {
492 typedef cmd::GetBucketStart::Result Result;
493 Result* result = GetResultAs<Result*>();
498 helper_->GetBucketStart(
499 bucket_id, GetResultShmId(), GetResultShmOffset(),
500 buffer.size(), buffer.shm_id(), buffer.offset());
502 uint32 size = *result;
507 if (!buffer.valid()) {
509 if (!buffer.valid()) {
512 helper_->GetBucketData(
513 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
516 uint32 size_to_copy = std::min(size, buffer.size());
517 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
518 offset += size_to_copy;
519 size -= size_to_copy;
522 // Free the bucket. This is not required but it does free up the memory.
523 // and we don't have to wait for the result so from the client's perspective
525 helper_->SetBucketSize(bucket_id, 0);
530 void GLES2Implementation::SetBucketContents(
531 uint32 bucket_id, const void* data, size_t size) {
533 helper_->SetBucketSize(bucket_id, size);
537 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
538 if (!buffer.valid()) {
541 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
543 helper_->SetBucketData(
544 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
545 offset += buffer.size();
546 size -= buffer.size();
551 void GLES2Implementation::SetBucketAsCString(
552 uint32 bucket_id, const char* str) {
553 // NOTE: strings are passed NULL terminated. That means the empty
554 // string will have a size of 1 and no-string will have a size of 0
556 SetBucketContents(bucket_id, str, strlen(str) + 1);
558 helper_->SetBucketSize(bucket_id, 0);
562 bool GLES2Implementation::GetBucketAsString(
563 uint32 bucket_id, std::string* str) {
565 std::vector<int8> data;
566 // NOTE: strings are passed NULL terminated. That means the empty
567 // string will have a size of 1 and no-string will have a size of 0
568 if (!GetBucketContents(bucket_id, &data)) {
574 str->assign(&data[0], &data[0] + data.size() - 1);
578 void GLES2Implementation::SetBucketAsString(
579 uint32 bucket_id, const std::string& str) {
580 // NOTE: strings are passed NULL terminated. That means the empty
581 // string will have a size of 1 and no-string will have a size of 0
582 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
585 void GLES2Implementation::Disable(GLenum cap) {
586 GPU_CLIENT_SINGLE_THREAD_CHECK();
587 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
588 << GLES2Util::GetStringCapability(cap) << ")");
589 bool changed = false;
590 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
591 helper_->Disable(cap);
596 void GLES2Implementation::Enable(GLenum cap) {
597 GPU_CLIENT_SINGLE_THREAD_CHECK();
598 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
599 << GLES2Util::GetStringCapability(cap) << ")");
600 bool changed = false;
601 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
602 helper_->Enable(cap);
607 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
608 GPU_CLIENT_SINGLE_THREAD_CHECK();
609 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
610 << GLES2Util::GetStringCapability(cap) << ")");
612 if (!state_.GetEnabled(cap, &state)) {
613 typedef cmds::IsEnabled::Result Result;
614 Result* result = GetResultAs<Result*>();
619 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
621 state = (*result) != 0;
624 GPU_CLIENT_LOG("returned " << state);
629 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
631 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
632 *params = static_state_.int_state.max_combined_texture_image_units;
634 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
635 *params = static_state_.int_state.max_cube_map_texture_size;
637 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
638 *params = static_state_.int_state.max_fragment_uniform_vectors;
640 case GL_MAX_RENDERBUFFER_SIZE:
641 *params = static_state_.int_state.max_renderbuffer_size;
643 case GL_MAX_TEXTURE_IMAGE_UNITS:
644 *params = static_state_.int_state.max_texture_image_units;
646 case GL_MAX_TEXTURE_SIZE:
647 *params = static_state_.int_state.max_texture_size;
649 case GL_MAX_VARYING_VECTORS:
650 *params = static_state_.int_state.max_varying_vectors;
652 case GL_MAX_VERTEX_ATTRIBS:
653 *params = static_state_.int_state.max_vertex_attribs;
655 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
656 *params = static_state_.int_state.max_vertex_texture_image_units;
658 case GL_MAX_VERTEX_UNIFORM_VECTORS:
659 *params = static_state_.int_state.max_vertex_uniform_vectors;
661 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
662 *params = static_state_.int_state.num_compressed_texture_formats;
664 case GL_NUM_SHADER_BINARY_FORMATS:
665 *params = static_state_.int_state.num_shader_binary_formats;
667 case GL_ARRAY_BUFFER_BINDING:
668 if (share_group_->bind_generates_resource()) {
669 *params = bound_array_buffer_id_;
673 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
674 if (share_group_->bind_generates_resource()) {
676 vertex_array_object_manager_->bound_element_array_buffer();
680 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
681 *params = bound_pixel_pack_transfer_buffer_id_;
683 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
684 *params = bound_pixel_unpack_transfer_buffer_id_;
686 case GL_ACTIVE_TEXTURE:
687 *params = active_texture_unit_ + GL_TEXTURE0;
689 case GL_TEXTURE_BINDING_2D:
690 if (share_group_->bind_generates_resource()) {
691 *params = texture_units_[active_texture_unit_].bound_texture_2d;
695 case GL_TEXTURE_BINDING_CUBE_MAP:
696 if (share_group_->bind_generates_resource()) {
697 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
701 case GL_TEXTURE_BINDING_EXTERNAL_OES:
702 if (share_group_->bind_generates_resource()) {
704 texture_units_[active_texture_unit_].bound_texture_external_oes;
708 case GL_FRAMEBUFFER_BINDING:
709 if (share_group_->bind_generates_resource()) {
710 *params = bound_framebuffer_;
714 case GL_READ_FRAMEBUFFER_BINDING:
715 if (IsChromiumFramebufferMultisampleAvailable() &&
716 share_group_->bind_generates_resource()) {
717 *params = bound_read_framebuffer_;
721 case GL_RENDERBUFFER_BINDING:
722 if (share_group_->bind_generates_resource()) {
723 *params = bound_renderbuffer_;
732 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
733 // TODO(gman): Make this handle pnames that return more than 1 value.
735 if (!GetHelper(pname, &value)) {
738 *params = static_cast<GLboolean>(value);
742 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
743 // TODO(gman): Make this handle pnames that return more than 1 value.
745 if (!GetHelper(pname, &value)) {
748 *params = static_cast<GLfloat>(value);
752 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
753 return GetHelper(pname, params);
756 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
757 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
758 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
759 Result* result = GetResultAs<Result*>();
764 helper_->GetMaxValueInBufferCHROMIUM(
765 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
770 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
771 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
772 GPU_CLIENT_SINGLE_THREAD_CHECK();
773 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
774 << buffer_id << ", " << count << ", "
775 << GLES2Util::GetStringGetMaxIndexType(type)
776 << ", " << offset << ")");
777 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
778 buffer_id, count, type, offset);
779 GPU_CLIENT_LOG("returned " << result);
784 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
786 RestoreArrayBuffer(restore);
787 // Restore the element array binding.
788 // We only need to restore it if it wasn't a client side array.
789 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
790 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
795 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
797 // Restore the user's current binding.
798 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_);
802 void GLES2Implementation::DrawElements(
803 GLenum mode, GLsizei count, GLenum type, const void* indices) {
804 GPU_CLIENT_SINGLE_THREAD_CHECK();
805 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
806 << GLES2Util::GetStringDrawMode(mode) << ", "
808 << GLES2Util::GetStringIndexType(type) << ", "
809 << static_cast<const void*>(indices) << ")");
811 SetGLError(GL_INVALID_VALUE, "glDrawElements", "count less than 0.");
818 bool simulated = false;
819 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
820 "glDrawElements", this, helper_, count, type, 0, indices,
821 &offset, &simulated)) {
824 helper_->DrawElements(mode, count, type, offset);
825 RestoreElementAndArrayBuffers(simulated);
829 void GLES2Implementation::Flush() {
830 GPU_CLIENT_SINGLE_THREAD_CHECK();
831 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
832 // Insert the cmd to call glFlush
834 // Flush our command buffer
835 // (tell the service to execute up to the flush cmd.)
836 helper_->CommandBufferHelper::Flush();
839 void GLES2Implementation::ShallowFlushCHROMIUM() {
840 GPU_CLIENT_SINGLE_THREAD_CHECK();
841 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
842 // Flush our command buffer
843 // (tell the service to execute up to the flush cmd.)
844 helper_->CommandBufferHelper::Flush();
847 void GLES2Implementation::Finish() {
848 GPU_CLIENT_SINGLE_THREAD_CHECK();
852 void GLES2Implementation::ShallowFinishCHROMIUM() {
853 GPU_CLIENT_SINGLE_THREAD_CHECK();
854 // Flush our command buffer (tell the service to execute up to the flush cmd
855 // and don't return until it completes).
856 helper_->CommandBufferHelper::Finish();
859 bool GLES2Implementation::MustBeContextLost() {
860 bool context_lost = helper_->IsContextLost();
863 context_lost = helper_->IsContextLost();
865 GPU_CHECK(context_lost);
869 void GLES2Implementation::FinishHelper() {
870 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
871 TRACE_EVENT0("gpu", "GLES2::Finish");
872 // Insert the cmd to call glFinish
874 // Finish our command buffer
875 // (tell the service to execute up to the Finish cmd and wait for it to
877 helper_->CommandBufferHelper::Finish();
880 void GLES2Implementation::SwapBuffers() {
881 GPU_CLIENT_SINGLE_THREAD_CHECK();
882 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
883 // TODO(piman): Strictly speaking we'd want to insert the token after the
884 // swap, but the state update with the updated token might not have happened
885 // by the time the SwapBuffer callback gets called, forcing us to synchronize
886 // with the GPU process more than needed. So instead, make it happen before.
887 // All it means is that we could be slightly looser on the kMaxSwapBuffers
888 // semantics if the client doesn't use the callback mechanism, and by chance
889 // the scheduler yields between the InsertToken and the SwapBuffers.
890 swap_buffers_tokens_.push(helper_->InsertToken());
891 helper_->SwapBuffers();
892 helper_->CommandBufferHelper::Flush();
893 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
894 // compensate for TODO above.
895 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
896 helper_->WaitForToken(swap_buffers_tokens_.front());
897 swap_buffers_tokens_.pop();
901 void GLES2Implementation::GenSharedIdsCHROMIUM(
902 GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) {
903 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenSharedIdsCHROMIUM("
904 << namespace_id << ", " << id_offset << ", " << n << ", " <<
905 static_cast<void*>(ids) << ")");
906 TRACE_EVENT0("gpu", "GLES2::GenSharedIdsCHROMIUM");
910 ScopedTransferBufferArray<GLint> id_buffer(num, helper_, transfer_buffer_);
911 if (!id_buffer.valid()) {
914 helper_->GenSharedIdsCHROMIUM(
915 namespace_id, id_offset, id_buffer.num_elements(),
916 id_buffer.shm_id(), id_buffer.offset());
918 memcpy(dst, id_buffer.address(), sizeof(*dst) * id_buffer.num_elements());
919 num -= id_buffer.num_elements();
920 dst += id_buffer.num_elements();
922 GPU_CLIENT_LOG_CODE_BLOCK({
923 for (GLsizei i = 0; i < n; ++i) {
924 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
929 void GLES2Implementation::DeleteSharedIdsCHROMIUM(
930 GLuint namespace_id, GLsizei n, const GLuint* ids) {
931 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteSharedIdsCHROMIUM("
932 << namespace_id << ", " << n << ", "
933 << static_cast<const void*>(ids) << ")");
934 GPU_CLIENT_LOG_CODE_BLOCK({
935 for (GLsizei i = 0; i < n; ++i) {
936 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
939 TRACE_EVENT0("gpu", "GLES2::DeleteSharedIdsCHROMIUM");
941 ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
942 if (!id_buffer.valid()) {
945 memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
946 helper_->DeleteSharedIdsCHROMIUM(
947 namespace_id, id_buffer.num_elements(),
948 id_buffer.shm_id(), id_buffer.offset());
950 n -= id_buffer.num_elements();
951 ids += id_buffer.num_elements();
955 void GLES2Implementation::RegisterSharedIdsCHROMIUM(
956 GLuint namespace_id, GLsizei n, const GLuint* ids) {
957 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRegisterSharedIdsCHROMIUM("
958 << namespace_id << ", " << n << ", "
959 << static_cast<const void*>(ids) << ")");
960 GPU_CLIENT_LOG_CODE_BLOCK({
961 for (GLsizei i = 0; i < n; ++i) {
962 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
965 TRACE_EVENT0("gpu", "GLES2::RegisterSharedIdsCHROMIUM");
967 ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
968 if (!id_buffer.valid()) {
971 memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
972 helper_->RegisterSharedIdsCHROMIUM(
973 namespace_id, id_buffer.num_elements(),
974 id_buffer.shm_id(), id_buffer.offset());
976 n -= id_buffer.num_elements();
977 ids += id_buffer.num_elements();
981 void GLES2Implementation::BindAttribLocation(
982 GLuint program, GLuint index, const char* name) {
983 GPU_CLIENT_SINGLE_THREAD_CHECK();
984 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
985 << program << ", " << index << ", " << name << ")");
986 SetBucketAsString(kResultBucketId, name);
987 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
988 helper_->SetBucketSize(kResultBucketId, 0);
992 void GLES2Implementation::BindUniformLocationCHROMIUM(
993 GLuint program, GLint location, const char* name) {
994 GPU_CLIENT_SINGLE_THREAD_CHECK();
995 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
996 << program << ", " << location << ", " << name << ")");
997 SetBucketAsString(kResultBucketId, name);
998 helper_->BindUniformLocationCHROMIUMBucket(
999 program, location, kResultBucketId);
1000 helper_->SetBucketSize(kResultBucketId, 0);
1004 void GLES2Implementation::GetVertexAttribPointerv(
1005 GLuint index, GLenum pname, void** ptr) {
1006 GPU_CLIENT_SINGLE_THREAD_CHECK();
1007 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1008 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1009 << static_cast<void*>(ptr) << ")");
1010 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
1011 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1012 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1013 typedef cmds::GetVertexAttribPointerv::Result Result;
1014 Result* result = GetResultAs<Result*>();
1018 result->SetNumResults(0);
1019 helper_->GetVertexAttribPointerv(
1020 index, pname, GetResultShmId(), GetResultShmOffset());
1022 result->CopyResult(ptr);
1023 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1025 GPU_CLIENT_LOG_CODE_BLOCK({
1026 for (int32 i = 0; i < num_results; ++i) {
1027 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
1033 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1034 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1035 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
1038 "glDeleteProgram", "id not created by this context.");
1041 if (program == current_program_) {
1042 current_program_ = 0;
1047 void GLES2Implementation::DeleteProgramStub(
1048 GLsizei n, const GLuint* programs) {
1049 GPU_DCHECK_EQ(1, n);
1050 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1051 helper_->DeleteProgram(programs[0]);
1054 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1055 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1056 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1059 "glDeleteShader", "id not created by this context.");
1065 void GLES2Implementation::DeleteShaderStub(
1066 GLsizei n, const GLuint* shaders) {
1067 GPU_DCHECK_EQ(1, n);
1068 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1069 helper_->DeleteShader(shaders[0]);
1073 GLint GLES2Implementation::GetAttribLocationHelper(
1074 GLuint program, const char* name) {
1075 typedef cmds::GetAttribLocationBucket::Result Result;
1076 Result* result = GetResultAs<Result*>();
1081 SetBucketAsCString(kResultBucketId, name);
1082 helper_->GetAttribLocationBucket(
1083 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1085 helper_->SetBucketSize(kResultBucketId, 0);
1089 GLint GLES2Implementation::GetAttribLocation(
1090 GLuint program, const char* name) {
1091 GPU_CLIENT_SINGLE_THREAD_CHECK();
1092 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1093 << ", " << name << ")");
1094 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1095 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1096 this, program, name);
1097 GPU_CLIENT_LOG("returned " << loc);
1102 GLint GLES2Implementation::GetUniformLocationHelper(
1103 GLuint program, const char* name) {
1104 typedef cmds::GetUniformLocationBucket::Result Result;
1105 Result* result = GetResultAs<Result*>();
1110 SetBucketAsCString(kResultBucketId, name);
1111 helper_->GetUniformLocationBucket(program, kResultBucketId,
1112 GetResultShmId(), GetResultShmOffset());
1114 helper_->SetBucketSize(kResultBucketId, 0);
1118 GLint GLES2Implementation::GetUniformLocation(
1119 GLuint program, const char* name) {
1120 GPU_CLIENT_SINGLE_THREAD_CHECK();
1121 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1122 << ", " << name << ")");
1123 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1124 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1125 this, program, name);
1126 GPU_CLIENT_LOG("returned " << loc);
1131 void GLES2Implementation::UseProgram(GLuint program) {
1132 GPU_CLIENT_SINGLE_THREAD_CHECK();
1133 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUseProgram(" << program << ")");
1134 if (current_program_ != program) {
1135 current_program_ = program;
1136 helper_->UseProgram(program);
1141 bool GLES2Implementation::GetProgramivHelper(
1142 GLuint program, GLenum pname, GLint* params) {
1143 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1144 this, program, pname, params);
1145 GPU_CLIENT_LOG_CODE_BLOCK({
1147 GPU_CLIENT_LOG(" 0: " << *params);
1153 void GLES2Implementation::LinkProgram(GLuint program) {
1154 GPU_CLIENT_SINGLE_THREAD_CHECK();
1155 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1156 helper_->LinkProgram(program);
1157 share_group_->program_info_manager()->CreateInfo(program);
1161 void GLES2Implementation::ShaderBinary(
1162 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1164 GPU_CLIENT_SINGLE_THREAD_CHECK();
1165 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1166 << static_cast<const void*>(shaders) << ", "
1167 << GLES2Util::GetStringEnum(binaryformat) << ", "
1168 << static_cast<const void*>(binary) << ", "
1171 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1175 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1178 // TODO(gman): ShaderBinary should use buckets.
1179 unsigned int shader_id_size = n * sizeof(*shaders);
1180 ScopedTransferBufferArray<GLint> buffer(
1181 shader_id_size + length, helper_, transfer_buffer_);
1182 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1183 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1186 void* shader_ids = buffer.elements();
1187 void* shader_data = buffer.elements() + shader_id_size;
1188 memcpy(shader_ids, shaders, shader_id_size);
1189 memcpy(shader_data, binary, length);
1190 helper_->ShaderBinary(
1196 buffer.offset() + shader_id_size,
1201 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1202 GPU_CLIENT_SINGLE_THREAD_CHECK();
1203 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1204 << GLES2Util::GetStringPixelStore(pname) << ", "
1207 case GL_PACK_ALIGNMENT:
1208 pack_alignment_ = param;
1210 case GL_UNPACK_ALIGNMENT:
1211 unpack_alignment_ = param;
1213 case GL_UNPACK_ROW_LENGTH:
1214 unpack_row_length_ = param;
1216 case GL_UNPACK_SKIP_ROWS:
1217 unpack_skip_rows_ = param;
1219 case GL_UNPACK_SKIP_PIXELS:
1220 unpack_skip_pixels_ = param;
1222 case GL_UNPACK_FLIP_Y_CHROMIUM:
1223 unpack_flip_y_ = (param != 0);
1225 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1226 pack_reverse_row_order_ =
1227 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1232 helper_->PixelStorei(pname, param);
1237 void GLES2Implementation::VertexAttribPointer(
1238 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1240 GPU_CLIENT_SINGLE_THREAD_CHECK();
1241 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1244 << GLES2Util::GetStringVertexAttribType(type) << ", "
1245 << GLES2Util::GetStringBool(normalized) << ", "
1247 << static_cast<const void*>(ptr) << ")");
1248 // Record the info on the client side.
1249 if (!vertex_array_object_manager_->SetAttribPointer(
1250 bound_array_buffer_id_, index, size, type, normalized, stride, ptr)) {
1251 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1252 "client side arrays are not allowed in vertex array objects.");
1255 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1256 if (bound_array_buffer_id_ != 0) {
1257 // Only report NON client side buffers to the service.
1258 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1261 #else // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1262 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1264 #endif // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1268 void GLES2Implementation::VertexAttribDivisorANGLE(
1269 GLuint index, GLuint divisor) {
1270 GPU_CLIENT_SINGLE_THREAD_CHECK();
1271 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1273 << divisor << ") ");
1274 // Record the info on the client side.
1275 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1276 helper_->VertexAttribDivisorANGLE(index, divisor);
1280 void GLES2Implementation::ShaderSource(
1281 GLuint shader, GLsizei count, const GLchar* const* source, const GLint* length) {
1282 GPU_CLIENT_SINGLE_THREAD_CHECK();
1283 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderSource("
1284 << shader << ", " << count << ", "
1285 << static_cast<const void*>(source) << ", "
1286 << static_cast<const void*>(length) << ")");
1287 GPU_CLIENT_LOG_CODE_BLOCK({
1288 for (GLsizei ii = 0; ii < count; ++ii) {
1290 if (length && length[ii] >= 0) {
1291 std::string str(source[ii], length[ii]);
1292 GPU_CLIENT_LOG(" " << ii << ": ---\n" << str << "\n---");
1294 GPU_CLIENT_LOG(" " << ii << ": ---\n" << source[ii] << "\n---");
1297 GPU_CLIENT_LOG(" " << ii << ": NULL");
1302 SetGLError(GL_INVALID_VALUE, "glShaderSource", "count < 0");
1306 SetGLError(GL_INVALID_VALUE, "glShaderSource", "shader == 0");
1310 // Compute the total size.
1311 uint32 total_size = 1;
1312 for (GLsizei ii = 0; ii < count; ++ii) {
1314 total_size += (length && length[ii] >= 0) ?
1315 static_cast<size_t>(length[ii]) : strlen(source[ii]);
1319 // Concatenate all the strings in to a bucket on the service.
1320 helper_->SetBucketSize(kResultBucketId, total_size);
1322 for (GLsizei ii = 0; ii <= count; ++ii) {
1323 const char* src = ii < count ? source[ii] : "";
1325 uint32 size = ii < count ?
1326 (length ? static_cast<size_t>(length[ii]) : strlen(src)) : 1;
1328 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1329 if (!buffer.valid()) {
1332 memcpy(buffer.address(), src, buffer.size());
1333 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
1334 buffer.shm_id(), buffer.offset());
1335 offset += buffer.size();
1336 src += buffer.size();
1337 size -= buffer.size();
1342 GPU_DCHECK_EQ(total_size, offset);
1344 helper_->ShaderSourceBucket(shader, kResultBucketId);
1345 helper_->SetBucketSize(kResultBucketId, 0);
1349 void GLES2Implementation::BufferDataHelper(
1350 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1352 SetGLError(GL_INVALID_VALUE, "glBufferData", "size < 0");
1357 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1362 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1364 // Free buffer memory, pending the passage of a token.
1365 buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
1367 // Remove old buffer.
1368 buffer_tracker_->RemoveBuffer(buffer_id);
1371 // Create new buffer.
1372 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1374 if (buffer->address() && data)
1375 memcpy(buffer->address(), data, size);
1383 // If there is no data just send BufferData
1385 helper_->BufferData(target, size, 0, 0, usage);
1389 // See if we can send all at once.
1390 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1391 if (!buffer.valid()) {
1395 if (buffer.size() >= static_cast<unsigned int>(size)) {
1396 memcpy(buffer.address(), data, size);
1397 helper_->BufferData(
1406 // Make the buffer with BufferData then send via BufferSubData
1407 helper_->BufferData(target, size, 0, 0, usage);
1408 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1412 void GLES2Implementation::BufferData(
1413 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1414 GPU_CLIENT_SINGLE_THREAD_CHECK();
1415 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1416 << GLES2Util::GetStringBufferTarget(target) << ", "
1418 << static_cast<const void*>(data) << ", "
1419 << GLES2Util::GetStringBufferUsage(usage) << ")");
1420 BufferDataHelper(target, size, data, usage);
1424 void GLES2Implementation::BufferSubDataHelper(
1425 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1431 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "size < 0");
1436 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1440 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1442 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1447 int32 buffer_size = buffer->size();
1448 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1449 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1453 if (buffer->address() && data)
1454 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1458 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1459 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1462 void GLES2Implementation::BufferSubDataHelperImpl(
1463 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1464 ScopedTransferBufferPtr* buffer) {
1466 GPU_DCHECK_GT(size, 0);
1468 const int8* source = static_cast<const int8*>(data);
1470 if (!buffer->valid() || buffer->size() == 0) {
1471 buffer->Reset(size);
1472 if (!buffer->valid()) {
1476 memcpy(buffer->address(), source, buffer->size());
1477 helper_->BufferSubData(
1478 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1479 offset += buffer->size();
1480 source += buffer->size();
1481 size -= buffer->size();
1486 void GLES2Implementation::BufferSubData(
1487 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1488 GPU_CLIENT_SINGLE_THREAD_CHECK();
1489 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1490 << GLES2Util::GetStringBufferTarget(target) << ", "
1491 << offset << ", " << size << ", "
1492 << static_cast<const void*>(data) << ")");
1493 BufferSubDataHelper(target, offset, size, data);
1497 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1499 const char* function_name,
1500 GLuint* buffer_id) {
1504 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1505 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1507 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1508 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1515 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1520 BufferTracker::Buffer*
1521 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1523 const char* function_name,
1524 GLuint offset, GLsizei size)
1527 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1529 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1532 if (buffer->mapped()) {
1533 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1536 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1537 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1543 void GLES2Implementation::CompressedTexImage2D(
1544 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1545 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1546 GPU_CLIENT_SINGLE_THREAD_CHECK();
1547 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1548 << GLES2Util::GetStringTextureTarget(target) << ", "
1550 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1551 << width << ", " << height << ", " << border << ", "
1552 << image_size << ", "
1553 << static_cast<const void*>(data) << ")");
1554 if (width < 0 || height < 0 || level < 0) {
1555 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1558 if (height == 0 || width == 0) {
1561 // If there's a pixel unpack buffer bound use it when issuing
1562 // CompressedTexImage2D.
1563 if (bound_pixel_unpack_transfer_buffer_id_) {
1564 GLuint offset = ToGLuint(data);
1565 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1566 bound_pixel_unpack_transfer_buffer_id_,
1567 "glCompressedTexImage2D", offset, image_size);
1568 if (buffer && buffer->shm_id() != -1) {
1569 helper_->CompressedTexImage2D(
1570 target, level, internalformat, width, height, border, image_size,
1571 buffer->shm_id(), buffer->shm_offset() + offset);
1572 buffer->set_transfer_ready_token(helper_->InsertToken());
1576 SetBucketContents(kResultBucketId, data, image_size);
1577 helper_->CompressedTexImage2DBucket(
1578 target, level, internalformat, width, height, border, kResultBucketId);
1579 // Free the bucket. This is not required but it does free up the memory.
1580 // and we don't have to wait for the result so from the client's perspective
1582 helper_->SetBucketSize(kResultBucketId, 0);
1586 void GLES2Implementation::CompressedTexSubImage2D(
1587 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1588 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1589 GPU_CLIENT_SINGLE_THREAD_CHECK();
1590 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1591 << GLES2Util::GetStringTextureTarget(target) << ", "
1593 << xoffset << ", " << yoffset << ", "
1594 << width << ", " << height << ", "
1595 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1596 << image_size << ", "
1597 << static_cast<const void*>(data) << ")");
1598 if (width < 0 || height < 0 || level < 0) {
1599 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1602 // If there's a pixel unpack buffer bound use it when issuing
1603 // CompressedTexSubImage2D.
1604 if (bound_pixel_unpack_transfer_buffer_id_) {
1605 GLuint offset = ToGLuint(data);
1606 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1607 bound_pixel_unpack_transfer_buffer_id_,
1608 "glCompressedTexSubImage2D", offset, image_size);
1609 if (buffer && buffer->shm_id() != -1) {
1610 helper_->CompressedTexSubImage2D(
1611 target, level, xoffset, yoffset, width, height, format, image_size,
1612 buffer->shm_id(), buffer->shm_offset() + offset);
1613 buffer->set_transfer_ready_token(helper_->InsertToken());
1618 SetBucketContents(kResultBucketId, data, image_size);
1619 helper_->CompressedTexSubImage2DBucket(
1620 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1621 // Free the bucket. This is not required but it does free up the memory.
1622 // and we don't have to wait for the result so from the client's perspective
1624 helper_->SetBucketSize(kResultBucketId, 0);
1630 void CopyRectToBuffer(
1633 uint32 unpadded_row_size,
1634 uint32 pixels_padded_row_size,
1637 uint32 buffer_padded_row_size) {
1638 const int8* source = static_cast<const int8*>(pixels);
1639 int8* dest = static_cast<int8*>(buffer);
1640 if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
1642 dest += buffer_padded_row_size * (height - 1);
1644 // the last row is copied unpadded at the end
1645 for (; height > 1; --height) {
1646 memcpy(dest, source, buffer_padded_row_size);
1648 dest -= buffer_padded_row_size;
1650 dest += buffer_padded_row_size;
1652 source += pixels_padded_row_size;
1654 memcpy(dest, source, unpadded_row_size);
1656 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
1657 memcpy(dest, source, size);
1661 } // anonymous namespace
1663 void GLES2Implementation::TexImage2D(
1664 GLenum target, GLint level, GLint internalformat, GLsizei width,
1665 GLsizei height, GLint border, GLenum format, GLenum type,
1666 const void* pixels) {
1667 GPU_CLIENT_SINGLE_THREAD_CHECK();
1668 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1669 << GLES2Util::GetStringTextureTarget(target) << ", "
1671 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1672 << width << ", " << height << ", " << border << ", "
1673 << GLES2Util::GetStringTextureFormat(format) << ", "
1674 << GLES2Util::GetStringPixelType(type) << ", "
1675 << static_cast<const void*>(pixels) << ")");
1676 if (level < 0 || height < 0 || width < 0) {
1677 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
1681 uint32 unpadded_row_size;
1682 uint32 padded_row_size;
1683 if (!GLES2Util::ComputeImageDataSizes(
1684 width, height, format, type, unpack_alignment_, &size,
1685 &unpadded_row_size, &padded_row_size)) {
1686 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
1690 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1691 if (bound_pixel_unpack_transfer_buffer_id_) {
1692 GLuint offset = ToGLuint(pixels);
1693 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1694 bound_pixel_unpack_transfer_buffer_id_,
1695 "glTexImage2D", offset, size);
1696 if (buffer && buffer->shm_id() != -1) {
1697 helper_->TexImage2D(
1698 target, level, internalformat, width, height, border, format, type,
1699 buffer->shm_id(), buffer->shm_offset() + offset);
1700 buffer->set_transfer_ready_token(helper_->InsertToken());
1706 // If there's no data just issue TexImage2D
1708 helper_->TexImage2D(
1709 target, level, internalformat, width, height, border, format, type,
1715 // compute the advance bytes per row for the src pixels
1716 uint32 src_padded_row_size;
1717 if (unpack_row_length_ > 0) {
1718 if (!GLES2Util::ComputeImagePaddedRowSize(
1719 unpack_row_length_, format, type, unpack_alignment_,
1720 &src_padded_row_size)) {
1722 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1726 src_padded_row_size = padded_row_size;
1729 // advance pixels pointer past the skip rows and skip pixels
1730 pixels = reinterpret_cast<const int8*>(pixels) +
1731 unpack_skip_rows_ * src_padded_row_size;
1732 if (unpack_skip_pixels_) {
1733 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1734 pixels = reinterpret_cast<const int8*>(pixels) +
1735 unpack_skip_pixels_ * group_size;
1738 // Check if we can send it all at once.
1739 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1740 if (!buffer.valid()) {
1744 if (buffer.size() >= size) {
1746 pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
1747 buffer.address(), padded_row_size);
1748 helper_->TexImage2D(
1749 target, level, internalformat, width, height, border, format, type,
1750 buffer.shm_id(), buffer.offset());
1755 // No, so send it using TexSubImage2D.
1756 helper_->TexImage2D(
1757 target, level, internalformat, width, height, border, format, type,
1760 target, level, 0, 0, width, height, format, type, unpadded_row_size,
1761 pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
1765 void GLES2Implementation::TexSubImage2D(
1766 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1767 GLsizei height, GLenum format, GLenum type, const void* pixels) {
1768 GPU_CLIENT_SINGLE_THREAD_CHECK();
1769 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1770 << GLES2Util::GetStringTextureTarget(target) << ", "
1772 << xoffset << ", " << yoffset << ", "
1773 << width << ", " << height << ", "
1774 << GLES2Util::GetStringTextureFormat(format) << ", "
1775 << GLES2Util::GetStringPixelType(type) << ", "
1776 << static_cast<const void*>(pixels) << ")");
1778 if (level < 0 || height < 0 || width < 0) {
1779 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
1782 if (height == 0 || width == 0) {
1787 uint32 unpadded_row_size;
1788 uint32 padded_row_size;
1789 if (!GLES2Util::ComputeImageDataSizes(
1790 width, height, format, type, unpack_alignment_, &temp_size,
1791 &unpadded_row_size, &padded_row_size)) {
1792 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
1796 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1797 if (bound_pixel_unpack_transfer_buffer_id_) {
1798 GLuint offset = ToGLuint(pixels);
1799 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1800 bound_pixel_unpack_transfer_buffer_id_,
1801 "glTexSubImage2D", offset, temp_size);
1802 if (buffer && buffer->shm_id() != -1) {
1803 helper_->TexSubImage2D(
1804 target, level, xoffset, yoffset, width, height, format, type,
1805 buffer->shm_id(), buffer->shm_offset() + offset, false);
1806 buffer->set_transfer_ready_token(helper_->InsertToken());
1812 // compute the advance bytes per row for the src pixels
1813 uint32 src_padded_row_size;
1814 if (unpack_row_length_ > 0) {
1815 if (!GLES2Util::ComputeImagePaddedRowSize(
1816 unpack_row_length_, format, type, unpack_alignment_,
1817 &src_padded_row_size)) {
1819 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1823 src_padded_row_size = padded_row_size;
1826 // advance pixels pointer past the skip rows and skip pixels
1827 pixels = reinterpret_cast<const int8*>(pixels) +
1828 unpack_skip_rows_ * src_padded_row_size;
1829 if (unpack_skip_pixels_) {
1830 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1831 pixels = reinterpret_cast<const int8*>(pixels) +
1832 unpack_skip_pixels_ * group_size;
1835 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
1837 target, level, xoffset, yoffset, width, height, format, type,
1838 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
1843 static GLint ComputeNumRowsThatFitInBuffer(
1844 GLsizeiptr padded_row_size, GLsizeiptr unpadded_row_size,
1845 unsigned int size) {
1846 GPU_DCHECK_GE(unpadded_row_size, 0);
1847 if (padded_row_size == 0) {
1850 GLint num_rows = size / padded_row_size;
1851 return num_rows + (size - num_rows * padded_row_size) / unpadded_row_size;
1854 void GLES2Implementation::TexSubImage2DImpl(
1855 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1856 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
1857 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
1858 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
1860 GPU_DCHECK_GE(level, 0);
1861 GPU_DCHECK_GT(height, 0);
1862 GPU_DCHECK_GT(width, 0);
1864 const int8* source = reinterpret_cast<const int8*>(pixels);
1865 GLint original_yoffset = yoffset;
1866 // Transfer by rows.
1868 unsigned int desired_size =
1869 buffer_padded_row_size * (height - 1) + unpadded_row_size;
1870 if (!buffer->valid() || buffer->size() == 0) {
1871 buffer->Reset(desired_size);
1872 if (!buffer->valid()) {
1877 GLint num_rows = ComputeNumRowsThatFitInBuffer(
1878 buffer_padded_row_size, unpadded_row_size, buffer->size());
1879 num_rows = std::min(num_rows, height);
1881 source, num_rows, unpadded_row_size, pixels_padded_row_size,
1882 unpack_flip_y_, buffer->address(), buffer_padded_row_size);
1883 GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
1884 helper_->TexSubImage2D(
1885 target, level, xoffset, y, width, num_rows, format, type,
1886 buffer->shm_id(), buffer->offset(), internal);
1888 yoffset += num_rows;
1889 source += num_rows * pixels_padded_row_size;
1894 bool GLES2Implementation::GetActiveAttribHelper(
1895 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1896 GLenum* type, char* name) {
1897 // Clear the bucket so if the command fails nothing will be in it.
1898 helper_->SetBucketSize(kResultBucketId, 0);
1899 typedef cmds::GetActiveAttrib::Result Result;
1900 Result* result = GetResultAs<Result*>();
1904 // Set as failed so if the command fails we'll recover.
1905 result->success = false;
1906 helper_->GetActiveAttrib(program, index, kResultBucketId,
1907 GetResultShmId(), GetResultShmOffset());
1909 if (result->success) {
1911 *size = result->size;
1914 *type = result->type;
1916 if (length || name) {
1917 std::vector<int8> str;
1918 GetBucketContents(kResultBucketId, &str);
1919 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
1920 std::max(static_cast<size_t>(0),
1925 if (name && bufsize > 0) {
1926 memcpy(name, &str[0], max_size);
1927 name[max_size] = '\0';
1931 return result->success != 0;
1934 void GLES2Implementation::GetActiveAttrib(
1935 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1936 GLenum* type, char* name) {
1937 GPU_CLIENT_SINGLE_THREAD_CHECK();
1938 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
1939 << program << ", " << index << ", " << bufsize << ", "
1940 << static_cast<const void*>(length) << ", "
1941 << static_cast<const void*>(size) << ", "
1942 << static_cast<const void*>(type) << ", "
1943 << static_cast<const void*>(name) << ", ");
1945 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
1948 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
1949 bool success = share_group_->program_info_manager()->GetActiveAttrib(
1950 this, program, index, bufsize, length, size, type, name);
1953 GPU_CLIENT_LOG(" size: " << *size);
1956 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
1959 GPU_CLIENT_LOG(" name: " << name);
1965 bool GLES2Implementation::GetActiveUniformHelper(
1966 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1967 GLenum* type, char* name) {
1968 // Clear the bucket so if the command fails nothing will be in it.
1969 helper_->SetBucketSize(kResultBucketId, 0);
1970 typedef cmds::GetActiveUniform::Result Result;
1971 Result* result = GetResultAs<Result*>();
1975 // Set as failed so if the command fails we'll recover.
1976 result->success = false;
1977 helper_->GetActiveUniform(program, index, kResultBucketId,
1978 GetResultShmId(), GetResultShmOffset());
1980 if (result->success) {
1982 *size = result->size;
1985 *type = result->type;
1987 if (length || name) {
1988 std::vector<int8> str;
1989 GetBucketContents(kResultBucketId, &str);
1990 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
1991 std::max(static_cast<size_t>(0),
1996 if (name && bufsize > 0) {
1997 memcpy(name, &str[0], max_size);
1998 name[max_size] = '\0';
2002 return result->success != 0;
2005 void GLES2Implementation::GetActiveUniform(
2006 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2007 GLenum* type, char* name) {
2008 GPU_CLIENT_SINGLE_THREAD_CHECK();
2009 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2010 << program << ", " << index << ", " << bufsize << ", "
2011 << static_cast<const void*>(length) << ", "
2012 << static_cast<const void*>(size) << ", "
2013 << static_cast<const void*>(type) << ", "
2014 << static_cast<const void*>(name) << ", ");
2016 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2019 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2020 bool success = share_group_->program_info_manager()->GetActiveUniform(
2021 this, program, index, bufsize, length, size, type, name);
2024 GPU_CLIENT_LOG(" size: " << *size);
2027 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2030 GPU_CLIENT_LOG(" name: " << name);
2036 void GLES2Implementation::GetAttachedShaders(
2037 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
2038 GPU_CLIENT_SINGLE_THREAD_CHECK();
2039 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2040 << program << ", " << maxcount << ", "
2041 << static_cast<const void*>(count) << ", "
2042 << static_cast<const void*>(shaders) << ", ");
2044 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
2047 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2048 typedef cmds::GetAttachedShaders::Result Result;
2049 uint32 size = Result::ComputeSize(maxcount);
2050 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
2054 result->SetNumResults(0);
2055 helper_->GetAttachedShaders(
2057 transfer_buffer_->GetShmId(),
2058 transfer_buffer_->GetOffset(result),
2060 int32 token = helper_->InsertToken();
2063 *count = result->GetNumResults();
2065 result->CopyResult(shaders);
2066 GPU_CLIENT_LOG_CODE_BLOCK({
2067 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2068 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2071 transfer_buffer_->FreePendingToken(result, token);
2075 void GLES2Implementation::GetShaderPrecisionFormat(
2076 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
2077 GPU_CLIENT_SINGLE_THREAD_CHECK();
2078 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2079 << GLES2Util::GetStringShaderType(shadertype) << ", "
2080 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
2081 << static_cast<const void*>(range) << ", "
2082 << static_cast<const void*>(precision) << ", ");
2083 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2084 typedef cmds::GetShaderPrecisionFormat::Result Result;
2085 Result* result = GetResultAs<Result*>();
2090 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
2091 GLStaticState::ShaderPrecisionMap::iterator i =
2092 static_state_.shader_precisions.find(key);
2093 if (i != static_state_.shader_precisions.end()) {
2094 *result = i->second;
2096 result->success = false;
2097 helper_->GetShaderPrecisionFormat(
2098 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
2100 if (result->success)
2101 static_state_.shader_precisions[key] = *result;
2104 if (result->success) {
2106 range[0] = result->min_range;
2107 range[1] = result->max_range;
2108 GPU_CLIENT_LOG(" min_range: " << range[0]);
2109 GPU_CLIENT_LOG(" min_range: " << range[1]);
2112 precision[0] = result->precision;
2113 GPU_CLIENT_LOG(" min_range: " << precision[0]);
2119 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
2120 const char* result = NULL;
2121 // Clears the bucket so if the command fails nothing will be in it.
2122 helper_->SetBucketSize(kResultBucketId, 0);
2123 helper_->GetString(name, kResultBucketId);
2125 if (GetBucketAsString(kResultBucketId, &str)) {
2126 // Adds extensions implemented on client side only.
2129 str += std::string(str.empty() ? "" : " ") +
2130 "GL_CHROMIUM_flipy "
2131 "GL_CHROMIUM_map_sub "
2132 "GL_CHROMIUM_shallow_flush "
2133 "GL_EXT_unpack_subimage";
2134 if (gpu_control_->SupportsGpuMemoryBuffer()) {
2135 // The first space character is intentional.
2136 str += " GL_CHROMIUM_map_image";
2143 // Because of WebGL the extensions can change. We have to cache each unique
2144 // result since we don't know when the client will stop referring to a
2145 // previous one it queries.
2146 GLStringMap::iterator it = gl_strings_.find(name);
2147 if (it == gl_strings_.end()) {
2148 std::set<std::string> strings;
2149 std::pair<GLStringMap::iterator, bool> insert_result =
2150 gl_strings_.insert(std::make_pair(name, strings));
2151 GPU_DCHECK(insert_result.second);
2152 it = insert_result.first;
2154 std::set<std::string>& string_set = it->second;
2155 std::set<std::string>::const_iterator sit = string_set.find(str);
2156 if (sit != string_set.end()) {
2157 result = sit->c_str();
2159 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2160 string_set.insert(str);
2161 GPU_DCHECK(insert_result.second);
2162 result = insert_result.first->c_str();
2165 return reinterpret_cast<const GLubyte*>(result);
2168 const GLubyte* GLES2Implementation::GetString(GLenum name) {
2169 GPU_CLIENT_SINGLE_THREAD_CHECK();
2170 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2171 << GLES2Util::GetStringStringType(name) << ")");
2172 TRACE_EVENT0("gpu", "GLES2::GetString");
2173 const GLubyte* result = GetStringHelper(name);
2174 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
2179 void GLES2Implementation::GetUniformfv(
2180 GLuint program, GLint location, GLfloat* params) {
2181 GPU_CLIENT_SINGLE_THREAD_CHECK();
2182 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2183 << program << ", " << location << ", "
2184 << static_cast<const void*>(params) << ")");
2185 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2186 typedef cmds::GetUniformfv::Result Result;
2187 Result* result = GetResultAs<Result*>();
2191 result->SetNumResults(0);
2192 helper_->GetUniformfv(
2193 program, location, GetResultShmId(), GetResultShmOffset());
2195 result->CopyResult(params);
2196 GPU_CLIENT_LOG_CODE_BLOCK({
2197 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2198 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2204 void GLES2Implementation::GetUniformiv(
2205 GLuint program, GLint location, GLint* params) {
2206 GPU_CLIENT_SINGLE_THREAD_CHECK();
2207 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2208 << program << ", " << location << ", "
2209 << static_cast<const void*>(params) << ")");
2210 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2211 typedef cmds::GetUniformiv::Result Result;
2212 Result* result = GetResultAs<Result*>();
2216 result->SetNumResults(0);
2217 helper_->GetUniformiv(
2218 program, location, GetResultShmId(), GetResultShmOffset());
2220 GetResultAs<cmds::GetUniformfv::Result*>()->CopyResult(params);
2221 GPU_CLIENT_LOG_CODE_BLOCK({
2222 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2223 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2229 void GLES2Implementation::ReadPixels(
2230 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
2231 GLenum type, void* pixels) {
2232 GPU_CLIENT_SINGLE_THREAD_CHECK();
2233 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2234 << xoffset << ", " << yoffset << ", "
2235 << width << ", " << height << ", "
2236 << GLES2Util::GetStringReadPixelFormat(format) << ", "
2237 << GLES2Util::GetStringPixelType(type) << ", "
2238 << static_cast<const void*>(pixels) << ")");
2239 if (width < 0 || height < 0) {
2240 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
2243 if (width == 0 || height == 0) {
2247 // glReadPixel pads the size of each row of pixels by an amount specified by
2248 // glPixelStorei. So, we have to take that into account both in the fact that
2249 // the pixels returned from the ReadPixel command will include that padding
2250 // and that when we copy the results to the user's buffer we need to not
2251 // write those padding bytes but leave them as they are.
2253 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2254 typedef cmds::ReadPixels::Result Result;
2256 int8* dest = reinterpret_cast<int8*>(pixels);
2258 uint32 unpadded_row_size;
2259 uint32 padded_row_size;
2260 if (!GLES2Util::ComputeImageDataSizes(
2261 width, 2, format, type, pack_alignment_, &temp_size, &unpadded_row_size,
2262 &padded_row_size)) {
2263 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
2267 if (bound_pixel_pack_transfer_buffer_id_) {
2268 GLuint offset = ToGLuint(pixels);
2269 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2270 bound_pixel_pack_transfer_buffer_id_,
2271 "glReadPixels", offset, padded_row_size * height);
2272 if (buffer && buffer->shm_id() != -1) {
2273 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
2274 buffer->shm_id(), buffer->shm_offset(),
2282 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
2286 // Transfer by rows.
2287 // The max rows we can transfer.
2289 GLsizei desired_size = padded_row_size * height - 1 + unpadded_row_size;
2290 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
2291 if (!buffer.valid()) {
2294 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2295 padded_row_size, unpadded_row_size, buffer.size());
2296 num_rows = std::min(num_rows, height);
2297 // NOTE: We must look up the address of the result area AFTER allocation
2298 // of the transfer buffer since the transfer buffer may be reallocated.
2299 Result* result = GetResultAs<Result*>();
2303 *result = 0; // mark as failed.
2304 helper_->ReadPixels(
2305 xoffset, yoffset, width, num_rows, format, type,
2306 buffer.shm_id(), buffer.offset(),
2307 GetResultShmId(), GetResultShmOffset(),
2311 // when doing a y-flip we have to iterate through top-to-bottom chunks
2312 // of the dst. The service side handles reversing the rows within a
2315 if (pack_reverse_row_order_) {
2316 rows_dst = dest + (height - num_rows) * padded_row_size;
2320 // We have to copy 1 row at a time to avoid writing pad bytes.
2321 const int8* src = static_cast<const int8*>(buffer.address());
2322 for (GLint yy = 0; yy < num_rows; ++yy) {
2323 memcpy(rows_dst, src, unpadded_row_size);
2324 rows_dst += padded_row_size;
2325 src += padded_row_size;
2327 if (!pack_reverse_row_order_) {
2331 // If it was not marked as successful exit.
2335 yoffset += num_rows;
2341 void GLES2Implementation::ActiveTexture(GLenum texture) {
2342 GPU_CLIENT_SINGLE_THREAD_CHECK();
2343 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2344 << GLES2Util::GetStringEnum(texture) << ")");
2345 GLuint texture_index = texture - GL_TEXTURE0;
2346 if (texture_index >= static_cast<GLuint>(
2347 static_state_.int_state.max_combined_texture_image_units)) {
2348 SetGLErrorInvalidEnum(
2349 "glActiveTexture", texture, "texture");
2353 active_texture_unit_ = texture_index;
2354 helper_->ActiveTexture(texture);
2358 void GLES2Implementation::GenBuffersHelper(
2359 GLsizei /* n */, const GLuint* /* buffers */) {
2362 void GLES2Implementation::GenFramebuffersHelper(
2363 GLsizei /* n */, const GLuint* /* framebuffers */) {
2366 void GLES2Implementation::GenRenderbuffersHelper(
2367 GLsizei /* n */, const GLuint* /* renderbuffers */) {
2370 void GLES2Implementation::GenTexturesHelper(
2371 GLsizei /* n */, const GLuint* /* textures */) {
2374 void GLES2Implementation::GenVertexArraysOESHelper(
2375 GLsizei n, const GLuint* arrays) {
2376 vertex_array_object_manager_->GenVertexArrays(n, arrays);
2379 void GLES2Implementation::GenQueriesEXTHelper(
2380 GLsizei /* n */, const GLuint* /* queries */) {
2383 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
2384 // generates a new resource. On newer versions of OpenGL they don't. The code
2385 // related to binding below will need to change if we switch to the new OpenGL
2386 // model. Specifically it assumes a bind will succeed which is always true in
2387 // the old model but possibly not true in the new model if another context has
2388 // deleted the resource.
2390 bool GLES2Implementation::BindBufferHelper(
2391 GLenum target, GLuint buffer) {
2392 // TODO(gman): See note #1 above.
2393 bool changed = false;
2395 case GL_ARRAY_BUFFER:
2396 if (bound_array_buffer_id_ != buffer) {
2397 bound_array_buffer_id_ = buffer;
2401 case GL_ELEMENT_ARRAY_BUFFER:
2402 changed = vertex_array_object_manager_->BindElementArray(buffer);
2404 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
2405 bound_pixel_pack_transfer_buffer_id_ = buffer;
2407 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
2408 bound_pixel_unpack_transfer_buffer_id_ = buffer;
2414 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2415 // used even though it's marked it as used here.
2416 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(buffer);
2420 bool GLES2Implementation::BindFramebufferHelper(
2421 GLenum target, GLuint framebuffer) {
2422 // TODO(gman): See note #1 above.
2423 bool changed = false;
2425 case GL_FRAMEBUFFER:
2426 if (bound_framebuffer_ != framebuffer ||
2427 bound_read_framebuffer_ != framebuffer) {
2428 bound_framebuffer_ = framebuffer;
2429 bound_read_framebuffer_ = framebuffer;
2433 case GL_READ_FRAMEBUFFER:
2434 if (!IsChromiumFramebufferMultisampleAvailable()) {
2435 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2438 if (bound_read_framebuffer_ != framebuffer) {
2439 bound_read_framebuffer_ = framebuffer;
2443 case GL_DRAW_FRAMEBUFFER:
2444 if (!IsChromiumFramebufferMultisampleAvailable()) {
2445 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2448 if (bound_framebuffer_ != framebuffer) {
2449 bound_framebuffer_ = framebuffer;
2454 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2457 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(framebuffer);
2461 bool GLES2Implementation::BindRenderbufferHelper(
2462 GLenum target, GLuint renderbuffer) {
2463 // TODO(gman): See note #1 above.
2464 bool changed = false;
2466 case GL_RENDERBUFFER:
2467 if (bound_renderbuffer_ != renderbuffer) {
2468 bound_renderbuffer_ = renderbuffer;
2476 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2477 // used even though it's marked it as used here.
2478 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(renderbuffer);
2482 bool GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
2483 // TODO(gman): See note #1 above.
2484 // TODO(gman): Change this to false once we figure out why it's failing
2486 bool changed = true;
2487 TextureUnit& unit = texture_units_[active_texture_unit_];
2490 if (unit.bound_texture_2d != texture) {
2491 unit.bound_texture_2d = texture;
2495 case GL_TEXTURE_CUBE_MAP:
2496 if (unit.bound_texture_cube_map != texture) {
2497 unit.bound_texture_cube_map = texture;
2501 case GL_TEXTURE_EXTERNAL_OES:
2502 if (unit.bound_texture_external_oes != texture) {
2503 unit.bound_texture_external_oes = texture;
2511 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2512 // used. even though it's marked it as used here.
2513 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(texture);
2517 bool GLES2Implementation::BindVertexArrayHelper(GLuint array) {
2518 // TODO(gman): See note #1 above.
2519 bool changed = false;
2520 if (!vertex_array_object_manager_->BindVertexArray(array, &changed)) {
2522 GL_INVALID_OPERATION, "glBindVertexArrayOES",
2523 "id was not generated with glGenVertexArrayOES");
2525 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
2526 // because unlike other resources VertexArrayObject ids must
2527 // be generated by GenVertexArrays. A random id to Bind will not
2528 // generate a new object.
2532 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
2533 return vertex_array_object_manager_->IsReservedId(id);
2536 void GLES2Implementation::DeleteBuffersHelper(
2537 GLsizei n, const GLuint* buffers) {
2538 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
2539 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
2542 "glDeleteBuffers", "id not created by this context.");
2545 for (GLsizei ii = 0; ii < n; ++ii) {
2546 if (buffers[ii] == bound_array_buffer_id_) {
2547 bound_array_buffer_id_ = 0;
2549 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
2550 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
2552 // Free buffer memory, pending the passage of a token.
2553 buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
2555 buffer_tracker_->RemoveBuffer(buffers[ii]);
2557 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
2558 bound_pixel_unpack_transfer_buffer_id_ = 0;
2563 void GLES2Implementation::DeleteBuffersStub(
2564 GLsizei n, const GLuint* buffers) {
2565 helper_->DeleteBuffersImmediate(n, buffers);
2569 void GLES2Implementation::DeleteFramebuffersHelper(
2570 GLsizei n, const GLuint* framebuffers) {
2571 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
2572 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
2575 "glDeleteFramebuffers", "id not created by this context.");
2578 for (GLsizei ii = 0; ii < n; ++ii) {
2579 if (framebuffers[ii] == bound_framebuffer_) {
2580 bound_framebuffer_ = 0;
2582 if (framebuffers[ii] == bound_read_framebuffer_) {
2583 bound_read_framebuffer_ = 0;
2588 void GLES2Implementation::DeleteFramebuffersStub(
2589 GLsizei n, const GLuint* framebuffers) {
2590 helper_->DeleteFramebuffersImmediate(n, framebuffers);
2593 void GLES2Implementation::DeleteRenderbuffersHelper(
2594 GLsizei n, const GLuint* renderbuffers) {
2595 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
2596 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
2599 "glDeleteRenderbuffers", "id not created by this context.");
2602 for (GLsizei ii = 0; ii < n; ++ii) {
2603 if (renderbuffers[ii] == bound_renderbuffer_) {
2604 bound_renderbuffer_ = 0;
2609 void GLES2Implementation::DeleteRenderbuffersStub(
2610 GLsizei n, const GLuint* renderbuffers) {
2611 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
2614 void GLES2Implementation::DeleteTexturesHelper(
2615 GLsizei n, const GLuint* textures) {
2616 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
2617 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
2620 "glDeleteTextures", "id not created by this context.");
2623 for (GLsizei ii = 0; ii < n; ++ii) {
2625 tt < static_state_.int_state.max_combined_texture_image_units;
2627 TextureUnit& unit = texture_units_[tt];
2628 if (textures[ii] == unit.bound_texture_2d) {
2629 unit.bound_texture_2d = 0;
2631 if (textures[ii] == unit.bound_texture_cube_map) {
2632 unit.bound_texture_cube_map = 0;
2634 if (textures[ii] == unit.bound_texture_external_oes) {
2635 unit.bound_texture_external_oes = 0;
2641 void GLES2Implementation::DeleteVertexArraysOESHelper(
2642 GLsizei n, const GLuint* arrays) {
2643 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
2644 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
2645 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
2648 "glDeleteVertexArraysOES", "id not created by this context.");
2653 void GLES2Implementation::DeleteVertexArraysOESStub(
2654 GLsizei n, const GLuint* arrays) {
2655 helper_->DeleteVertexArraysOESImmediate(n, arrays);
2658 void GLES2Implementation::DeleteTexturesStub(
2659 GLsizei n, const GLuint* textures) {
2660 helper_->DeleteTexturesImmediate(n, textures);
2663 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
2664 GPU_CLIENT_SINGLE_THREAD_CHECK();
2666 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
2667 vertex_array_object_manager_->SetAttribEnable(index, false);
2668 helper_->DisableVertexAttribArray(index);
2672 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
2673 GPU_CLIENT_SINGLE_THREAD_CHECK();
2674 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
2676 vertex_array_object_manager_->SetAttribEnable(index, true);
2677 helper_->EnableVertexAttribArray(index);
2681 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
2682 GPU_CLIENT_SINGLE_THREAD_CHECK();
2683 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
2684 << GLES2Util::GetStringDrawMode(mode) << ", "
2685 << first << ", " << count << ")");
2687 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
2690 bool simulated = false;
2691 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
2692 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
2695 helper_->DrawArrays(mode, first, count);
2696 RestoreArrayBuffer(simulated);
2700 void GLES2Implementation::GetVertexAttribfv(
2701 GLuint index, GLenum pname, GLfloat* params) {
2702 GPU_CLIENT_SINGLE_THREAD_CHECK();
2703 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
2705 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2706 << static_cast<const void*>(params) << ")");
2708 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2709 *params = static_cast<float>(value);
2712 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
2713 typedef cmds::GetVertexAttribfv::Result Result;
2714 Result* result = GetResultAs<Result*>();
2718 result->SetNumResults(0);
2719 helper_->GetVertexAttribfv(
2720 index, pname, GetResultShmId(), GetResultShmOffset());
2722 result->CopyResult(params);
2723 GPU_CLIENT_LOG_CODE_BLOCK({
2724 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2725 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2731 void GLES2Implementation::GetVertexAttribiv(
2732 GLuint index, GLenum pname, GLint* params) {
2733 GPU_CLIENT_SINGLE_THREAD_CHECK();
2734 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
2736 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2737 << static_cast<const void*>(params) << ")");
2739 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2743 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
2744 typedef cmds::GetVertexAttribiv::Result Result;
2745 Result* result = GetResultAs<Result*>();
2749 result->SetNumResults(0);
2750 helper_->GetVertexAttribiv(
2751 index, pname, GetResultShmId(), GetResultShmOffset());
2753 result->CopyResult(params);
2754 GPU_CLIENT_LOG_CODE_BLOCK({
2755 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2756 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2762 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
2763 const char* feature) {
2764 GPU_CLIENT_SINGLE_THREAD_CHECK();
2765 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
2767 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
2768 typedef cmds::EnableFeatureCHROMIUM::Result Result;
2769 Result* result = GetResultAs<Result*>();
2774 SetBucketAsCString(kResultBucketId, feature);
2775 helper_->EnableFeatureCHROMIUM(
2776 kResultBucketId, GetResultShmId(), GetResultShmOffset());
2778 helper_->SetBucketSize(kResultBucketId, 0);
2779 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
2783 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
2784 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
2785 GPU_CLIENT_SINGLE_THREAD_CHECK();
2786 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
2787 << target << ", " << offset << ", " << size << ", "
2788 << GLES2Util::GetStringEnum(access) << ")");
2789 // NOTE: target is NOT checked because the service will check it
2790 // and we don't know what targets are valid.
2791 if (access != GL_WRITE_ONLY) {
2792 SetGLErrorInvalidEnum(
2793 "glMapBufferSubDataCHROMIUM", access, "access");
2796 if (offset < 0 || size < 0) {
2797 SetGLError(GL_INVALID_VALUE, "glMapBufferSubDataCHROMIUM", "bad range");
2801 unsigned int shm_offset;
2802 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2804 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
2808 std::pair<MappedBufferMap::iterator, bool> result =
2809 mapped_buffers_.insert(std::make_pair(
2812 access, shm_id, mem, shm_offset, target, offset, size)));
2813 GPU_DCHECK(result.second);
2814 GPU_CLIENT_LOG(" returned " << mem);
2818 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
2819 GPU_CLIENT_SINGLE_THREAD_CHECK();
2821 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
2822 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
2823 if (it == mapped_buffers_.end()) {
2825 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
2828 const MappedBuffer& mb = it->second;
2829 helper_->BufferSubData(
2830 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
2831 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
2832 mapped_buffers_.erase(it);
2836 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
2846 GPU_CLIENT_SINGLE_THREAD_CHECK();
2847 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
2848 << target << ", " << level << ", "
2849 << xoffset << ", " << yoffset << ", "
2850 << width << ", " << height << ", "
2851 << GLES2Util::GetStringTextureFormat(format) << ", "
2852 << GLES2Util::GetStringPixelType(type) << ", "
2853 << GLES2Util::GetStringEnum(access) << ")");
2854 if (access != GL_WRITE_ONLY) {
2855 SetGLErrorInvalidEnum(
2856 "glMapTexSubImage2DCHROMIUM", access, "access");
2859 // NOTE: target is NOT checked because the service will check it
2860 // and we don't know what targets are valid.
2861 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
2863 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
2867 if (!GLES2Util::ComputeImageDataSizes(
2868 width, height, format, type, unpack_alignment_, &size, NULL, NULL)) {
2870 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
2874 unsigned int shm_offset;
2875 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2877 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
2881 std::pair<MappedTextureMap::iterator, bool> result =
2882 mapped_textures_.insert(std::make_pair(
2885 access, shm_id, mem, shm_offset,
2886 target, level, xoffset, yoffset, width, height, format, type)));
2887 GPU_DCHECK(result.second);
2888 GPU_CLIENT_LOG(" returned " << mem);
2892 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
2893 GPU_CLIENT_SINGLE_THREAD_CHECK();
2895 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
2896 MappedTextureMap::iterator it = mapped_textures_.find(mem);
2897 if (it == mapped_textures_.end()) {
2899 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
2902 const MappedTexture& mt = it->second;
2903 helper_->TexSubImage2D(
2904 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
2905 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
2906 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
2907 mapped_textures_.erase(it);
2911 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
2912 float scale_factor) {
2913 GPU_CLIENT_SINGLE_THREAD_CHECK();
2914 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
2915 << width << ", " << height << ", " << scale_factor << ")");
2916 helper_->ResizeCHROMIUM(width, height, scale_factor);
2920 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
2921 GPU_CLIENT_SINGLE_THREAD_CHECK();
2922 GPU_CLIENT_LOG("[" << GetLogPrefix()
2923 << "] glGetRequestableExtensionsCHROMIUM()");
2925 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
2926 const char* result = NULL;
2927 // Clear the bucket so if the command fails nothing will be in it.
2928 helper_->SetBucketSize(kResultBucketId, 0);
2929 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
2931 if (GetBucketAsString(kResultBucketId, &str)) {
2932 // The set of requestable extensions shrinks as we enable
2933 // them. Because we don't know when the client will stop referring
2934 // to a previous one it queries (see GetString) we need to cache
2935 // the unique results.
2936 std::set<std::string>::const_iterator sit =
2937 requestable_extensions_set_.find(str);
2938 if (sit != requestable_extensions_set_.end()) {
2939 result = sit->c_str();
2941 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2942 requestable_extensions_set_.insert(str);
2943 GPU_DCHECK(insert_result.second);
2944 result = insert_result.first->c_str();
2947 GPU_CLIENT_LOG(" returned " << result);
2948 return reinterpret_cast<const GLchar*>(result);
2951 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
2952 // with VirtualGL contexts.
2953 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
2954 GPU_CLIENT_SINGLE_THREAD_CHECK();
2955 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
2956 << extension << ")");
2957 SetBucketAsCString(kResultBucketId, extension);
2958 helper_->RequestExtensionCHROMIUM(kResultBucketId);
2959 helper_->SetBucketSize(kResultBucketId, 0);
2961 struct ExtensionCheck {
2962 const char* extension;
2963 ExtensionStatus* status;
2965 const ExtensionCheck checks[] = {
2967 "GL_ANGLE_pack_reverse_row_order",
2968 &angle_pack_reverse_row_order_status_,
2971 "GL_CHROMIUM_framebuffer_multisample",
2972 &chromium_framebuffer_multisample_,
2975 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
2976 for (size_t ii = 0; ii < kNumChecks; ++ii) {
2977 const ExtensionCheck& check = checks[ii];
2978 if (*check.status == kUnavailableExtensionStatus &&
2979 !strcmp(extension, check.extension)) {
2980 *check.status = kUnknownExtensionStatus;
2985 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
2986 GPU_CLIENT_SINGLE_THREAD_CHECK();
2987 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
2988 // Wait if this would add too many rate limit tokens.
2989 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
2990 helper_->WaitForToken(rate_limit_tokens_.front());
2991 rate_limit_tokens_.pop();
2993 rate_limit_tokens_.push(helper_->InsertToken());
2996 void GLES2Implementation::GetMultipleIntegervCHROMIUM(
2997 const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size) {
2998 GPU_CLIENT_SINGLE_THREAD_CHECK();
2999 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMultipleIntegervCHROMIUM("
3000 << static_cast<const void*>(pnames) << ", "
3001 << count << ", " << results << ", "
3003 GPU_CLIENT_LOG_CODE_BLOCK({
3004 for (GLuint i = 0; i < count; ++i) {
3006 " " << i << ": " << GLES2Util::GetStringGLState(pnames[i]));
3010 GetMultipleIntegervState state(pnames, count, results, size);
3011 if (!GetMultipleIntegervSetup(&state)) {
3014 state.buffer = transfer_buffer_->Alloc(state.transfer_buffer_size_needed);
3015 if (!state.buffer) {
3016 SetGLError(GL_OUT_OF_MEMORY, "glGetMultipleIntegervCHROMIUM",
3017 "Transfer buffer allocation failed.");
3020 GetMultipleIntegervRequest(&state);
3022 GetMultipleIntegervOnCompleted(&state);
3024 GPU_CLIENT_LOG(" returned");
3025 GPU_CLIENT_LOG_CODE_BLOCK({
3026 for (int i = 0; i < state.num_results; ++i) {
3027 GPU_CLIENT_LOG(" " << i << ": " << (results[i]));
3031 // TODO(gman): We should be able to free without a token.
3032 transfer_buffer_->FreePendingToken(state.buffer, helper_->InsertToken());
3036 bool GLES2Implementation::GetMultipleIntegervSetup(
3037 GetMultipleIntegervState* state) {
3038 state->num_results = 0;
3039 for (GLuint ii = 0; ii < state->pnames_count; ++ii) {
3040 int num = util_.GLGetNumValuesReturned(state->pnames[ii]);
3042 SetGLErrorInvalidEnum(
3043 "glGetMultipleIntegervCHROMIUM", state->pnames[ii], "pname");
3046 state->num_results += num;
3048 if (static_cast<size_t>(state->results_size) !=
3049 state->num_results * sizeof(GLint)) {
3050 SetGLError(GL_INVALID_VALUE, "glGetMultipleIntegervCHROMIUM", "bad size");
3053 for (int ii = 0; ii < state->num_results; ++ii) {
3054 if (state->results[ii] != 0) {
3055 SetGLError(GL_INVALID_VALUE,
3056 "glGetMultipleIntegervCHROMIUM", "results not set to zero.");
3060 state->transfer_buffer_size_needed =
3061 state->pnames_count * sizeof(state->pnames[0]) +
3062 state->num_results * sizeof(state->results[0]);
3066 void GLES2Implementation::GetMultipleIntegervRequest(
3067 GetMultipleIntegervState* state) {
3068 GLenum* pnames_buffer = static_cast<GLenum*>(state->buffer);
3069 state->results_buffer = pnames_buffer + state->pnames_count;
3070 memcpy(pnames_buffer, state->pnames, state->pnames_count * sizeof(GLenum));
3071 memset(state->results_buffer, 0, state->num_results * sizeof(GLint));
3072 helper_->GetMultipleIntegervCHROMIUM(
3073 transfer_buffer_->GetShmId(),
3074 transfer_buffer_->GetOffset(pnames_buffer),
3075 state->pnames_count,
3076 transfer_buffer_->GetShmId(),
3077 transfer_buffer_->GetOffset(state->results_buffer),
3078 state->results_size);
3081 void GLES2Implementation::GetMultipleIntegervOnCompleted(
3082 GetMultipleIntegervState* state) {
3083 memcpy(state->results, state->results_buffer, state->results_size);;
3086 void GLES2Implementation::GetAllShaderPrecisionFormatsSetup(
3087 GetAllShaderPrecisionFormatsState* state) {
3088 state->transfer_buffer_size_needed =
3089 state->precision_params_count *
3090 sizeof(cmds::GetShaderPrecisionFormat::Result);
3093 void GLES2Implementation::GetAllShaderPrecisionFormatsRequest(
3094 GetAllShaderPrecisionFormatsState* state) {
3095 typedef cmds::GetShaderPrecisionFormat::Result Result;
3096 Result* result = static_cast<Result*>(state->results_buffer);
3098 for (int i = 0; i < state->precision_params_count; i++) {
3099 result->success = false;
3100 helper_->GetShaderPrecisionFormat(state->precision_params[i][0],
3101 state->precision_params[i][1],
3102 transfer_buffer_->GetShmId(),
3103 transfer_buffer_->GetOffset(result));
3108 void GLES2Implementation::GetAllShaderPrecisionFormatsOnCompleted(
3109 GetAllShaderPrecisionFormatsState* state) {
3110 typedef cmds::GetShaderPrecisionFormat::Result Result;
3111 Result* result = static_cast<Result*>(state->results_buffer);
3113 for (int i = 0; i < state->precision_params_count; i++) {
3114 if (result->success) {
3115 const GLStaticState::ShaderPrecisionKey key(
3116 state->precision_params[i][0], state->precision_params[i][1]);
3117 static_state_.shader_precisions[key] = *result;
3123 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3124 GLuint program, std::vector<int8>* result) {
3126 // Clear the bucket so if the command fails nothing will be in it.
3127 helper_->SetBucketSize(kResultBucketId, 0);
3128 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
3129 GetBucketContents(kResultBucketId, result);
3132 void GLES2Implementation::GetProgramInfoCHROMIUM(
3133 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3134 GPU_CLIENT_SINGLE_THREAD_CHECK();
3137 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3141 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
3144 // Make sure they've set size to 0 else the value will be undefined on
3146 GPU_DCHECK(*size == 0);
3147 std::vector<int8> result;
3148 GetProgramInfoCHROMIUMHelper(program, &result);
3149 if (result.empty()) {
3152 *size = result.size();
3156 if (static_cast<size_t>(bufsize) < result.size()) {
3157 SetGLError(GL_INVALID_OPERATION,
3158 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3161 memcpy(info, &result[0], result.size());
3164 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
3165 GPU_CLIENT_SINGLE_THREAD_CHECK();
3166 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
3168 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
3169 typedef cmds::CreateStreamTextureCHROMIUM::Result Result;
3170 Result* result = GetResultAs<Result*>();
3176 helper_->CreateStreamTextureCHROMIUM(texture,
3178 GetResultShmOffset());
3180 GLuint result_value = *result;
3182 return result_value;
3185 void GLES2Implementation::DestroyStreamTextureCHROMIUM(GLuint texture) {
3186 GPU_CLIENT_SINGLE_THREAD_CHECK();
3187 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] DestroyStreamTextureCHROMIUM("
3189 TRACE_EVENT0("gpu", "GLES2::DestroyStreamTextureCHROMIUM");
3190 helper_->DestroyStreamTextureCHROMIUM(texture);
3194 void GLES2Implementation::PostSubBufferCHROMIUM(
3195 GLint x, GLint y, GLint width, GLint height) {
3196 GPU_CLIENT_SINGLE_THREAD_CHECK();
3197 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
3198 << x << ", " << y << ", " << width << ", " << height << ")");
3199 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
3200 "width", width, "height", height);
3202 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
3203 swap_buffers_tokens_.push(helper_->InsertToken());
3204 helper_->PostSubBufferCHROMIUM(x, y, width, height);
3205 helper_->CommandBufferHelper::Flush();
3206 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
3207 helper_->WaitForToken(swap_buffers_tokens_.front());
3208 swap_buffers_tokens_.pop();
3212 void GLES2Implementation::DeleteQueriesEXTHelper(
3213 GLsizei n, const GLuint* queries) {
3214 // TODO(gman): Remove this as queries are not shared resources.
3215 if (!GetIdHandler(id_namespaces::kQueries)->FreeIds(
3216 this, n, queries, &GLES2Implementation::DeleteQueriesStub)) {
3219 "glDeleteTextures", "id not created by this context.");
3223 for (GLsizei ii = 0; ii < n; ++ii)
3224 query_tracker_->RemoveQuery(queries[ii]);
3226 helper_->DeleteQueriesEXTImmediate(n, queries);
3229 // TODO(gman): Remove this. Queries are not shared resources.
3230 void GLES2Implementation::DeleteQueriesStub(
3231 GLsizei /* n */, const GLuint* /* queries */) {
3234 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
3235 GPU_CLIENT_SINGLE_THREAD_CHECK();
3236 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
3238 // TODO(gman): To be spec compliant IDs from other contexts sharing
3239 // resources need to return true here even though you can't share
3240 // queries across contexts?
3241 return query_tracker_->GetQuery(id) != NULL;
3244 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
3245 GPU_CLIENT_SINGLE_THREAD_CHECK();
3246 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
3247 << GLES2Util::GetStringQueryTarget(target)
3248 << ", " << id << ")");
3250 // if any outstanding queries INV_OP
3251 if (current_query_) {
3253 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
3259 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
3263 // TODO(gman) if id not GENned INV_OPERATION
3265 // if id does not have an object
3266 QueryTracker::Query* query = query_tracker_->GetQuery(id);
3268 query = query_tracker_->CreateQuery(id, target);
3270 MustBeContextLost();
3273 } else if (query->target() != target) {
3275 GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
3279 current_query_ = query;
3285 void GLES2Implementation::EndQueryEXT(GLenum target) {
3286 GPU_CLIENT_SINGLE_THREAD_CHECK();
3287 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
3288 << GLES2Util::GetStringQueryTarget(target) << ")");
3289 // Don't do anything if the context is lost.
3290 if (helper_->IsContextLost()) {
3294 if (!current_query_) {
3295 SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
3299 if (current_query_->target() != target) {
3300 SetGLError(GL_INVALID_OPERATION,
3301 "glEndQueryEXT", "target does not match active query");
3305 current_query_->End(this);
3306 current_query_ = NULL;
3310 void GLES2Implementation::GetQueryivEXT(
3311 GLenum target, GLenum pname, GLint* params) {
3312 GPU_CLIENT_SINGLE_THREAD_CHECK();
3313 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
3314 << GLES2Util::GetStringQueryTarget(target) << ", "
3315 << GLES2Util::GetStringQueryParameter(pname) << ", "
3316 << static_cast<const void*>(params) << ")");
3318 if (pname != GL_CURRENT_QUERY_EXT) {
3319 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
3322 *params = (current_query_ && current_query_->target() == target) ?
3323 current_query_->id() : 0;
3324 GPU_CLIENT_LOG(" " << *params);
3328 void GLES2Implementation::GetQueryObjectuivEXT(
3329 GLuint id, GLenum pname, GLuint* params) {
3330 GPU_CLIENT_SINGLE_THREAD_CHECK();
3331 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
3332 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
3333 << static_cast<const void*>(params) << ")");
3335 QueryTracker::Query* query = query_tracker_->GetQuery(id);
3337 SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
3341 if (query == current_query_) {
3343 GL_INVALID_OPERATION,
3344 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
3348 if (query->NeverUsed()) {
3350 GL_INVALID_OPERATION,
3351 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
3356 case GL_QUERY_RESULT_EXT:
3357 if (!query->CheckResultsAvailable(helper_)) {
3358 helper_->WaitForToken(query->token());
3359 if (!query->CheckResultsAvailable(helper_)) {
3360 // TODO(gman): Speed this up.
3362 GPU_CHECK(query->CheckResultsAvailable(helper_));
3365 *params = query->GetResult();
3367 case GL_QUERY_RESULT_AVAILABLE_EXT:
3368 *params = query->CheckResultsAvailable(helper_);
3371 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
3374 GPU_CLIENT_LOG(" " << *params);
3378 void GLES2Implementation::DrawArraysInstancedANGLE(
3379 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
3380 GPU_CLIENT_SINGLE_THREAD_CHECK();
3381 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
3382 << GLES2Util::GetStringDrawMode(mode) << ", "
3383 << first << ", " << count << ", " << primcount << ")");
3385 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
3388 if (primcount < 0) {
3389 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
3392 if (primcount == 0) {
3395 bool simulated = false;
3396 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
3397 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
3401 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
3402 RestoreArrayBuffer(simulated);
3406 void GLES2Implementation::DrawElementsInstancedANGLE(
3407 GLenum mode, GLsizei count, GLenum type, const void* indices,
3408 GLsizei primcount) {
3409 GPU_CLIENT_SINGLE_THREAD_CHECK();
3410 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
3411 << GLES2Util::GetStringDrawMode(mode) << ", "
3413 << GLES2Util::GetStringIndexType(type) << ", "
3414 << static_cast<const void*>(indices) << ", "
3415 << primcount << ")");
3417 SetGLError(GL_INVALID_VALUE,
3418 "glDrawElementsInstancedANGLE", "count less than 0.");
3424 if (primcount < 0) {
3425 SetGLError(GL_INVALID_VALUE,
3426 "glDrawElementsInstancedANGLE", "primcount < 0");
3429 if (primcount == 0) {
3433 bool simulated = false;
3434 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
3435 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
3436 indices, &offset, &simulated)) {
3439 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
3440 RestoreElementAndArrayBuffers(simulated);
3444 void GLES2Implementation::GenMailboxCHROMIUM(
3446 GPU_CLIENT_SINGLE_THREAD_CHECK();
3447 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
3448 << static_cast<const void*>(mailbox) << ")");
3449 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
3451 std::vector<gpu::Mailbox> names;
3452 if (!gpu_control_->GenerateMailboxNames(1, &names)) {
3453 SetGLError(GL_OUT_OF_MEMORY, "glGenMailboxCHROMIUM", "Generate failed.");
3456 memcpy(mailbox, names[0].name, GL_MAILBOX_SIZE_CHROMIUM);
3459 void GLES2Implementation::PushGroupMarkerEXT(
3460 GLsizei length, const GLchar* marker) {
3461 GPU_CLIENT_SINGLE_THREAD_CHECK();
3462 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
3463 << length << ", " << marker << ")");
3469 (length ? std::string(marker, length) : std::string(marker)));
3470 helper_->PushGroupMarkerEXT(kResultBucketId);
3471 helper_->SetBucketSize(kResultBucketId, 0);
3472 debug_marker_manager_.PushGroup(
3473 length ? std::string(marker, length) : std::string(marker));
3476 void GLES2Implementation::InsertEventMarkerEXT(
3477 GLsizei length, const GLchar* marker) {
3478 GPU_CLIENT_SINGLE_THREAD_CHECK();
3479 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
3480 << length << ", " << marker << ")");
3486 (length ? std::string(marker, length) : std::string(marker)));
3487 helper_->InsertEventMarkerEXT(kResultBucketId);
3488 helper_->SetBucketSize(kResultBucketId, 0);
3489 debug_marker_manager_.SetMarker(
3490 length ? std::string(marker, length) : std::string(marker));
3493 void GLES2Implementation::PopGroupMarkerEXT() {
3494 GPU_CLIENT_SINGLE_THREAD_CHECK();
3495 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
3496 helper_->PopGroupMarkerEXT();
3497 debug_marker_manager_.PopGroup();
3500 void GLES2Implementation::TraceBeginCHROMIUM(const char* name) {
3501 GPU_CLIENT_SINGLE_THREAD_CHECK();
3502 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
3504 if (current_trace_name_.get()) {
3505 SetGLError(GL_INVALID_OPERATION, "glTraceBeginCHROMIUM",
3506 "trace already running");
3509 TRACE_EVENT_COPY_ASYNC_BEGIN0("gpu", name, this);
3510 SetBucketAsCString(kResultBucketId, name);
3511 helper_->TraceBeginCHROMIUM(kResultBucketId);
3512 helper_->SetBucketSize(kResultBucketId, 0);
3513 current_trace_name_.reset(new std::string(name));
3516 void GLES2Implementation::TraceEndCHROMIUM() {
3517 GPU_CLIENT_SINGLE_THREAD_CHECK();
3518 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
3519 if (!current_trace_name_.get()) {
3520 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
3521 "missing begin trace");
3524 helper_->TraceEndCHROMIUM();
3525 TRACE_EVENT_COPY_ASYNC_END0("gpu", current_trace_name_->c_str(), this);
3526 current_trace_name_.reset();
3529 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
3530 GPU_CLIENT_SINGLE_THREAD_CHECK();
3531 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
3532 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
3534 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3535 if (access != GL_READ_ONLY) {
3536 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3540 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3541 if (access != GL_WRITE_ONLY) {
3542 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3548 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
3552 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
3556 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3558 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
3561 if (buffer->mapped()) {
3562 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
3565 // Here we wait for previous transfer operations to be finished.
3566 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
3567 // with this method of synchronization. Until this is fixed,
3568 // MapBufferCHROMIUM will not block even if the transfer is not ready
3570 if (buffer->transfer_ready_token()) {
3571 helper_->WaitForToken(buffer->transfer_ready_token());
3572 buffer->set_transfer_ready_token(0);
3574 buffer->set_mapped(true);
3576 GPU_CLIENT_LOG(" returned " << buffer->address());
3578 return buffer->address();
3581 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
3582 GPU_CLIENT_SINGLE_THREAD_CHECK();
3584 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
3586 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
3587 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
3592 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3594 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
3597 if (!buffer->mapped()) {
3598 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
3601 buffer->set_mapped(false);
3606 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
3607 GLenum target, GLint level, GLint internalformat, GLsizei width,
3608 GLsizei height, GLint border, GLenum format, GLenum type,
3609 const void* pixels) {
3610 GPU_CLIENT_SINGLE_THREAD_CHECK();
3611 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
3612 << GLES2Util::GetStringTextureTarget(target) << ", "
3614 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
3615 << width << ", " << height << ", " << border << ", "
3616 << GLES2Util::GetStringTextureFormat(format) << ", "
3617 << GLES2Util::GetStringPixelType(type) << ", "
3618 << static_cast<const void*>(pixels) << ")");
3619 if (level < 0 || height < 0 || width < 0) {
3620 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
3624 uint32 unpadded_row_size;
3625 uint32 padded_row_size;
3626 if (!GLES2Util::ComputeImageDataSizes(
3627 width, height, format, type, unpack_alignment_, &size,
3628 &unpadded_row_size, &padded_row_size)) {
3629 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
3633 // If there's no data/buffer just issue the AsyncTexImage2D
3634 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
3635 helper_->AsyncTexImage2DCHROMIUM(
3636 target, level, internalformat, width, height, border, format, type,
3641 // Otherwise, async uploads require a transfer buffer to be bound.
3642 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3643 // the buffer before the transfer is finished. (Currently such
3644 // synchronization has to be handled manually.)
3645 GLuint offset = ToGLuint(pixels);
3646 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3647 bound_pixel_unpack_transfer_buffer_id_,
3648 "glAsyncTexImage2DCHROMIUM", offset, size);
3649 if (buffer && buffer->shm_id() != -1) {
3650 helper_->AsyncTexImage2DCHROMIUM(
3651 target, level, internalformat, width, height, border, format, type,
3652 buffer->shm_id(), buffer->shm_offset() + offset);
3656 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
3657 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
3658 GLsizei height, GLenum format, GLenum type, const void* pixels) {
3659 GPU_CLIENT_SINGLE_THREAD_CHECK();
3660 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
3661 << GLES2Util::GetStringTextureTarget(target) << ", "
3663 << xoffset << ", " << yoffset << ", "
3664 << width << ", " << height << ", "
3665 << GLES2Util::GetStringTextureFormat(format) << ", "
3666 << GLES2Util::GetStringPixelType(type) << ", "
3667 << static_cast<const void*>(pixels) << ")");
3668 if (level < 0 || height < 0 || width < 0) {
3670 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
3675 uint32 unpadded_row_size;
3676 uint32 padded_row_size;
3677 if (!GLES2Util::ComputeImageDataSizes(
3678 width, height, format, type, unpack_alignment_, &size,
3679 &unpadded_row_size, &padded_row_size)) {
3681 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
3685 // Async uploads require a transfer buffer to be bound.
3686 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3687 // the buffer before the transfer is finished. (Currently such
3688 // synchronization has to be handled manually.)
3689 GLuint offset = ToGLuint(pixels);
3690 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3691 bound_pixel_unpack_transfer_buffer_id_,
3692 "glAsyncTexSubImage2DCHROMIUM", offset, size);
3693 if (buffer && buffer->shm_id() != -1) {
3694 helper_->AsyncTexSubImage2DCHROMIUM(
3695 target, level, xoffset, yoffset, width, height, format, type,
3696 buffer->shm_id(), buffer->shm_offset() + offset);
3700 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
3701 GPU_CLIENT_SINGLE_THREAD_CHECK();
3702 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
3703 << GLES2Util::GetStringTextureTarget(target) << ")");
3704 helper_->WaitAsyncTexImage2DCHROMIUM(target);
3708 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
3709 GPU_CLIENT_SINGLE_THREAD_CHECK();
3710 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
3711 helper_->CommandBufferHelper::Flush();
3712 return gpu_control_->InsertSyncPoint();
3715 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(
3716 GLsizei width, GLsizei height, GLenum internalformat) {
3718 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
3723 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
3726 // Flush the command stream to ensure ordering in case the newly
3727 // returned image_id has recently been in use with a different buffer.
3728 helper_->CommandBufferHelper::Flush();
3730 // Create new buffer.
3731 GLuint buffer_id = gpu_memory_buffer_tracker_->CreateBuffer(
3732 width, height, internalformat);
3733 if (buffer_id == 0) {
3734 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "out of GPU memory.");
3740 GLuint GLES2Implementation::CreateImageCHROMIUM(
3741 GLsizei width, GLsizei height, GLenum internalformat) {
3742 GPU_CLIENT_SINGLE_THREAD_CHECK();
3743 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM("
3746 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ")");
3747 GLuint image_id = CreateImageCHROMIUMHelper(width, height, internalformat);
3752 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
3753 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3756 SetGLError(GL_INVALID_OPERATION, "glDestroyImageCHROMIUM", "invalid image");
3760 // Flush the command stream to make sure all pending commands
3761 // that may refer to the image_id are executed on the service side.
3762 helper_->CommandBufferHelper::Flush();
3763 gpu_memory_buffer_tracker_->RemoveBuffer(image_id);
3766 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
3767 GPU_CLIENT_SINGLE_THREAD_CHECK();
3768 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
3769 << image_id << ")");
3770 DestroyImageCHROMIUMHelper(image_id);
3774 void GLES2Implementation::UnmapImageCHROMIUMHelper(GLuint image_id) {
3775 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3778 SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "invalid image");
3782 if (!gpu_buffer->IsMapped()) {
3783 SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "not mapped");
3786 gpu_buffer->Unmap();
3789 void GLES2Implementation::UnmapImageCHROMIUM(GLuint image_id) {
3790 GPU_CLIENT_SINGLE_THREAD_CHECK();
3791 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapImageCHROMIUM("
3792 << image_id << ")");
3794 UnmapImageCHROMIUMHelper(image_id);
3798 void* GLES2Implementation::MapImageCHROMIUMHelper(GLuint image_id,
3800 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3803 SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "invalid image");
3806 gfx::GpuMemoryBuffer::AccessMode mode;
3809 mode = gfx::GpuMemoryBuffer::WRITE_ONLY;
3812 mode = gfx::GpuMemoryBuffer::READ_ONLY;
3815 mode = gfx::GpuMemoryBuffer::READ_WRITE;
3818 SetGLError(GL_INVALID_ENUM, "glMapImageCHROMIUM",
3819 "invalid GPU access mode");
3823 if (gpu_buffer->IsMapped()) {
3824 SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "already mapped");
3828 void* mapped_buffer = NULL;
3829 gpu_buffer->Map(mode, &mapped_buffer);
3830 return mapped_buffer;
3833 void* GLES2Implementation::MapImageCHROMIUM(
3834 GLuint image_id, GLenum access) {
3835 GPU_CLIENT_SINGLE_THREAD_CHECK();
3836 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapImageCHROMIUM("
3838 << GLES2Util::GetStringEnum(access) << ")");
3840 void* mapped = MapImageCHROMIUMHelper(image_id, access);
3845 void GLES2Implementation::GetImageParameterivCHROMIUMHelper(
3846 GLuint image_id, GLenum pname, GLint* params) {
3847 if (pname != GL_IMAGE_ROWBYTES_CHROMIUM) {
3848 SetGLError(GL_INVALID_ENUM, "glGetImageParameterivCHROMIUM",
3849 "invalid parameter");
3853 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3856 SetGLError(GL_INVALID_OPERATION, "glGetImageParameterivCHROMIUM",
3861 *params = gpu_buffer->GetStride();
3864 void GLES2Implementation::GetImageParameterivCHROMIUM(
3865 GLuint image_id, GLenum pname, GLint* params) {
3866 GPU_CLIENT_SINGLE_THREAD_CHECK();
3867 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
3868 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glImageParameterivCHROMIUM("
3870 << GLES2Util::GetStringBufferParameter(pname) << ", "
3871 << static_cast<const void*>(params) << ")");
3872 GetImageParameterivCHROMIUMHelper(image_id, pname, params);
3876 // Include the auto-generated part of this file. We split this because it means
3877 // we can easily edit the non-auto generated parts right here in this file
3878 // instead of having to edit some template or the code generator.
3879 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
3881 } // namespace gles2