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 CHECK_EQ(0, gles2_implementation_->use_count_);
76 ++gles2_implementation_->use_count_;
79 GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
80 --gles2_implementation_->use_count_;
81 CHECK_EQ(0, gles2_implementation_->use_count_);
84 GLES2Implementation::GLES2Implementation(
85 GLES2CmdHelper* helper,
86 ShareGroup* share_group,
87 TransferBufferInterface* transfer_buffer,
88 bool bind_generates_resource,
89 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 error_message_callback_(NULL),
113 gpu_control_(gpu_control),
114 capabilities_(gpu_control->GetCapabilities()),
115 weak_ptr_factory_(this) {
117 DCHECK(transfer_buffer);
120 std::stringstream ss;
121 ss << std::hex << this;
122 this_in_hex_ = ss.str();
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 DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
141 DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
142 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]);
276 // Release any per-context data in share group.
277 share_group_->FreeContext(this);
279 buffer_tracker_.reset();
281 // Make sure the commands make it the service.
285 GLES2CmdHelper* GLES2Implementation::helper() const {
289 IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
290 return share_group_->GetIdHandler(namespace_id);
293 void* GLES2Implementation::GetResultBuffer() {
294 return transfer_buffer_->GetResultBuffer();
297 int32 GLES2Implementation::GetResultShmId() {
298 return transfer_buffer_->GetShmId();
301 uint32 GLES2Implementation::GetResultShmOffset() {
302 return transfer_buffer_->GetResultOffset();
305 void GLES2Implementation::FreeUnusedSharedMemory() {
306 mapped_memory_->FreeUnused();
309 void GLES2Implementation::FreeEverything() {
311 query_tracker_->Shrink();
312 FreeUnusedSharedMemory();
313 transfer_buffer_->Free();
314 helper_->FreeRingBuffer();
317 void GLES2Implementation::RunIfContextNotLost(const base::Closure& callback) {
318 if (!helper_->IsContextLost())
322 void GLES2Implementation::SignalSyncPoint(uint32 sync_point,
323 const base::Closure& callback) {
324 gpu_control_->SignalSyncPoint(
326 base::Bind(&GLES2Implementation::RunIfContextNotLost,
327 weak_ptr_factory_.GetWeakPtr(),
331 void GLES2Implementation::SignalQuery(uint32 query,
332 const base::Closure& callback) {
333 // Flush previously entered commands to ensure ordering with any
334 // glBeginQueryEXT() calls that may have been put into the context.
335 ShallowFlushCHROMIUM();
336 gpu_control_->SignalQuery(
338 base::Bind(&GLES2Implementation::RunIfContextNotLost,
339 weak_ptr_factory_.GetWeakPtr(),
343 void GLES2Implementation::SetSurfaceVisible(bool visible) {
344 // TODO(piman): This probably should be ShallowFlushCHROMIUM().
346 gpu_control_->SetSurfaceVisible(visible);
351 void GLES2Implementation::SendManagedMemoryStats(
352 const ManagedMemoryStats& stats) {
353 gpu_control_->SendManagedMemoryStats(stats);
356 void GLES2Implementation::WaitForCmd() {
357 TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
358 helper_->CommandBufferHelper::Finish();
361 bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
362 const char* extensions =
363 reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
367 int length = strlen(ext);
369 int n = strcspn(extensions, " ");
370 if (n == length && 0 == strncmp(ext, extensions, length)) {
373 if ('\0' == extensions[n]) {
380 bool GLES2Implementation::IsExtensionAvailableHelper(
381 const char* extension, ExtensionStatus* status) {
383 case kAvailableExtensionStatus:
385 case kUnavailableExtensionStatus:
388 bool available = IsExtensionAvailable(extension);
389 *status = available ? kAvailableExtensionStatus :
390 kUnavailableExtensionStatus;
396 bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
397 return IsExtensionAvailableHelper(
398 "GL_ANGLE_pack_reverse_row_order",
399 &angle_pack_reverse_row_order_status_);
402 bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
403 return IsExtensionAvailableHelper(
404 "GL_CHROMIUM_framebuffer_multisample",
405 &chromium_framebuffer_multisample_);
408 const std::string& GLES2Implementation::GetLogPrefix() const {
409 const std::string& prefix(debug_marker_manager_.GetMarker());
410 return prefix.empty() ? this_in_hex_ : prefix;
413 GLenum GLES2Implementation::GetError() {
414 GPU_CLIENT_SINGLE_THREAD_CHECK();
415 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
416 GLenum err = GetGLError();
417 GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
421 GLenum GLES2Implementation::GetClientSideGLError() {
422 if (error_bits_ == 0) {
426 GLenum error = GL_NO_ERROR;
427 for (uint32 mask = 1; mask != 0; mask = mask << 1) {
428 if ((error_bits_ & mask) != 0) {
429 error = GLES2Util::GLErrorBitToGLError(mask);
433 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
437 GLenum GLES2Implementation::GetGLError() {
438 TRACE_EVENT0("gpu", "GLES2::GetGLError");
439 // Check the GL error first, then our wrapped error.
440 typedef cmds::GetError::Result Result;
441 Result* result = GetResultAs<Result*>();
442 // If we couldn't allocate a result the context is lost.
446 *result = GL_NO_ERROR;
447 helper_->GetError(GetResultShmId(), GetResultShmOffset());
449 GLenum error = *result;
450 if (error == GL_NO_ERROR) {
451 error = GetClientSideGLError();
453 // There was an error, clear the corresponding wrapped error.
454 error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
459 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
460 void GLES2Implementation::FailGLError(GLenum error) {
461 if (error != GL_NO_ERROR) {
462 NOTREACHED() << "Error";
465 // NOTE: Calling GetGLError overwrites data in the result buffer.
466 void GLES2Implementation::CheckGLError() {
467 FailGLError(GetGLError());
469 #endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
471 void GLES2Implementation::SetGLError(
472 GLenum error, const char* function_name, const char* msg) {
473 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
474 << GLES2Util::GetStringError(error) << ": "
475 << function_name << ": " << msg);
480 if (error_message_callback_) {
481 std::string temp(GLES2Util::GetStringError(error) + " : " +
482 function_name + ": " + (msg ? msg : ""));
483 error_message_callback_->OnErrorMessage(temp.c_str(), 0);
485 error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
488 void GLES2Implementation::SetGLErrorInvalidEnum(
489 const char* function_name, GLenum value, const char* label) {
490 SetGLError(GL_INVALID_ENUM, function_name,
491 (std::string(label) + " was " +
492 GLES2Util::GetStringEnum(value)).c_str());
495 bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
496 std::vector<int8>* data) {
497 TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
499 const uint32 kStartSize = 32 * 1024;
500 ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
501 if (!buffer.valid()) {
504 typedef cmd::GetBucketStart::Result Result;
505 Result* result = GetResultAs<Result*>();
510 helper_->GetBucketStart(
511 bucket_id, GetResultShmId(), GetResultShmOffset(),
512 buffer.size(), buffer.shm_id(), buffer.offset());
514 uint32 size = *result;
519 if (!buffer.valid()) {
521 if (!buffer.valid()) {
524 helper_->GetBucketData(
525 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
528 uint32 size_to_copy = std::min(size, buffer.size());
529 memcpy(&(*data)[offset], buffer.address(), size_to_copy);
530 offset += size_to_copy;
531 size -= size_to_copy;
534 // Free the bucket. This is not required but it does free up the memory.
535 // and we don't have to wait for the result so from the client's perspective
537 helper_->SetBucketSize(bucket_id, 0);
542 void GLES2Implementation::SetBucketContents(
543 uint32 bucket_id, const void* data, size_t size) {
545 helper_->SetBucketSize(bucket_id, size);
549 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
550 if (!buffer.valid()) {
553 memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
555 helper_->SetBucketData(
556 bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
557 offset += buffer.size();
558 size -= buffer.size();
563 void GLES2Implementation::SetBucketAsCString(
564 uint32 bucket_id, const char* str) {
565 // NOTE: strings are passed NULL terminated. That means the empty
566 // string will have a size of 1 and no-string will have a size of 0
568 SetBucketContents(bucket_id, str, strlen(str) + 1);
570 helper_->SetBucketSize(bucket_id, 0);
574 bool GLES2Implementation::GetBucketAsString(
575 uint32 bucket_id, std::string* str) {
577 std::vector<int8> data;
578 // NOTE: strings are passed NULL terminated. That means the empty
579 // string will have a size of 1 and no-string will have a size of 0
580 if (!GetBucketContents(bucket_id, &data)) {
586 str->assign(&data[0], &data[0] + data.size() - 1);
590 void GLES2Implementation::SetBucketAsString(
591 uint32 bucket_id, const std::string& str) {
592 // NOTE: strings are passed NULL terminated. That means the empty
593 // string will have a size of 1 and no-string will have a size of 0
594 SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
597 void GLES2Implementation::Disable(GLenum cap) {
598 GPU_CLIENT_SINGLE_THREAD_CHECK();
599 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
600 << GLES2Util::GetStringCapability(cap) << ")");
601 bool changed = false;
602 if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
603 helper_->Disable(cap);
608 void GLES2Implementation::Enable(GLenum cap) {
609 GPU_CLIENT_SINGLE_THREAD_CHECK();
610 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
611 << GLES2Util::GetStringCapability(cap) << ")");
612 bool changed = false;
613 if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
614 helper_->Enable(cap);
619 GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
620 GPU_CLIENT_SINGLE_THREAD_CHECK();
621 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
622 << GLES2Util::GetStringCapability(cap) << ")");
624 if (!state_.GetEnabled(cap, &state)) {
625 typedef cmds::IsEnabled::Result Result;
626 Result* result = GetResultAs<Result*>();
631 helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
633 state = (*result) != 0;
636 GPU_CLIENT_LOG("returned " << state);
641 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
643 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
644 *params = static_state_.int_state.max_combined_texture_image_units;
646 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
647 *params = static_state_.int_state.max_cube_map_texture_size;
649 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
650 *params = static_state_.int_state.max_fragment_uniform_vectors;
652 case GL_MAX_RENDERBUFFER_SIZE:
653 *params = static_state_.int_state.max_renderbuffer_size;
655 case GL_MAX_TEXTURE_IMAGE_UNITS:
656 *params = static_state_.int_state.max_texture_image_units;
658 case GL_MAX_TEXTURE_SIZE:
659 *params = static_state_.int_state.max_texture_size;
661 case GL_MAX_VARYING_VECTORS:
662 *params = static_state_.int_state.max_varying_vectors;
664 case GL_MAX_VERTEX_ATTRIBS:
665 *params = static_state_.int_state.max_vertex_attribs;
667 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
668 *params = static_state_.int_state.max_vertex_texture_image_units;
670 case GL_MAX_VERTEX_UNIFORM_VECTORS:
671 *params = static_state_.int_state.max_vertex_uniform_vectors;
673 case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
674 *params = static_state_.int_state.num_compressed_texture_formats;
676 case GL_NUM_SHADER_BINARY_FORMATS:
677 *params = static_state_.int_state.num_shader_binary_formats;
679 case GL_ARRAY_BUFFER_BINDING:
680 if (share_group_->bind_generates_resource()) {
681 *params = bound_array_buffer_id_;
685 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
686 if (share_group_->bind_generates_resource()) {
688 vertex_array_object_manager_->bound_element_array_buffer();
692 case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
693 *params = bound_pixel_pack_transfer_buffer_id_;
695 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
696 *params = bound_pixel_unpack_transfer_buffer_id_;
698 case GL_ACTIVE_TEXTURE:
699 *params = active_texture_unit_ + GL_TEXTURE0;
701 case GL_TEXTURE_BINDING_2D:
702 if (share_group_->bind_generates_resource()) {
703 *params = texture_units_[active_texture_unit_].bound_texture_2d;
707 case GL_TEXTURE_BINDING_CUBE_MAP:
708 if (share_group_->bind_generates_resource()) {
709 *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
713 case GL_TEXTURE_BINDING_EXTERNAL_OES:
714 if (share_group_->bind_generates_resource()) {
716 texture_units_[active_texture_unit_].bound_texture_external_oes;
720 case GL_FRAMEBUFFER_BINDING:
721 if (share_group_->bind_generates_resource()) {
722 *params = bound_framebuffer_;
726 case GL_READ_FRAMEBUFFER_BINDING:
727 if (IsChromiumFramebufferMultisampleAvailable() &&
728 share_group_->bind_generates_resource()) {
729 *params = bound_read_framebuffer_;
733 case GL_RENDERBUFFER_BINDING:
734 if (share_group_->bind_generates_resource()) {
735 *params = bound_renderbuffer_;
744 bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
745 // TODO(gman): Make this handle pnames that return more than 1 value.
747 if (!GetHelper(pname, &value)) {
750 *params = static_cast<GLboolean>(value);
754 bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
755 // TODO(gman): Make this handle pnames that return more than 1 value.
757 if (!GetHelper(pname, &value)) {
760 *params = static_cast<GLfloat>(value);
764 bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
765 return GetHelper(pname, params);
768 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
769 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
770 typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
771 Result* result = GetResultAs<Result*>();
776 helper_->GetMaxValueInBufferCHROMIUM(
777 buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
782 GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
783 GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
784 GPU_CLIENT_SINGLE_THREAD_CHECK();
785 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
786 << buffer_id << ", " << count << ", "
787 << GLES2Util::GetStringGetMaxIndexType(type)
788 << ", " << offset << ")");
789 GLuint result = GetMaxValueInBufferCHROMIUMHelper(
790 buffer_id, count, type, offset);
791 GPU_CLIENT_LOG("returned " << result);
796 void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
798 RestoreArrayBuffer(restore);
799 // Restore the element array binding.
800 // We only need to restore it if it wasn't a client side array.
801 if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
802 helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
807 void GLES2Implementation::RestoreArrayBuffer(bool restore) {
809 // Restore the user's current binding.
810 helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_);
814 void GLES2Implementation::DrawElements(
815 GLenum mode, GLsizei count, GLenum type, const void* indices) {
816 GPU_CLIENT_SINGLE_THREAD_CHECK();
817 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
818 << GLES2Util::GetStringDrawMode(mode) << ", "
820 << GLES2Util::GetStringIndexType(type) << ", "
821 << static_cast<const void*>(indices) << ")");
823 SetGLError(GL_INVALID_VALUE, "glDrawElements", "count less than 0.");
830 bool simulated = false;
831 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
832 "glDrawElements", this, helper_, count, type, 0, indices,
833 &offset, &simulated)) {
836 helper_->DrawElements(mode, count, type, offset);
837 RestoreElementAndArrayBuffers(simulated);
841 void GLES2Implementation::Flush() {
842 GPU_CLIENT_SINGLE_THREAD_CHECK();
843 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
844 // Insert the cmd to call glFlush
846 // Flush our command buffer
847 // (tell the service to execute up to the flush cmd.)
848 helper_->CommandBufferHelper::Flush();
851 void GLES2Implementation::ShallowFlushCHROMIUM() {
852 GPU_CLIENT_SINGLE_THREAD_CHECK();
853 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
854 // Flush our command buffer
855 // (tell the service to execute up to the flush cmd.)
856 helper_->CommandBufferHelper::Flush();
857 // TODO(piman): Add the FreeEverything() logic here.
860 void GLES2Implementation::Finish() {
861 GPU_CLIENT_SINGLE_THREAD_CHECK();
865 void GLES2Implementation::ShallowFinishCHROMIUM() {
866 GPU_CLIENT_SINGLE_THREAD_CHECK();
867 TRACE_EVENT0("gpu", "GLES2::ShallowFinishCHROMIUM");
868 // Flush our command buffer (tell the service to execute up to the flush cmd
869 // and don't return until it completes).
870 helper_->CommandBufferHelper::Finish();
873 bool GLES2Implementation::MustBeContextLost() {
874 bool context_lost = helper_->IsContextLost();
877 context_lost = helper_->IsContextLost();
883 void GLES2Implementation::FinishHelper() {
884 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
885 TRACE_EVENT0("gpu", "GLES2::Finish");
886 // Insert the cmd to call glFinish
888 // Finish our command buffer
889 // (tell the service to execute up to the Finish cmd and wait for it to
891 helper_->CommandBufferHelper::Finish();
894 void GLES2Implementation::SwapBuffers() {
895 GPU_CLIENT_SINGLE_THREAD_CHECK();
896 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
897 // TODO(piman): Strictly speaking we'd want to insert the token after the
898 // swap, but the state update with the updated token might not have happened
899 // by the time the SwapBuffer callback gets called, forcing us to synchronize
900 // with the GPU process more than needed. So instead, make it happen before.
901 // All it means is that we could be slightly looser on the kMaxSwapBuffers
902 // semantics if the client doesn't use the callback mechanism, and by chance
903 // the scheduler yields between the InsertToken and the SwapBuffers.
904 swap_buffers_tokens_.push(helper_->InsertToken());
905 helper_->SwapBuffers();
906 helper_->CommandBufferHelper::Flush();
907 // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
908 // compensate for TODO above.
909 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
910 helper_->WaitForToken(swap_buffers_tokens_.front());
911 swap_buffers_tokens_.pop();
915 void GLES2Implementation::GenSharedIdsCHROMIUM(
916 GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) {
917 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenSharedIdsCHROMIUM("
918 << namespace_id << ", " << id_offset << ", " << n << ", " <<
919 static_cast<void*>(ids) << ")");
920 TRACE_EVENT0("gpu", "GLES2::GenSharedIdsCHROMIUM");
924 ScopedTransferBufferArray<GLint> id_buffer(num, helper_, transfer_buffer_);
925 if (!id_buffer.valid()) {
928 helper_->GenSharedIdsCHROMIUM(
929 namespace_id, id_offset, id_buffer.num_elements(),
930 id_buffer.shm_id(), id_buffer.offset());
932 memcpy(dst, id_buffer.address(), sizeof(*dst) * id_buffer.num_elements());
933 num -= id_buffer.num_elements();
934 dst += id_buffer.num_elements();
936 GPU_CLIENT_LOG_CODE_BLOCK({
937 for (GLsizei i = 0; i < n; ++i) {
938 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
943 void GLES2Implementation::DeleteSharedIdsCHROMIUM(
944 GLuint namespace_id, GLsizei n, const GLuint* ids) {
945 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteSharedIdsCHROMIUM("
946 << namespace_id << ", " << n << ", "
947 << static_cast<const void*>(ids) << ")");
948 GPU_CLIENT_LOG_CODE_BLOCK({
949 for (GLsizei i = 0; i < n; ++i) {
950 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
953 TRACE_EVENT0("gpu", "GLES2::DeleteSharedIdsCHROMIUM");
955 ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
956 if (!id_buffer.valid()) {
959 memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
960 helper_->DeleteSharedIdsCHROMIUM(
961 namespace_id, id_buffer.num_elements(),
962 id_buffer.shm_id(), id_buffer.offset());
964 n -= id_buffer.num_elements();
965 ids += id_buffer.num_elements();
969 void GLES2Implementation::RegisterSharedIdsCHROMIUM(
970 GLuint namespace_id, GLsizei n, const GLuint* ids) {
971 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRegisterSharedIdsCHROMIUM("
972 << namespace_id << ", " << n << ", "
973 << static_cast<const void*>(ids) << ")");
974 GPU_CLIENT_LOG_CODE_BLOCK({
975 for (GLsizei i = 0; i < n; ++i) {
976 GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
979 TRACE_EVENT0("gpu", "GLES2::RegisterSharedIdsCHROMIUM");
981 ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
982 if (!id_buffer.valid()) {
985 memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
986 helper_->RegisterSharedIdsCHROMIUM(
987 namespace_id, id_buffer.num_elements(),
988 id_buffer.shm_id(), id_buffer.offset());
990 n -= id_buffer.num_elements();
991 ids += id_buffer.num_elements();
995 void GLES2Implementation::BindAttribLocation(
996 GLuint program, GLuint index, const char* name) {
997 GPU_CLIENT_SINGLE_THREAD_CHECK();
998 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
999 << program << ", " << index << ", " << name << ")");
1000 SetBucketAsString(kResultBucketId, name);
1001 helper_->BindAttribLocationBucket(program, index, kResultBucketId);
1002 helper_->SetBucketSize(kResultBucketId, 0);
1006 void GLES2Implementation::BindUniformLocationCHROMIUM(
1007 GLuint program, GLint location, const char* name) {
1008 GPU_CLIENT_SINGLE_THREAD_CHECK();
1009 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
1010 << program << ", " << location << ", " << name << ")");
1011 SetBucketAsString(kResultBucketId, name);
1012 helper_->BindUniformLocationCHROMIUMBucket(
1013 program, location, kResultBucketId);
1014 helper_->SetBucketSize(kResultBucketId, 0);
1018 void GLES2Implementation::GetVertexAttribPointerv(
1019 GLuint index, GLenum pname, void** ptr) {
1020 GPU_CLIENT_SINGLE_THREAD_CHECK();
1021 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
1022 << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
1023 << static_cast<void*>(ptr) << ")");
1024 GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
1025 if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
1026 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
1027 typedef cmds::GetVertexAttribPointerv::Result Result;
1028 Result* result = GetResultAs<Result*>();
1032 result->SetNumResults(0);
1033 helper_->GetVertexAttribPointerv(
1034 index, pname, GetResultShmId(), GetResultShmOffset());
1036 result->CopyResult(ptr);
1037 GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
1039 GPU_CLIENT_LOG_CODE_BLOCK({
1040 for (int32 i = 0; i < num_results; ++i) {
1041 GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
1047 bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
1048 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1049 this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
1052 "glDeleteProgram", "id not created by this context.");
1055 if (program == current_program_) {
1056 current_program_ = 0;
1061 void GLES2Implementation::DeleteProgramStub(
1062 GLsizei n, const GLuint* programs) {
1064 share_group_->program_info_manager()->DeleteInfo(programs[0]);
1065 helper_->DeleteProgram(programs[0]);
1068 bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
1069 if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
1070 this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
1073 "glDeleteShader", "id not created by this context.");
1079 void GLES2Implementation::DeleteShaderStub(
1080 GLsizei n, const GLuint* shaders) {
1082 share_group_->program_info_manager()->DeleteInfo(shaders[0]);
1083 helper_->DeleteShader(shaders[0]);
1087 GLint GLES2Implementation::GetAttribLocationHelper(
1088 GLuint program, const char* name) {
1089 typedef cmds::GetAttribLocationBucket::Result Result;
1090 Result* result = GetResultAs<Result*>();
1095 SetBucketAsCString(kResultBucketId, name);
1096 helper_->GetAttribLocationBucket(
1097 program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
1099 helper_->SetBucketSize(kResultBucketId, 0);
1103 GLint GLES2Implementation::GetAttribLocation(
1104 GLuint program, const char* name) {
1105 GPU_CLIENT_SINGLE_THREAD_CHECK();
1106 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
1107 << ", " << name << ")");
1108 TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
1109 GLint loc = share_group_->program_info_manager()->GetAttribLocation(
1110 this, program, name);
1111 GPU_CLIENT_LOG("returned " << loc);
1116 GLint GLES2Implementation::GetUniformLocationHelper(
1117 GLuint program, const char* name) {
1118 typedef cmds::GetUniformLocationBucket::Result Result;
1119 Result* result = GetResultAs<Result*>();
1124 SetBucketAsCString(kResultBucketId, name);
1125 helper_->GetUniformLocationBucket(program, kResultBucketId,
1126 GetResultShmId(), GetResultShmOffset());
1128 helper_->SetBucketSize(kResultBucketId, 0);
1132 GLint GLES2Implementation::GetUniformLocation(
1133 GLuint program, const char* name) {
1134 GPU_CLIENT_SINGLE_THREAD_CHECK();
1135 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
1136 << ", " << name << ")");
1137 TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
1138 GLint loc = share_group_->program_info_manager()->GetUniformLocation(
1139 this, program, name);
1140 GPU_CLIENT_LOG("returned " << loc);
1145 bool GLES2Implementation::GetProgramivHelper(
1146 GLuint program, GLenum pname, GLint* params) {
1147 bool got_value = share_group_->program_info_manager()->GetProgramiv(
1148 this, program, pname, params);
1149 GPU_CLIENT_LOG_CODE_BLOCK({
1151 GPU_CLIENT_LOG(" 0: " << *params);
1157 void GLES2Implementation::LinkProgram(GLuint program) {
1158 GPU_CLIENT_SINGLE_THREAD_CHECK();
1159 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
1160 helper_->LinkProgram(program);
1161 share_group_->program_info_manager()->CreateInfo(program);
1165 void GLES2Implementation::ShaderBinary(
1166 GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
1168 GPU_CLIENT_SINGLE_THREAD_CHECK();
1169 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
1170 << static_cast<const void*>(shaders) << ", "
1171 << GLES2Util::GetStringEnum(binaryformat) << ", "
1172 << static_cast<const void*>(binary) << ", "
1175 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
1179 SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
1182 // TODO(gman): ShaderBinary should use buckets.
1183 unsigned int shader_id_size = n * sizeof(*shaders);
1184 ScopedTransferBufferArray<GLint> buffer(
1185 shader_id_size + length, helper_, transfer_buffer_);
1186 if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
1187 SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
1190 void* shader_ids = buffer.elements();
1191 void* shader_data = buffer.elements() + shader_id_size;
1192 memcpy(shader_ids, shaders, shader_id_size);
1193 memcpy(shader_data, binary, length);
1194 helper_->ShaderBinary(
1200 buffer.offset() + shader_id_size,
1205 void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
1206 GPU_CLIENT_SINGLE_THREAD_CHECK();
1207 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
1208 << GLES2Util::GetStringPixelStore(pname) << ", "
1211 case GL_PACK_ALIGNMENT:
1212 pack_alignment_ = param;
1214 case GL_UNPACK_ALIGNMENT:
1215 unpack_alignment_ = param;
1217 case GL_UNPACK_ROW_LENGTH_EXT:
1218 unpack_row_length_ = param;
1220 case GL_UNPACK_SKIP_ROWS_EXT:
1221 unpack_skip_rows_ = param;
1223 case GL_UNPACK_SKIP_PIXELS_EXT:
1224 unpack_skip_pixels_ = param;
1226 case GL_UNPACK_FLIP_Y_CHROMIUM:
1227 unpack_flip_y_ = (param != 0);
1229 case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
1230 pack_reverse_row_order_ =
1231 IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
1236 helper_->PixelStorei(pname, param);
1241 void GLES2Implementation::VertexAttribPointer(
1242 GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
1244 GPU_CLIENT_SINGLE_THREAD_CHECK();
1245 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
1248 << GLES2Util::GetStringVertexAttribType(type) << ", "
1249 << GLES2Util::GetStringBool(normalized) << ", "
1251 << static_cast<const void*>(ptr) << ")");
1252 // Record the info on the client side.
1253 if (!vertex_array_object_manager_->SetAttribPointer(
1254 bound_array_buffer_id_, index, size, type, normalized, stride, ptr)) {
1255 SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
1256 "client side arrays are not allowed in vertex array objects.");
1259 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1260 if (bound_array_buffer_id_ != 0) {
1261 // Only report NON client side buffers to the service.
1262 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1265 #else // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1266 helper_->VertexAttribPointer(index, size, type, normalized, stride,
1268 #endif // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
1272 void GLES2Implementation::VertexAttribDivisorANGLE(
1273 GLuint index, GLuint divisor) {
1274 GPU_CLIENT_SINGLE_THREAD_CHECK();
1275 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
1277 << divisor << ") ");
1278 // Record the info on the client side.
1279 vertex_array_object_manager_->SetAttribDivisor(index, divisor);
1280 helper_->VertexAttribDivisorANGLE(index, divisor);
1284 void GLES2Implementation::ShaderSource(
1285 GLuint shader, GLsizei count, const GLchar* const* source, const GLint* length) {
1286 GPU_CLIENT_SINGLE_THREAD_CHECK();
1287 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderSource("
1288 << shader << ", " << count << ", "
1289 << static_cast<const void*>(source) << ", "
1290 << static_cast<const void*>(length) << ")");
1291 GPU_CLIENT_LOG_CODE_BLOCK({
1292 for (GLsizei ii = 0; ii < count; ++ii) {
1294 if (length && length[ii] >= 0) {
1295 std::string str(source[ii], length[ii]);
1296 GPU_CLIENT_LOG(" " << ii << ": ---\n" << str << "\n---");
1298 GPU_CLIENT_LOG(" " << ii << ": ---\n" << source[ii] << "\n---");
1301 GPU_CLIENT_LOG(" " << ii << ": NULL");
1306 SetGLError(GL_INVALID_VALUE, "glShaderSource", "count < 0");
1310 SetGLError(GL_INVALID_VALUE, "glShaderSource", "shader == 0");
1314 // Compute the total size.
1315 uint32 total_size = 1;
1316 for (GLsizei ii = 0; ii < count; ++ii) {
1318 total_size += (length && length[ii] >= 0) ?
1319 static_cast<size_t>(length[ii]) : strlen(source[ii]);
1323 // Concatenate all the strings in to a bucket on the service.
1324 helper_->SetBucketSize(kResultBucketId, total_size);
1326 for (GLsizei ii = 0; ii <= count; ++ii) {
1327 const char* src = ii < count ? source[ii] : "";
1329 uint32 size = ii < count ?
1330 (length ? static_cast<size_t>(length[ii]) : strlen(src)) : 1;
1332 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1333 if (!buffer.valid()) {
1336 memcpy(buffer.address(), src, buffer.size());
1337 helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
1338 buffer.shm_id(), buffer.offset());
1339 offset += buffer.size();
1340 src += buffer.size();
1341 size -= buffer.size();
1346 DCHECK_EQ(total_size, offset);
1348 helper_->ShaderSourceBucket(shader, kResultBucketId);
1349 helper_->SetBucketSize(kResultBucketId, 0);
1353 void GLES2Implementation::BufferDataHelper(
1354 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1356 SetGLError(GL_INVALID_VALUE, "glBufferData", "size < 0");
1361 if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
1366 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1368 // Free buffer memory, pending the passage of a token.
1369 buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
1371 // Remove old buffer.
1372 buffer_tracker_->RemoveBuffer(buffer_id);
1375 // Create new buffer.
1376 buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
1378 if (buffer->address() && data)
1379 memcpy(buffer->address(), data, size);
1387 // If there is no data just send BufferData
1389 helper_->BufferData(target, size, 0, 0, usage);
1393 // See if we can send all at once.
1394 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1395 if (!buffer.valid()) {
1399 if (buffer.size() >= static_cast<unsigned int>(size)) {
1400 memcpy(buffer.address(), data, size);
1401 helper_->BufferData(
1410 // Make the buffer with BufferData then send via BufferSubData
1411 helper_->BufferData(target, size, 0, 0, usage);
1412 BufferSubDataHelperImpl(target, 0, size, data, &buffer);
1416 void GLES2Implementation::BufferData(
1417 GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
1418 GPU_CLIENT_SINGLE_THREAD_CHECK();
1419 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
1420 << GLES2Util::GetStringBufferTarget(target) << ", "
1422 << static_cast<const void*>(data) << ", "
1423 << GLES2Util::GetStringBufferUsage(usage) << ")");
1424 BufferDataHelper(target, size, data, usage);
1428 void GLES2Implementation::BufferSubDataHelper(
1429 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1435 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "size < 0");
1440 if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
1444 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1446 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
1451 int32 buffer_size = buffer->size();
1452 if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
1453 SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
1457 if (buffer->address() && data)
1458 memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
1462 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1463 BufferSubDataHelperImpl(target, offset, size, data, &buffer);
1466 void GLES2Implementation::BufferSubDataHelperImpl(
1467 GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
1468 ScopedTransferBufferPtr* buffer) {
1472 const int8* source = static_cast<const int8*>(data);
1474 if (!buffer->valid() || buffer->size() == 0) {
1475 buffer->Reset(size);
1476 if (!buffer->valid()) {
1480 memcpy(buffer->address(), source, buffer->size());
1481 helper_->BufferSubData(
1482 target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
1483 offset += buffer->size();
1484 source += buffer->size();
1485 size -= buffer->size();
1490 void GLES2Implementation::BufferSubData(
1491 GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
1492 GPU_CLIENT_SINGLE_THREAD_CHECK();
1493 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
1494 << GLES2Util::GetStringBufferTarget(target) << ", "
1495 << offset << ", " << size << ", "
1496 << static_cast<const void*>(data) << ")");
1497 BufferSubDataHelper(target, offset, size, data);
1501 bool GLES2Implementation::GetBoundPixelTransferBuffer(
1503 const char* function_name,
1504 GLuint* buffer_id) {
1508 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
1509 *buffer_id = bound_pixel_pack_transfer_buffer_id_;
1511 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
1512 *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
1519 SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
1524 BufferTracker::Buffer*
1525 GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
1527 const char* function_name,
1528 GLuint offset, GLsizei size)
1531 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
1533 SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
1536 if (buffer->mapped()) {
1537 SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
1540 if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
1541 SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
1547 void GLES2Implementation::CompressedTexImage2D(
1548 GLenum target, GLint level, GLenum internalformat, GLsizei width,
1549 GLsizei height, GLint border, GLsizei image_size, const void* data) {
1550 GPU_CLIENT_SINGLE_THREAD_CHECK();
1551 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
1552 << GLES2Util::GetStringTextureTarget(target) << ", "
1554 << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
1555 << width << ", " << height << ", " << border << ", "
1556 << image_size << ", "
1557 << static_cast<const void*>(data) << ")");
1558 if (width < 0 || height < 0 || level < 0) {
1559 SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
1562 if (height == 0 || width == 0) {
1565 // If there's a pixel unpack buffer bound use it when issuing
1566 // CompressedTexImage2D.
1567 if (bound_pixel_unpack_transfer_buffer_id_) {
1568 GLuint offset = ToGLuint(data);
1569 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1570 bound_pixel_unpack_transfer_buffer_id_,
1571 "glCompressedTexImage2D", offset, image_size);
1572 if (buffer && buffer->shm_id() != -1) {
1573 helper_->CompressedTexImage2D(
1574 target, level, internalformat, width, height, border, image_size,
1575 buffer->shm_id(), buffer->shm_offset() + offset);
1576 buffer->set_transfer_ready_token(helper_->InsertToken());
1580 SetBucketContents(kResultBucketId, data, image_size);
1581 helper_->CompressedTexImage2DBucket(
1582 target, level, internalformat, width, height, border, kResultBucketId);
1583 // Free the bucket. This is not required but it does free up the memory.
1584 // and we don't have to wait for the result so from the client's perspective
1586 helper_->SetBucketSize(kResultBucketId, 0);
1590 void GLES2Implementation::CompressedTexSubImage2D(
1591 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1592 GLsizei height, GLenum format, GLsizei image_size, const void* data) {
1593 GPU_CLIENT_SINGLE_THREAD_CHECK();
1594 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
1595 << GLES2Util::GetStringTextureTarget(target) << ", "
1597 << xoffset << ", " << yoffset << ", "
1598 << width << ", " << height << ", "
1599 << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
1600 << image_size << ", "
1601 << static_cast<const void*>(data) << ")");
1602 if (width < 0 || height < 0 || level < 0) {
1603 SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
1606 // If there's a pixel unpack buffer bound use it when issuing
1607 // CompressedTexSubImage2D.
1608 if (bound_pixel_unpack_transfer_buffer_id_) {
1609 GLuint offset = ToGLuint(data);
1610 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1611 bound_pixel_unpack_transfer_buffer_id_,
1612 "glCompressedTexSubImage2D", offset, image_size);
1613 if (buffer && buffer->shm_id() != -1) {
1614 helper_->CompressedTexSubImage2D(
1615 target, level, xoffset, yoffset, width, height, format, image_size,
1616 buffer->shm_id(), buffer->shm_offset() + offset);
1617 buffer->set_transfer_ready_token(helper_->InsertToken());
1622 SetBucketContents(kResultBucketId, data, image_size);
1623 helper_->CompressedTexSubImage2DBucket(
1624 target, level, xoffset, yoffset, width, height, format, kResultBucketId);
1625 // Free the bucket. This is not required but it does free up the memory.
1626 // and we don't have to wait for the result so from the client's perspective
1628 helper_->SetBucketSize(kResultBucketId, 0);
1634 void CopyRectToBuffer(
1637 uint32 unpadded_row_size,
1638 uint32 pixels_padded_row_size,
1641 uint32 buffer_padded_row_size) {
1642 const int8* source = static_cast<const int8*>(pixels);
1643 int8* dest = static_cast<int8*>(buffer);
1644 if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
1646 dest += buffer_padded_row_size * (height - 1);
1648 // the last row is copied unpadded at the end
1649 for (; height > 1; --height) {
1650 memcpy(dest, source, buffer_padded_row_size);
1652 dest -= buffer_padded_row_size;
1654 dest += buffer_padded_row_size;
1656 source += pixels_padded_row_size;
1658 memcpy(dest, source, unpadded_row_size);
1660 uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
1661 memcpy(dest, source, size);
1665 } // anonymous namespace
1667 void GLES2Implementation::TexImage2D(
1668 GLenum target, GLint level, GLint internalformat, GLsizei width,
1669 GLsizei height, GLint border, GLenum format, GLenum type,
1670 const void* pixels) {
1671 GPU_CLIENT_SINGLE_THREAD_CHECK();
1672 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
1673 << GLES2Util::GetStringTextureTarget(target) << ", "
1675 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
1676 << width << ", " << height << ", " << border << ", "
1677 << GLES2Util::GetStringTextureFormat(format) << ", "
1678 << GLES2Util::GetStringPixelType(type) << ", "
1679 << static_cast<const void*>(pixels) << ")");
1680 if (level < 0 || height < 0 || width < 0) {
1681 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
1685 uint32 unpadded_row_size;
1686 uint32 padded_row_size;
1687 if (!GLES2Util::ComputeImageDataSizes(
1688 width, height, format, type, unpack_alignment_, &size,
1689 &unpadded_row_size, &padded_row_size)) {
1690 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
1694 // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
1695 if (bound_pixel_unpack_transfer_buffer_id_) {
1696 GLuint offset = ToGLuint(pixels);
1697 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1698 bound_pixel_unpack_transfer_buffer_id_,
1699 "glTexImage2D", offset, size);
1700 if (buffer && buffer->shm_id() != -1) {
1701 helper_->TexImage2D(
1702 target, level, internalformat, width, height, border, format, type,
1703 buffer->shm_id(), buffer->shm_offset() + offset);
1704 buffer->set_transfer_ready_token(helper_->InsertToken());
1710 // If there's no data just issue TexImage2D
1712 helper_->TexImage2D(
1713 target, level, internalformat, width, height, border, format, type,
1719 // compute the advance bytes per row for the src pixels
1720 uint32 src_padded_row_size;
1721 if (unpack_row_length_ > 0) {
1722 if (!GLES2Util::ComputeImagePaddedRowSize(
1723 unpack_row_length_, format, type, unpack_alignment_,
1724 &src_padded_row_size)) {
1726 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1730 src_padded_row_size = padded_row_size;
1733 // advance pixels pointer past the skip rows and skip pixels
1734 pixels = reinterpret_cast<const int8*>(pixels) +
1735 unpack_skip_rows_ * src_padded_row_size;
1736 if (unpack_skip_pixels_) {
1737 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1738 pixels = reinterpret_cast<const int8*>(pixels) +
1739 unpack_skip_pixels_ * group_size;
1742 // Check if we can send it all at once.
1743 ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
1744 if (!buffer.valid()) {
1748 if (buffer.size() >= size) {
1750 pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
1751 buffer.address(), padded_row_size);
1752 helper_->TexImage2D(
1753 target, level, internalformat, width, height, border, format, type,
1754 buffer.shm_id(), buffer.offset());
1759 // No, so send it using TexSubImage2D.
1760 helper_->TexImage2D(
1761 target, level, internalformat, width, height, border, format, type,
1764 target, level, 0, 0, width, height, format, type, unpadded_row_size,
1765 pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
1769 void GLES2Implementation::TexSubImage2D(
1770 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1771 GLsizei height, GLenum format, GLenum type, const void* pixels) {
1772 GPU_CLIENT_SINGLE_THREAD_CHECK();
1773 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
1774 << GLES2Util::GetStringTextureTarget(target) << ", "
1776 << xoffset << ", " << yoffset << ", "
1777 << width << ", " << height << ", "
1778 << GLES2Util::GetStringTextureFormat(format) << ", "
1779 << GLES2Util::GetStringPixelType(type) << ", "
1780 << static_cast<const void*>(pixels) << ")");
1782 if (level < 0 || height < 0 || width < 0) {
1783 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
1786 if (height == 0 || width == 0) {
1791 uint32 unpadded_row_size;
1792 uint32 padded_row_size;
1793 if (!GLES2Util::ComputeImageDataSizes(
1794 width, height, format, type, unpack_alignment_, &temp_size,
1795 &unpadded_row_size, &padded_row_size)) {
1796 SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
1800 // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
1801 if (bound_pixel_unpack_transfer_buffer_id_) {
1802 GLuint offset = ToGLuint(pixels);
1803 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
1804 bound_pixel_unpack_transfer_buffer_id_,
1805 "glTexSubImage2D", offset, temp_size);
1806 if (buffer && buffer->shm_id() != -1) {
1807 helper_->TexSubImage2D(
1808 target, level, xoffset, yoffset, width, height, format, type,
1809 buffer->shm_id(), buffer->shm_offset() + offset, false);
1810 buffer->set_transfer_ready_token(helper_->InsertToken());
1816 // compute the advance bytes per row for the src pixels
1817 uint32 src_padded_row_size;
1818 if (unpack_row_length_ > 0) {
1819 if (!GLES2Util::ComputeImagePaddedRowSize(
1820 unpack_row_length_, format, type, unpack_alignment_,
1821 &src_padded_row_size)) {
1823 GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
1827 src_padded_row_size = padded_row_size;
1830 // advance pixels pointer past the skip rows and skip pixels
1831 pixels = reinterpret_cast<const int8*>(pixels) +
1832 unpack_skip_rows_ * src_padded_row_size;
1833 if (unpack_skip_pixels_) {
1834 uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
1835 pixels = reinterpret_cast<const int8*>(pixels) +
1836 unpack_skip_pixels_ * group_size;
1839 ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
1841 target, level, xoffset, yoffset, width, height, format, type,
1842 unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
1847 static GLint ComputeNumRowsThatFitInBuffer(
1848 GLsizeiptr padded_row_size, GLsizeiptr unpadded_row_size,
1849 unsigned int size) {
1850 DCHECK_GE(unpadded_row_size, 0);
1851 if (padded_row_size == 0) {
1854 GLint num_rows = size / padded_row_size;
1855 return num_rows + (size - num_rows * padded_row_size) / unpadded_row_size;
1858 void GLES2Implementation::TexSubImage2DImpl(
1859 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
1860 GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
1861 const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
1862 ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
1864 DCHECK_GE(level, 0);
1865 DCHECK_GT(height, 0);
1866 DCHECK_GT(width, 0);
1868 const int8* source = reinterpret_cast<const int8*>(pixels);
1869 GLint original_yoffset = yoffset;
1870 // Transfer by rows.
1872 unsigned int desired_size =
1873 buffer_padded_row_size * (height - 1) + unpadded_row_size;
1874 if (!buffer->valid() || buffer->size() == 0) {
1875 buffer->Reset(desired_size);
1876 if (!buffer->valid()) {
1881 GLint num_rows = ComputeNumRowsThatFitInBuffer(
1882 buffer_padded_row_size, unpadded_row_size, buffer->size());
1883 num_rows = std::min(num_rows, height);
1885 source, num_rows, unpadded_row_size, pixels_padded_row_size,
1886 unpack_flip_y_, buffer->address(), buffer_padded_row_size);
1887 GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
1888 helper_->TexSubImage2D(
1889 target, level, xoffset, y, width, num_rows, format, type,
1890 buffer->shm_id(), buffer->offset(), internal);
1892 yoffset += num_rows;
1893 source += num_rows * pixels_padded_row_size;
1898 bool GLES2Implementation::GetActiveAttribHelper(
1899 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1900 GLenum* type, char* name) {
1901 // Clear the bucket so if the command fails nothing will be in it.
1902 helper_->SetBucketSize(kResultBucketId, 0);
1903 typedef cmds::GetActiveAttrib::Result Result;
1904 Result* result = GetResultAs<Result*>();
1908 // Set as failed so if the command fails we'll recover.
1909 result->success = false;
1910 helper_->GetActiveAttrib(program, index, kResultBucketId,
1911 GetResultShmId(), GetResultShmOffset());
1913 if (result->success) {
1915 *size = result->size;
1918 *type = result->type;
1920 if (length || name) {
1921 std::vector<int8> str;
1922 GetBucketContents(kResultBucketId, &str);
1923 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
1924 std::max(static_cast<size_t>(0),
1929 if (name && bufsize > 0) {
1930 memcpy(name, &str[0], max_size);
1931 name[max_size] = '\0';
1935 return result->success != 0;
1938 void GLES2Implementation::GetActiveAttrib(
1939 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1940 GLenum* type, char* name) {
1941 GPU_CLIENT_SINGLE_THREAD_CHECK();
1942 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
1943 << program << ", " << index << ", " << bufsize << ", "
1944 << static_cast<const void*>(length) << ", "
1945 << static_cast<const void*>(size) << ", "
1946 << static_cast<const void*>(type) << ", "
1947 << static_cast<const void*>(name) << ", ");
1949 SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
1952 TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
1953 bool success = share_group_->program_info_manager()->GetActiveAttrib(
1954 this, program, index, bufsize, length, size, type, name);
1957 GPU_CLIENT_LOG(" size: " << *size);
1960 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
1963 GPU_CLIENT_LOG(" name: " << name);
1969 bool GLES2Implementation::GetActiveUniformHelper(
1970 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
1971 GLenum* type, char* name) {
1972 // Clear the bucket so if the command fails nothing will be in it.
1973 helper_->SetBucketSize(kResultBucketId, 0);
1974 typedef cmds::GetActiveUniform::Result Result;
1975 Result* result = GetResultAs<Result*>();
1979 // Set as failed so if the command fails we'll recover.
1980 result->success = false;
1981 helper_->GetActiveUniform(program, index, kResultBucketId,
1982 GetResultShmId(), GetResultShmOffset());
1984 if (result->success) {
1986 *size = result->size;
1989 *type = result->type;
1991 if (length || name) {
1992 std::vector<int8> str;
1993 GetBucketContents(kResultBucketId, &str);
1994 GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
1995 std::max(static_cast<size_t>(0),
2000 if (name && bufsize > 0) {
2001 memcpy(name, &str[0], max_size);
2002 name[max_size] = '\0';
2006 return result->success != 0;
2009 void GLES2Implementation::GetActiveUniform(
2010 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
2011 GLenum* type, char* name) {
2012 GPU_CLIENT_SINGLE_THREAD_CHECK();
2013 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
2014 << program << ", " << index << ", " << bufsize << ", "
2015 << static_cast<const void*>(length) << ", "
2016 << static_cast<const void*>(size) << ", "
2017 << static_cast<const void*>(type) << ", "
2018 << static_cast<const void*>(name) << ", ");
2020 SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
2023 TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
2024 bool success = share_group_->program_info_manager()->GetActiveUniform(
2025 this, program, index, bufsize, length, size, type, name);
2028 GPU_CLIENT_LOG(" size: " << *size);
2031 GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
2034 GPU_CLIENT_LOG(" name: " << name);
2040 void GLES2Implementation::GetAttachedShaders(
2041 GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
2042 GPU_CLIENT_SINGLE_THREAD_CHECK();
2043 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
2044 << program << ", " << maxcount << ", "
2045 << static_cast<const void*>(count) << ", "
2046 << static_cast<const void*>(shaders) << ", ");
2048 SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
2051 TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
2052 typedef cmds::GetAttachedShaders::Result Result;
2053 uint32 size = Result::ComputeSize(maxcount);
2054 Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
2058 result->SetNumResults(0);
2059 helper_->GetAttachedShaders(
2061 transfer_buffer_->GetShmId(),
2062 transfer_buffer_->GetOffset(result),
2064 int32 token = helper_->InsertToken();
2067 *count = result->GetNumResults();
2069 result->CopyResult(shaders);
2070 GPU_CLIENT_LOG_CODE_BLOCK({
2071 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2072 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2075 transfer_buffer_->FreePendingToken(result, token);
2079 void GLES2Implementation::GetShaderPrecisionFormat(
2080 GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
2081 GPU_CLIENT_SINGLE_THREAD_CHECK();
2082 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
2083 << GLES2Util::GetStringShaderType(shadertype) << ", "
2084 << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
2085 << static_cast<const void*>(range) << ", "
2086 << static_cast<const void*>(precision) << ", ");
2087 TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
2088 typedef cmds::GetShaderPrecisionFormat::Result Result;
2089 Result* result = GetResultAs<Result*>();
2094 GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
2095 GLStaticState::ShaderPrecisionMap::iterator i =
2096 static_state_.shader_precisions.find(key);
2097 if (i != static_state_.shader_precisions.end()) {
2098 *result = i->second;
2100 result->success = false;
2101 helper_->GetShaderPrecisionFormat(
2102 shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
2104 if (result->success)
2105 static_state_.shader_precisions[key] = *result;
2108 if (result->success) {
2110 range[0] = result->min_range;
2111 range[1] = result->max_range;
2112 GPU_CLIENT_LOG(" min_range: " << range[0]);
2113 GPU_CLIENT_LOG(" min_range: " << range[1]);
2116 precision[0] = result->precision;
2117 GPU_CLIENT_LOG(" min_range: " << precision[0]);
2123 const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
2124 const char* result = NULL;
2125 // Clears the bucket so if the command fails nothing will be in it.
2126 helper_->SetBucketSize(kResultBucketId, 0);
2127 helper_->GetString(name, kResultBucketId);
2129 if (GetBucketAsString(kResultBucketId, &str)) {
2130 // Adds extensions implemented on client side only.
2133 str += std::string(str.empty() ? "" : " ") +
2134 "GL_CHROMIUM_flipy "
2135 "GL_EXT_unpack_subimage";
2136 if (capabilities_.map_image) {
2137 // The first space character is intentional.
2138 str += " GL_CHROMIUM_map_image";
2145 // Because of WebGL the extensions can change. We have to cache each unique
2146 // result since we don't know when the client will stop referring to a
2147 // previous one it queries.
2148 GLStringMap::iterator it = gl_strings_.find(name);
2149 if (it == gl_strings_.end()) {
2150 std::set<std::string> strings;
2151 std::pair<GLStringMap::iterator, bool> insert_result =
2152 gl_strings_.insert(std::make_pair(name, strings));
2153 DCHECK(insert_result.second);
2154 it = insert_result.first;
2156 std::set<std::string>& string_set = it->second;
2157 std::set<std::string>::const_iterator sit = string_set.find(str);
2158 if (sit != string_set.end()) {
2159 result = sit->c_str();
2161 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2162 string_set.insert(str);
2163 DCHECK(insert_result.second);
2164 result = insert_result.first->c_str();
2167 return reinterpret_cast<const GLubyte*>(result);
2170 const GLubyte* GLES2Implementation::GetString(GLenum name) {
2171 GPU_CLIENT_SINGLE_THREAD_CHECK();
2172 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
2173 << GLES2Util::GetStringStringType(name) << ")");
2174 TRACE_EVENT0("gpu", "GLES2::GetString");
2175 const GLubyte* result = GetStringHelper(name);
2176 GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
2181 void GLES2Implementation::GetUniformfv(
2182 GLuint program, GLint location, GLfloat* params) {
2183 GPU_CLIENT_SINGLE_THREAD_CHECK();
2184 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
2185 << program << ", " << location << ", "
2186 << static_cast<const void*>(params) << ")");
2187 TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
2188 typedef cmds::GetUniformfv::Result Result;
2189 Result* result = GetResultAs<Result*>();
2193 result->SetNumResults(0);
2194 helper_->GetUniformfv(
2195 program, location, GetResultShmId(), GetResultShmOffset());
2197 result->CopyResult(params);
2198 GPU_CLIENT_LOG_CODE_BLOCK({
2199 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2200 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2206 void GLES2Implementation::GetUniformiv(
2207 GLuint program, GLint location, GLint* params) {
2208 GPU_CLIENT_SINGLE_THREAD_CHECK();
2209 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
2210 << program << ", " << location << ", "
2211 << static_cast<const void*>(params) << ")");
2212 TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
2213 typedef cmds::GetUniformiv::Result Result;
2214 Result* result = GetResultAs<Result*>();
2218 result->SetNumResults(0);
2219 helper_->GetUniformiv(
2220 program, location, GetResultShmId(), GetResultShmOffset());
2222 GetResultAs<cmds::GetUniformfv::Result*>()->CopyResult(params);
2223 GPU_CLIENT_LOG_CODE_BLOCK({
2224 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2225 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2231 void GLES2Implementation::ReadPixels(
2232 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
2233 GLenum type, void* pixels) {
2234 GPU_CLIENT_SINGLE_THREAD_CHECK();
2235 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
2236 << xoffset << ", " << yoffset << ", "
2237 << width << ", " << height << ", "
2238 << GLES2Util::GetStringReadPixelFormat(format) << ", "
2239 << GLES2Util::GetStringPixelType(type) << ", "
2240 << static_cast<const void*>(pixels) << ")");
2241 if (width < 0 || height < 0) {
2242 SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
2245 if (width == 0 || height == 0) {
2249 // glReadPixel pads the size of each row of pixels by an amount specified by
2250 // glPixelStorei. So, we have to take that into account both in the fact that
2251 // the pixels returned from the ReadPixel command will include that padding
2252 // and that when we copy the results to the user's buffer we need to not
2253 // write those padding bytes but leave them as they are.
2255 TRACE_EVENT0("gpu", "GLES2::ReadPixels");
2256 typedef cmds::ReadPixels::Result Result;
2258 int8* dest = reinterpret_cast<int8*>(pixels);
2260 uint32 unpadded_row_size;
2261 uint32 padded_row_size;
2262 if (!GLES2Util::ComputeImageDataSizes(
2263 width, 2, format, type, pack_alignment_, &temp_size, &unpadded_row_size,
2264 &padded_row_size)) {
2265 SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
2269 if (bound_pixel_pack_transfer_buffer_id_) {
2270 GLuint offset = ToGLuint(pixels);
2271 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
2272 bound_pixel_pack_transfer_buffer_id_,
2273 "glReadPixels", offset, padded_row_size * height);
2274 if (buffer && buffer->shm_id() != -1) {
2275 helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
2276 buffer->shm_id(), buffer->shm_offset(),
2284 SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
2288 // Transfer by rows.
2289 // The max rows we can transfer.
2291 GLsizei desired_size = padded_row_size * height - 1 + unpadded_row_size;
2292 ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
2293 if (!buffer.valid()) {
2296 GLint num_rows = ComputeNumRowsThatFitInBuffer(
2297 padded_row_size, unpadded_row_size, buffer.size());
2298 num_rows = std::min(num_rows, height);
2299 // NOTE: We must look up the address of the result area AFTER allocation
2300 // of the transfer buffer since the transfer buffer may be reallocated.
2301 Result* result = GetResultAs<Result*>();
2305 *result = 0; // mark as failed.
2306 helper_->ReadPixels(
2307 xoffset, yoffset, width, num_rows, format, type,
2308 buffer.shm_id(), buffer.offset(),
2309 GetResultShmId(), GetResultShmOffset(),
2313 // when doing a y-flip we have to iterate through top-to-bottom chunks
2314 // of the dst. The service side handles reversing the rows within a
2317 if (pack_reverse_row_order_) {
2318 rows_dst = dest + (height - num_rows) * padded_row_size;
2322 // We have to copy 1 row at a time to avoid writing pad bytes.
2323 const int8* src = static_cast<const int8*>(buffer.address());
2324 for (GLint yy = 0; yy < num_rows; ++yy) {
2325 memcpy(rows_dst, src, unpadded_row_size);
2326 rows_dst += padded_row_size;
2327 src += padded_row_size;
2329 if (!pack_reverse_row_order_) {
2333 // If it was not marked as successful exit.
2337 yoffset += num_rows;
2343 void GLES2Implementation::ActiveTexture(GLenum texture) {
2344 GPU_CLIENT_SINGLE_THREAD_CHECK();
2345 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
2346 << GLES2Util::GetStringEnum(texture) << ")");
2347 GLuint texture_index = texture - GL_TEXTURE0;
2348 if (texture_index >= static_cast<GLuint>(
2349 static_state_.int_state.max_combined_texture_image_units)) {
2350 SetGLErrorInvalidEnum(
2351 "glActiveTexture", texture, "texture");
2355 active_texture_unit_ = texture_index;
2356 helper_->ActiveTexture(texture);
2360 void GLES2Implementation::GenBuffersHelper(
2361 GLsizei /* n */, const GLuint* /* buffers */) {
2364 void GLES2Implementation::GenFramebuffersHelper(
2365 GLsizei /* n */, const GLuint* /* framebuffers */) {
2368 void GLES2Implementation::GenRenderbuffersHelper(
2369 GLsizei /* n */, const GLuint* /* renderbuffers */) {
2372 void GLES2Implementation::GenTexturesHelper(
2373 GLsizei /* n */, const GLuint* /* textures */) {
2376 void GLES2Implementation::GenVertexArraysOESHelper(
2377 GLsizei n, const GLuint* arrays) {
2378 vertex_array_object_manager_->GenVertexArrays(n, arrays);
2381 void GLES2Implementation::GenQueriesEXTHelper(
2382 GLsizei /* n */, const GLuint* /* queries */) {
2385 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
2386 // generates a new resource. On newer versions of OpenGL they don't. The code
2387 // related to binding below will need to change if we switch to the new OpenGL
2388 // model. Specifically it assumes a bind will succeed which is always true in
2389 // the old model but possibly not true in the new model if another context has
2390 // deleted the resource.
2392 bool GLES2Implementation::BindBufferHelper(
2393 GLenum target, GLuint buffer) {
2394 // TODO(gman): See note #1 above.
2395 bool changed = false;
2397 case GL_ARRAY_BUFFER:
2398 if (bound_array_buffer_id_ != buffer) {
2399 bound_array_buffer_id_ = buffer;
2403 case GL_ELEMENT_ARRAY_BUFFER:
2404 changed = vertex_array_object_manager_->BindElementArray(buffer);
2406 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
2407 bound_pixel_pack_transfer_buffer_id_ = buffer;
2409 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
2410 bound_pixel_unpack_transfer_buffer_id_ = buffer;
2416 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2417 // used even though it's marked it as used here.
2418 GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(buffer);
2422 bool GLES2Implementation::BindFramebufferHelper(
2423 GLenum target, GLuint framebuffer) {
2424 // TODO(gman): See note #1 above.
2425 bool changed = false;
2427 case GL_FRAMEBUFFER:
2428 if (bound_framebuffer_ != framebuffer ||
2429 bound_read_framebuffer_ != framebuffer) {
2430 bound_framebuffer_ = framebuffer;
2431 bound_read_framebuffer_ = framebuffer;
2435 case GL_READ_FRAMEBUFFER:
2436 if (!IsChromiumFramebufferMultisampleAvailable()) {
2437 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2440 if (bound_read_framebuffer_ != framebuffer) {
2441 bound_read_framebuffer_ = framebuffer;
2445 case GL_DRAW_FRAMEBUFFER:
2446 if (!IsChromiumFramebufferMultisampleAvailable()) {
2447 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2450 if (bound_framebuffer_ != framebuffer) {
2451 bound_framebuffer_ = framebuffer;
2456 SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
2459 GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(framebuffer);
2463 bool GLES2Implementation::BindRenderbufferHelper(
2464 GLenum target, GLuint renderbuffer) {
2465 // TODO(gman): See note #1 above.
2466 bool changed = false;
2468 case GL_RENDERBUFFER:
2469 if (bound_renderbuffer_ != renderbuffer) {
2470 bound_renderbuffer_ = renderbuffer;
2478 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2479 // used even though it's marked it as used here.
2480 GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(renderbuffer);
2484 bool GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
2485 // TODO(gman): See note #1 above.
2486 // TODO(gman): Change this to false once we figure out why it's failing
2488 bool changed = true;
2489 TextureUnit& unit = texture_units_[active_texture_unit_];
2492 if (unit.bound_texture_2d != texture) {
2493 unit.bound_texture_2d = texture;
2497 case GL_TEXTURE_CUBE_MAP:
2498 if (unit.bound_texture_cube_map != texture) {
2499 unit.bound_texture_cube_map = texture;
2503 case GL_TEXTURE_EXTERNAL_OES:
2504 if (unit.bound_texture_external_oes != texture) {
2505 unit.bound_texture_external_oes = texture;
2513 // TODO(gman): There's a bug here. If the target is invalid the ID will not be
2514 // used. even though it's marked it as used here.
2515 GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(texture);
2519 bool GLES2Implementation::BindVertexArrayOESHelper(GLuint array) {
2520 // TODO(gman): See note #1 above.
2521 bool changed = false;
2522 if (!vertex_array_object_manager_->BindVertexArray(array, &changed)) {
2524 GL_INVALID_OPERATION, "glBindVertexArrayOES",
2525 "id was not generated with glGenVertexArrayOES");
2527 // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
2528 // because unlike other resources VertexArrayObject ids must
2529 // be generated by GenVertexArrays. A random id to Bind will not
2530 // generate a new object.
2534 bool GLES2Implementation::UseProgramHelper(GLuint program) {
2535 bool changed = false;
2536 if (current_program_ != program) {
2537 current_program_ = program;
2543 bool GLES2Implementation::IsBufferReservedId(GLuint id) {
2544 return vertex_array_object_manager_->IsReservedId(id);
2547 void GLES2Implementation::DeleteBuffersHelper(
2548 GLsizei n, const GLuint* buffers) {
2549 if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
2550 this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
2553 "glDeleteBuffers", "id not created by this context.");
2556 for (GLsizei ii = 0; ii < n; ++ii) {
2557 if (buffers[ii] == bound_array_buffer_id_) {
2558 bound_array_buffer_id_ = 0;
2560 vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
2561 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
2563 // Free buffer memory, pending the passage of a token.
2564 buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
2566 buffer_tracker_->RemoveBuffer(buffers[ii]);
2568 if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
2569 bound_pixel_unpack_transfer_buffer_id_ = 0;
2574 void GLES2Implementation::DeleteBuffersStub(
2575 GLsizei n, const GLuint* buffers) {
2576 helper_->DeleteBuffersImmediate(n, buffers);
2580 void GLES2Implementation::DeleteFramebuffersHelper(
2581 GLsizei n, const GLuint* framebuffers) {
2582 if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
2583 this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
2586 "glDeleteFramebuffers", "id not created by this context.");
2589 for (GLsizei ii = 0; ii < n; ++ii) {
2590 if (framebuffers[ii] == bound_framebuffer_) {
2591 bound_framebuffer_ = 0;
2593 if (framebuffers[ii] == bound_read_framebuffer_) {
2594 bound_read_framebuffer_ = 0;
2599 void GLES2Implementation::DeleteFramebuffersStub(
2600 GLsizei n, const GLuint* framebuffers) {
2601 helper_->DeleteFramebuffersImmediate(n, framebuffers);
2604 void GLES2Implementation::DeleteRenderbuffersHelper(
2605 GLsizei n, const GLuint* renderbuffers) {
2606 if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
2607 this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
2610 "glDeleteRenderbuffers", "id not created by this context.");
2613 for (GLsizei ii = 0; ii < n; ++ii) {
2614 if (renderbuffers[ii] == bound_renderbuffer_) {
2615 bound_renderbuffer_ = 0;
2620 void GLES2Implementation::DeleteRenderbuffersStub(
2621 GLsizei n, const GLuint* renderbuffers) {
2622 helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
2625 void GLES2Implementation::DeleteTexturesHelper(
2626 GLsizei n, const GLuint* textures) {
2627 if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
2628 this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
2631 "glDeleteTextures", "id not created by this context.");
2634 for (GLsizei ii = 0; ii < n; ++ii) {
2636 tt < static_state_.int_state.max_combined_texture_image_units;
2638 TextureUnit& unit = texture_units_[tt];
2639 if (textures[ii] == unit.bound_texture_2d) {
2640 unit.bound_texture_2d = 0;
2642 if (textures[ii] == unit.bound_texture_cube_map) {
2643 unit.bound_texture_cube_map = 0;
2645 if (textures[ii] == unit.bound_texture_external_oes) {
2646 unit.bound_texture_external_oes = 0;
2652 void GLES2Implementation::DeleteVertexArraysOESHelper(
2653 GLsizei n, const GLuint* arrays) {
2654 vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
2655 if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
2656 this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
2659 "glDeleteVertexArraysOES", "id not created by this context.");
2664 void GLES2Implementation::DeleteVertexArraysOESStub(
2665 GLsizei n, const GLuint* arrays) {
2666 helper_->DeleteVertexArraysOESImmediate(n, arrays);
2669 void GLES2Implementation::DeleteTexturesStub(
2670 GLsizei n, const GLuint* textures) {
2671 helper_->DeleteTexturesImmediate(n, textures);
2674 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
2675 GPU_CLIENT_SINGLE_THREAD_CHECK();
2677 "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
2678 vertex_array_object_manager_->SetAttribEnable(index, false);
2679 helper_->DisableVertexAttribArray(index);
2683 void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
2684 GPU_CLIENT_SINGLE_THREAD_CHECK();
2685 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
2687 vertex_array_object_manager_->SetAttribEnable(index, true);
2688 helper_->EnableVertexAttribArray(index);
2692 void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
2693 GPU_CLIENT_SINGLE_THREAD_CHECK();
2694 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
2695 << GLES2Util::GetStringDrawMode(mode) << ", "
2696 << first << ", " << count << ")");
2698 SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
2701 bool simulated = false;
2702 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
2703 "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
2706 helper_->DrawArrays(mode, first, count);
2707 RestoreArrayBuffer(simulated);
2711 void GLES2Implementation::GetVertexAttribfv(
2712 GLuint index, GLenum pname, GLfloat* params) {
2713 GPU_CLIENT_SINGLE_THREAD_CHECK();
2714 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
2716 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2717 << static_cast<const void*>(params) << ")");
2719 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2720 *params = static_cast<float>(value);
2723 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
2724 typedef cmds::GetVertexAttribfv::Result Result;
2725 Result* result = GetResultAs<Result*>();
2729 result->SetNumResults(0);
2730 helper_->GetVertexAttribfv(
2731 index, pname, GetResultShmId(), GetResultShmOffset());
2733 result->CopyResult(params);
2734 GPU_CLIENT_LOG_CODE_BLOCK({
2735 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2736 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2742 void GLES2Implementation::GetVertexAttribiv(
2743 GLuint index, GLenum pname, GLint* params) {
2744 GPU_CLIENT_SINGLE_THREAD_CHECK();
2745 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
2747 << GLES2Util::GetStringVertexAttribute(pname) << ", "
2748 << static_cast<const void*>(params) << ")");
2750 if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
2754 TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
2755 typedef cmds::GetVertexAttribiv::Result Result;
2756 Result* result = GetResultAs<Result*>();
2760 result->SetNumResults(0);
2761 helper_->GetVertexAttribiv(
2762 index, pname, GetResultShmId(), GetResultShmOffset());
2764 result->CopyResult(params);
2765 GPU_CLIENT_LOG_CODE_BLOCK({
2766 for (int32 i = 0; i < result->GetNumResults(); ++i) {
2767 GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
2773 void GLES2Implementation::Swap() {
2776 base::Bind(&GLES2Implementation::OnSwapBuffersComplete,
2777 weak_ptr_factory_.GetWeakPtr()));
2780 void GLES2Implementation::PartialSwapBuffers(const gfx::Rect& sub_buffer) {
2781 PostSubBufferCHROMIUM(sub_buffer.x(),
2784 sub_buffer.height());
2785 gpu_control_->Echo(base::Bind(&GLES2Implementation::OnSwapBuffersComplete,
2786 weak_ptr_factory_.GetWeakPtr()));
2789 void GLES2Implementation::SetSwapBuffersCompleteCallback(
2790 const base::Closure& swap_buffers_complete_callback) {
2791 swap_buffers_complete_callback_ = swap_buffers_complete_callback;
2794 void GLES2Implementation::ScheduleOverlayPlane(int plane_z_order,
2795 unsigned plane_transform,
2796 unsigned overlay_texture_id,
2797 const gfx::Rect& display_bounds,
2798 const gfx::RectF& uv_rect) {
2799 NOTREACHED() << "Overlay supported isn't finished.";
2802 void GLES2Implementation::OnSwapBuffersComplete() {
2803 if (!swap_buffers_complete_callback_.is_null())
2804 swap_buffers_complete_callback_.Run();
2807 GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
2808 const char* feature) {
2809 GPU_CLIENT_SINGLE_THREAD_CHECK();
2810 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
2812 TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
2813 typedef cmds::EnableFeatureCHROMIUM::Result Result;
2814 Result* result = GetResultAs<Result*>();
2819 SetBucketAsCString(kResultBucketId, feature);
2820 helper_->EnableFeatureCHROMIUM(
2821 kResultBucketId, GetResultShmId(), GetResultShmOffset());
2823 helper_->SetBucketSize(kResultBucketId, 0);
2824 GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
2828 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
2829 GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
2830 GPU_CLIENT_SINGLE_THREAD_CHECK();
2831 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
2832 << target << ", " << offset << ", " << size << ", "
2833 << GLES2Util::GetStringEnum(access) << ")");
2834 // NOTE: target is NOT checked because the service will check it
2835 // and we don't know what targets are valid.
2836 if (access != GL_WRITE_ONLY) {
2837 SetGLErrorInvalidEnum(
2838 "glMapBufferSubDataCHROMIUM", access, "access");
2841 if (offset < 0 || size < 0) {
2842 SetGLError(GL_INVALID_VALUE, "glMapBufferSubDataCHROMIUM", "bad range");
2846 unsigned int shm_offset;
2847 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2849 SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
2853 std::pair<MappedBufferMap::iterator, bool> result =
2854 mapped_buffers_.insert(std::make_pair(
2857 access, shm_id, mem, shm_offset, target, offset, size)));
2858 DCHECK(result.second);
2859 GPU_CLIENT_LOG(" returned " << mem);
2863 void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
2864 GPU_CLIENT_SINGLE_THREAD_CHECK();
2866 "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
2867 MappedBufferMap::iterator it = mapped_buffers_.find(mem);
2868 if (it == mapped_buffers_.end()) {
2870 GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
2873 const MappedBuffer& mb = it->second;
2874 helper_->BufferSubData(
2875 mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
2876 mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
2877 mapped_buffers_.erase(it);
2881 void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
2891 GPU_CLIENT_SINGLE_THREAD_CHECK();
2892 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
2893 << target << ", " << level << ", "
2894 << xoffset << ", " << yoffset << ", "
2895 << width << ", " << height << ", "
2896 << GLES2Util::GetStringTextureFormat(format) << ", "
2897 << GLES2Util::GetStringPixelType(type) << ", "
2898 << GLES2Util::GetStringEnum(access) << ")");
2899 if (access != GL_WRITE_ONLY) {
2900 SetGLErrorInvalidEnum(
2901 "glMapTexSubImage2DCHROMIUM", access, "access");
2904 // NOTE: target is NOT checked because the service will check it
2905 // and we don't know what targets are valid.
2906 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
2908 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
2912 if (!GLES2Util::ComputeImageDataSizes(
2913 width, height, format, type, unpack_alignment_, &size, NULL, NULL)) {
2915 GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
2919 unsigned int shm_offset;
2920 void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
2922 SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
2926 std::pair<MappedTextureMap::iterator, bool> result =
2927 mapped_textures_.insert(std::make_pair(
2930 access, shm_id, mem, shm_offset,
2931 target, level, xoffset, yoffset, width, height, format, type)));
2932 DCHECK(result.second);
2933 GPU_CLIENT_LOG(" returned " << mem);
2937 void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
2938 GPU_CLIENT_SINGLE_THREAD_CHECK();
2940 "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
2941 MappedTextureMap::iterator it = mapped_textures_.find(mem);
2942 if (it == mapped_textures_.end()) {
2944 GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
2947 const MappedTexture& mt = it->second;
2948 helper_->TexSubImage2D(
2949 mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
2950 mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
2951 mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
2952 mapped_textures_.erase(it);
2956 void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
2957 float scale_factor) {
2958 GPU_CLIENT_SINGLE_THREAD_CHECK();
2959 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
2960 << width << ", " << height << ", " << scale_factor << ")");
2961 helper_->ResizeCHROMIUM(width, height, scale_factor);
2965 const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
2966 GPU_CLIENT_SINGLE_THREAD_CHECK();
2967 GPU_CLIENT_LOG("[" << GetLogPrefix()
2968 << "] glGetRequestableExtensionsCHROMIUM()");
2970 "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
2971 const char* result = NULL;
2972 // Clear the bucket so if the command fails nothing will be in it.
2973 helper_->SetBucketSize(kResultBucketId, 0);
2974 helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
2976 if (GetBucketAsString(kResultBucketId, &str)) {
2977 // The set of requestable extensions shrinks as we enable
2978 // them. Because we don't know when the client will stop referring
2979 // to a previous one it queries (see GetString) we need to cache
2980 // the unique results.
2981 std::set<std::string>::const_iterator sit =
2982 requestable_extensions_set_.find(str);
2983 if (sit != requestable_extensions_set_.end()) {
2984 result = sit->c_str();
2986 std::pair<std::set<std::string>::const_iterator, bool> insert_result =
2987 requestable_extensions_set_.insert(str);
2988 DCHECK(insert_result.second);
2989 result = insert_result.first->c_str();
2992 GPU_CLIENT_LOG(" returned " << result);
2993 return reinterpret_cast<const GLchar*>(result);
2996 // TODO(gman): Remove this command. It's here for WebGL but is incompatible
2997 // with VirtualGL contexts.
2998 void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
2999 GPU_CLIENT_SINGLE_THREAD_CHECK();
3000 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
3001 << extension << ")");
3002 SetBucketAsCString(kResultBucketId, extension);
3003 helper_->RequestExtensionCHROMIUM(kResultBucketId);
3004 helper_->SetBucketSize(kResultBucketId, 0);
3006 struct ExtensionCheck {
3007 const char* extension;
3008 ExtensionStatus* status;
3010 const ExtensionCheck checks[] = {
3012 "GL_ANGLE_pack_reverse_row_order",
3013 &angle_pack_reverse_row_order_status_,
3016 "GL_CHROMIUM_framebuffer_multisample",
3017 &chromium_framebuffer_multisample_,
3020 const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
3021 for (size_t ii = 0; ii < kNumChecks; ++ii) {
3022 const ExtensionCheck& check = checks[ii];
3023 if (*check.status == kUnavailableExtensionStatus &&
3024 !strcmp(extension, check.extension)) {
3025 *check.status = kUnknownExtensionStatus;
3030 void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
3031 GPU_CLIENT_SINGLE_THREAD_CHECK();
3032 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
3033 // Wait if this would add too many rate limit tokens.
3034 if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
3035 helper_->WaitForToken(rate_limit_tokens_.front());
3036 rate_limit_tokens_.pop();
3038 rate_limit_tokens_.push(helper_->InsertToken());
3041 void GLES2Implementation::GetMultipleIntegervCHROMIUM(
3042 const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size) {
3043 GPU_CLIENT_SINGLE_THREAD_CHECK();
3044 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMultipleIntegervCHROMIUM("
3045 << static_cast<const void*>(pnames) << ", "
3046 << count << ", " << results << ", "
3048 GPU_CLIENT_LOG_CODE_BLOCK({
3049 for (GLuint i = 0; i < count; ++i) {
3051 " " << i << ": " << GLES2Util::GetStringGLState(pnames[i]));
3055 GetMultipleIntegervState state(pnames, count, results, size);
3056 if (!GetMultipleIntegervSetup(&state)) {
3059 state.buffer = transfer_buffer_->Alloc(state.transfer_buffer_size_needed);
3060 if (!state.buffer) {
3061 SetGLError(GL_OUT_OF_MEMORY, "glGetMultipleIntegervCHROMIUM",
3062 "Transfer buffer allocation failed.");
3065 GetMultipleIntegervRequest(&state);
3067 GetMultipleIntegervOnCompleted(&state);
3069 GPU_CLIENT_LOG(" returned");
3070 GPU_CLIENT_LOG_CODE_BLOCK({
3071 for (int i = 0; i < state.num_results; ++i) {
3072 GPU_CLIENT_LOG(" " << i << ": " << (results[i]));
3076 // TODO(gman): We should be able to free without a token.
3077 transfer_buffer_->FreePendingToken(state.buffer, helper_->InsertToken());
3081 bool GLES2Implementation::GetMultipleIntegervSetup(
3082 GetMultipleIntegervState* state) {
3083 state->num_results = 0;
3084 for (GLuint ii = 0; ii < state->pnames_count; ++ii) {
3085 int num = util_.GLGetNumValuesReturned(state->pnames[ii]);
3087 SetGLErrorInvalidEnum(
3088 "glGetMultipleIntegervCHROMIUM", state->pnames[ii], "pname");
3091 state->num_results += num;
3093 if (static_cast<size_t>(state->results_size) !=
3094 state->num_results * sizeof(GLint)) {
3095 SetGLError(GL_INVALID_VALUE, "glGetMultipleIntegervCHROMIUM", "bad size");
3098 for (int ii = 0; ii < state->num_results; ++ii) {
3099 if (state->results[ii] != 0) {
3100 SetGLError(GL_INVALID_VALUE,
3101 "glGetMultipleIntegervCHROMIUM", "results not set to zero.");
3105 state->transfer_buffer_size_needed =
3106 state->pnames_count * sizeof(state->pnames[0]) +
3107 state->num_results * sizeof(state->results[0]);
3111 void GLES2Implementation::GetMultipleIntegervRequest(
3112 GetMultipleIntegervState* state) {
3113 GLenum* pnames_buffer = static_cast<GLenum*>(state->buffer);
3114 state->results_buffer = pnames_buffer + state->pnames_count;
3115 memcpy(pnames_buffer, state->pnames, state->pnames_count * sizeof(GLenum));
3116 memset(state->results_buffer, 0, state->num_results * sizeof(GLint));
3117 helper_->GetMultipleIntegervCHROMIUM(
3118 transfer_buffer_->GetShmId(),
3119 transfer_buffer_->GetOffset(pnames_buffer),
3120 state->pnames_count,
3121 transfer_buffer_->GetShmId(),
3122 transfer_buffer_->GetOffset(state->results_buffer),
3123 state->results_size);
3126 void GLES2Implementation::GetMultipleIntegervOnCompleted(
3127 GetMultipleIntegervState* state) {
3128 memcpy(state->results, state->results_buffer, state->results_size);;
3131 void GLES2Implementation::GetAllShaderPrecisionFormatsSetup(
3132 GetAllShaderPrecisionFormatsState* state) {
3133 state->transfer_buffer_size_needed =
3134 state->precision_params_count *
3135 sizeof(cmds::GetShaderPrecisionFormat::Result);
3138 void GLES2Implementation::GetAllShaderPrecisionFormatsRequest(
3139 GetAllShaderPrecisionFormatsState* state) {
3140 typedef cmds::GetShaderPrecisionFormat::Result Result;
3141 Result* result = static_cast<Result*>(state->results_buffer);
3143 for (int i = 0; i < state->precision_params_count; i++) {
3144 result->success = false;
3145 helper_->GetShaderPrecisionFormat(state->precision_params[i][0],
3146 state->precision_params[i][1],
3147 transfer_buffer_->GetShmId(),
3148 transfer_buffer_->GetOffset(result));
3153 void GLES2Implementation::GetAllShaderPrecisionFormatsOnCompleted(
3154 GetAllShaderPrecisionFormatsState* state) {
3155 typedef cmds::GetShaderPrecisionFormat::Result Result;
3156 Result* result = static_cast<Result*>(state->results_buffer);
3158 for (int i = 0; i < state->precision_params_count; i++) {
3159 if (result->success) {
3160 const GLStaticState::ShaderPrecisionKey key(
3161 state->precision_params[i][0], state->precision_params[i][1]);
3162 static_state_.shader_precisions[key] = *result;
3168 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
3169 GLuint program, std::vector<int8>* result) {
3171 // Clear the bucket so if the command fails nothing will be in it.
3172 helper_->SetBucketSize(kResultBucketId, 0);
3173 helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
3174 GetBucketContents(kResultBucketId, result);
3177 void GLES2Implementation::GetProgramInfoCHROMIUM(
3178 GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
3179 GPU_CLIENT_SINGLE_THREAD_CHECK();
3182 GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
3186 SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
3189 // Make sure they've set size to 0 else the value will be undefined on
3192 std::vector<int8> result;
3193 GetProgramInfoCHROMIUMHelper(program, &result);
3194 if (result.empty()) {
3197 *size = result.size();
3201 if (static_cast<size_t>(bufsize) < result.size()) {
3202 SetGLError(GL_INVALID_OPERATION,
3203 "glProgramInfoCHROMIUM", "bufsize is too small for result.");
3206 memcpy(info, &result[0], result.size());
3209 GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
3210 GPU_CLIENT_SINGLE_THREAD_CHECK();
3211 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
3213 TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
3214 helper_->CommandBufferHelper::Flush();
3215 return gpu_control_->CreateStreamTexture(texture);
3218 void GLES2Implementation::PostSubBufferCHROMIUM(
3219 GLint x, GLint y, GLint width, GLint height) {
3220 GPU_CLIENT_SINGLE_THREAD_CHECK();
3221 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
3222 << x << ", " << y << ", " << width << ", " << height << ")");
3223 TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
3224 "width", width, "height", height);
3226 // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
3227 swap_buffers_tokens_.push(helper_->InsertToken());
3228 helper_->PostSubBufferCHROMIUM(x, y, width, height);
3229 helper_->CommandBufferHelper::Flush();
3230 if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
3231 helper_->WaitForToken(swap_buffers_tokens_.front());
3232 swap_buffers_tokens_.pop();
3236 void GLES2Implementation::DeleteQueriesEXTHelper(
3237 GLsizei n, const GLuint* queries) {
3238 // TODO(gman): Remove this as queries are not shared resources.
3239 if (!GetIdHandler(id_namespaces::kQueries)->FreeIds(
3240 this, n, queries, &GLES2Implementation::DeleteQueriesStub)) {
3243 "glDeleteTextures", "id not created by this context.");
3247 for (GLsizei ii = 0; ii < n; ++ii)
3248 query_tracker_->RemoveQuery(queries[ii]);
3250 helper_->DeleteQueriesEXTImmediate(n, queries);
3253 // TODO(gman): Remove this. Queries are not shared resources.
3254 void GLES2Implementation::DeleteQueriesStub(
3255 GLsizei /* n */, const GLuint* /* queries */) {
3258 GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
3259 GPU_CLIENT_SINGLE_THREAD_CHECK();
3260 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
3262 // TODO(gman): To be spec compliant IDs from other contexts sharing
3263 // resources need to return true here even though you can't share
3264 // queries across contexts?
3265 return query_tracker_->GetQuery(id) != NULL;
3268 void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
3269 GPU_CLIENT_SINGLE_THREAD_CHECK();
3270 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
3271 << GLES2Util::GetStringQueryTarget(target)
3272 << ", " << id << ")");
3274 // if any outstanding queries INV_OP
3275 QueryMap::iterator it = current_queries_.find(target);
3276 if (it != current_queries_.end()) {
3278 GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
3284 SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
3288 // TODO(gman) if id not GENned INV_OPERATION
3290 // if id does not have an object
3291 QueryTracker::Query* query = query_tracker_->GetQuery(id);
3293 query = query_tracker_->CreateQuery(id, target);
3295 MustBeContextLost();
3298 } else if (query->target() != target) {
3300 GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
3304 current_queries_[target] = query;
3310 void GLES2Implementation::EndQueryEXT(GLenum target) {
3311 GPU_CLIENT_SINGLE_THREAD_CHECK();
3312 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
3313 << GLES2Util::GetStringQueryTarget(target) << ")");
3314 // Don't do anything if the context is lost.
3315 if (helper_->IsContextLost()) {
3319 QueryMap::iterator it = current_queries_.find(target);
3320 if (it == current_queries_.end()) {
3321 SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
3325 QueryTracker::Query* query = it->second;
3327 current_queries_.erase(it);
3331 void GLES2Implementation::GetQueryivEXT(
3332 GLenum target, GLenum pname, GLint* params) {
3333 GPU_CLIENT_SINGLE_THREAD_CHECK();
3334 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
3335 << GLES2Util::GetStringQueryTarget(target) << ", "
3336 << GLES2Util::GetStringQueryParameter(pname) << ", "
3337 << static_cast<const void*>(params) << ")");
3339 if (pname != GL_CURRENT_QUERY_EXT) {
3340 SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
3343 QueryMap::iterator it = current_queries_.find(target);
3344 if (it != current_queries_.end()) {
3345 QueryTracker::Query* query = it->second;
3346 *params = query->id();
3350 GPU_CLIENT_LOG(" " << *params);
3354 void GLES2Implementation::GetQueryObjectuivEXT(
3355 GLuint id, GLenum pname, GLuint* params) {
3356 GPU_CLIENT_SINGLE_THREAD_CHECK();
3357 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
3358 << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
3359 << static_cast<const void*>(params) << ")");
3361 QueryTracker::Query* query = query_tracker_->GetQuery(id);
3363 SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
3367 QueryMap::iterator it = current_queries_.find(query->target());
3368 if (it != current_queries_.end()) {
3370 GL_INVALID_OPERATION,
3371 "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
3375 if (query->NeverUsed()) {
3377 GL_INVALID_OPERATION,
3378 "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
3383 case GL_QUERY_RESULT_EXT:
3384 if (!query->CheckResultsAvailable(helper_)) {
3385 helper_->WaitForToken(query->token());
3386 if (!query->CheckResultsAvailable(helper_)) {
3387 // TODO(gman): Speed this up.
3389 CHECK(query->CheckResultsAvailable(helper_));
3392 *params = query->GetResult();
3394 case GL_QUERY_RESULT_AVAILABLE_EXT:
3395 *params = query->CheckResultsAvailable(helper_);
3398 SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
3401 GPU_CLIENT_LOG(" " << *params);
3405 void GLES2Implementation::DrawArraysInstancedANGLE(
3406 GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
3407 GPU_CLIENT_SINGLE_THREAD_CHECK();
3408 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
3409 << GLES2Util::GetStringDrawMode(mode) << ", "
3410 << first << ", " << count << ", " << primcount << ")");
3412 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
3415 if (primcount < 0) {
3416 SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
3419 if (primcount == 0) {
3422 bool simulated = false;
3423 if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
3424 "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
3428 helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
3429 RestoreArrayBuffer(simulated);
3433 void GLES2Implementation::DrawElementsInstancedANGLE(
3434 GLenum mode, GLsizei count, GLenum type, const void* indices,
3435 GLsizei primcount) {
3436 GPU_CLIENT_SINGLE_THREAD_CHECK();
3437 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
3438 << GLES2Util::GetStringDrawMode(mode) << ", "
3440 << GLES2Util::GetStringIndexType(type) << ", "
3441 << static_cast<const void*>(indices) << ", "
3442 << primcount << ")");
3444 SetGLError(GL_INVALID_VALUE,
3445 "glDrawElementsInstancedANGLE", "count less than 0.");
3451 if (primcount < 0) {
3452 SetGLError(GL_INVALID_VALUE,
3453 "glDrawElementsInstancedANGLE", "primcount < 0");
3456 if (primcount == 0) {
3460 bool simulated = false;
3461 if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
3462 "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
3463 indices, &offset, &simulated)) {
3466 helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
3467 RestoreElementAndArrayBuffers(simulated);
3471 void GLES2Implementation::GenMailboxCHROMIUM(
3473 GPU_CLIENT_SINGLE_THREAD_CHECK();
3474 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
3475 << static_cast<const void*>(mailbox) << ")");
3476 TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
3478 gpu::Mailbox result = gpu::Mailbox::Generate();
3479 memcpy(mailbox, result.name, sizeof(result.name));
3482 void GLES2Implementation::ProduceTextureCHROMIUM(GLenum target,
3483 const GLbyte* data) {
3484 GPU_CLIENT_SINGLE_THREAD_CHECK();
3485 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM("
3486 << static_cast<const void*>(data) << ")");
3487 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
3488 DCHECK(mailbox.Verify()) << "ProduceTextureCHROMIUM was passed a "
3489 "mailbox that was not generated by "
3490 "GenMailboxCHROMIUM.";
3491 helper_->ProduceTextureCHROMIUMImmediate(target, data);
3495 void GLES2Implementation::ConsumeTextureCHROMIUM(GLenum target,
3496 const GLbyte* data) {
3497 GPU_CLIENT_SINGLE_THREAD_CHECK();
3498 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM("
3499 << static_cast<const void*>(data) << ")");
3500 const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
3501 DCHECK(mailbox.Verify()) << "ConsumeTextureCHROMIUM was passed a "
3502 "mailbox that was not generated by "
3503 "GenMailboxCHROMIUM.";
3504 helper_->ConsumeTextureCHROMIUMImmediate(target, data);
3508 void GLES2Implementation::PushGroupMarkerEXT(
3509 GLsizei length, const GLchar* marker) {
3510 GPU_CLIENT_SINGLE_THREAD_CHECK();
3511 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
3512 << length << ", " << marker << ")");
3518 (length ? std::string(marker, length) : std::string(marker)));
3519 helper_->PushGroupMarkerEXT(kResultBucketId);
3520 helper_->SetBucketSize(kResultBucketId, 0);
3521 debug_marker_manager_.PushGroup(
3522 length ? std::string(marker, length) : std::string(marker));
3525 void GLES2Implementation::InsertEventMarkerEXT(
3526 GLsizei length, const GLchar* marker) {
3527 GPU_CLIENT_SINGLE_THREAD_CHECK();
3528 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
3529 << length << ", " << marker << ")");
3535 (length ? std::string(marker, length) : std::string(marker)));
3536 helper_->InsertEventMarkerEXT(kResultBucketId);
3537 helper_->SetBucketSize(kResultBucketId, 0);
3538 debug_marker_manager_.SetMarker(
3539 length ? std::string(marker, length) : std::string(marker));
3542 void GLES2Implementation::PopGroupMarkerEXT() {
3543 GPU_CLIENT_SINGLE_THREAD_CHECK();
3544 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
3545 helper_->PopGroupMarkerEXT();
3546 debug_marker_manager_.PopGroup();
3549 void GLES2Implementation::TraceBeginCHROMIUM(const char* name) {
3550 GPU_CLIENT_SINGLE_THREAD_CHECK();
3551 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
3553 if (current_trace_name_.get()) {
3554 SetGLError(GL_INVALID_OPERATION, "glTraceBeginCHROMIUM",
3555 "trace already running");
3558 TRACE_EVENT_COPY_ASYNC_BEGIN0("gpu", name, this);
3559 SetBucketAsCString(kResultBucketId, name);
3560 helper_->TraceBeginCHROMIUM(kResultBucketId);
3561 helper_->SetBucketSize(kResultBucketId, 0);
3562 current_trace_name_.reset(new std::string(name));
3565 void GLES2Implementation::TraceEndCHROMIUM() {
3566 GPU_CLIENT_SINGLE_THREAD_CHECK();
3567 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
3568 if (!current_trace_name_.get()) {
3569 SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
3570 "missing begin trace");
3573 helper_->TraceEndCHROMIUM();
3574 TRACE_EVENT_COPY_ASYNC_END0("gpu", current_trace_name_->c_str(), this);
3575 current_trace_name_.reset();
3578 void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
3579 GPU_CLIENT_SINGLE_THREAD_CHECK();
3580 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
3581 << target << ", " << GLES2Util::GetStringEnum(access) << ")");
3583 case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
3584 if (access != GL_READ_ONLY) {
3585 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3589 case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
3590 if (access != GL_WRITE_ONLY) {
3591 SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
3597 GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
3601 GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
3605 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3607 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
3610 if (buffer->mapped()) {
3611 SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
3614 // Here we wait for previous transfer operations to be finished.
3615 // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
3616 // with this method of synchronization. Until this is fixed,
3617 // MapBufferCHROMIUM will not block even if the transfer is not ready
3619 if (buffer->transfer_ready_token()) {
3620 helper_->WaitForToken(buffer->transfer_ready_token());
3621 buffer->set_transfer_ready_token(0);
3623 buffer->set_mapped(true);
3625 GPU_CLIENT_LOG(" returned " << buffer->address());
3627 return buffer->address();
3630 GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
3631 GPU_CLIENT_SINGLE_THREAD_CHECK();
3633 "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
3635 if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
3636 SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
3641 BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
3643 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
3646 if (!buffer->mapped()) {
3647 SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
3650 buffer->set_mapped(false);
3655 void GLES2Implementation::AsyncTexImage2DCHROMIUM(
3656 GLenum target, GLint level, GLint internalformat, GLsizei width,
3657 GLsizei height, GLint border, GLenum format, GLenum type,
3658 const void* pixels) {
3659 GPU_CLIENT_SINGLE_THREAD_CHECK();
3660 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
3661 << GLES2Util::GetStringTextureTarget(target) << ", "
3663 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
3664 << width << ", " << height << ", " << border << ", "
3665 << GLES2Util::GetStringTextureFormat(format) << ", "
3666 << GLES2Util::GetStringPixelType(type) << ", "
3667 << static_cast<const void*>(pixels) << ")");
3668 if (level < 0 || height < 0 || width < 0) {
3669 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
3673 uint32 unpadded_row_size;
3674 uint32 padded_row_size;
3675 if (!GLES2Util::ComputeImageDataSizes(
3676 width, height, format, type, unpack_alignment_, &size,
3677 &unpadded_row_size, &padded_row_size)) {
3678 SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
3682 // If there's no data/buffer just issue the AsyncTexImage2D
3683 if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
3684 helper_->AsyncTexImage2DCHROMIUM(
3685 target, level, internalformat, width, height, border, format, type,
3690 // Otherwise, async uploads require a transfer buffer to be bound.
3691 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3692 // the buffer before the transfer is finished. (Currently such
3693 // synchronization has to be handled manually.)
3694 GLuint offset = ToGLuint(pixels);
3695 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3696 bound_pixel_unpack_transfer_buffer_id_,
3697 "glAsyncTexImage2DCHROMIUM", offset, size);
3698 if (buffer && buffer->shm_id() != -1) {
3699 helper_->AsyncTexImage2DCHROMIUM(
3700 target, level, internalformat, width, height, border, format, type,
3701 buffer->shm_id(), buffer->shm_offset() + offset);
3705 void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
3706 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
3707 GLsizei height, GLenum format, GLenum type, const void* pixels) {
3708 GPU_CLIENT_SINGLE_THREAD_CHECK();
3709 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
3710 << GLES2Util::GetStringTextureTarget(target) << ", "
3712 << xoffset << ", " << yoffset << ", "
3713 << width << ", " << height << ", "
3714 << GLES2Util::GetStringTextureFormat(format) << ", "
3715 << GLES2Util::GetStringPixelType(type) << ", "
3716 << static_cast<const void*>(pixels) << ")");
3717 if (level < 0 || height < 0 || width < 0) {
3719 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
3724 uint32 unpadded_row_size;
3725 uint32 padded_row_size;
3726 if (!GLES2Util::ComputeImageDataSizes(
3727 width, height, format, type, unpack_alignment_, &size,
3728 &unpadded_row_size, &padded_row_size)) {
3730 GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
3734 // Async uploads require a transfer buffer to be bound.
3735 // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
3736 // the buffer before the transfer is finished. (Currently such
3737 // synchronization has to be handled manually.)
3738 GLuint offset = ToGLuint(pixels);
3739 BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
3740 bound_pixel_unpack_transfer_buffer_id_,
3741 "glAsyncTexSubImage2DCHROMIUM", offset, size);
3742 if (buffer && buffer->shm_id() != -1) {
3743 helper_->AsyncTexSubImage2DCHROMIUM(
3744 target, level, xoffset, yoffset, width, height, format, type,
3745 buffer->shm_id(), buffer->shm_offset() + offset);
3749 void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
3750 GPU_CLIENT_SINGLE_THREAD_CHECK();
3751 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
3752 << GLES2Util::GetStringTextureTarget(target) << ")");
3753 helper_->WaitAsyncTexImage2DCHROMIUM(target);
3757 GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
3758 GPU_CLIENT_SINGLE_THREAD_CHECK();
3759 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
3760 helper_->CommandBufferHelper::Flush();
3761 return gpu_control_->InsertSyncPoint();
3764 GLuint GLES2Implementation::CreateImageCHROMIUMHelper(
3765 GLsizei width, GLsizei height, GLenum internalformat) {
3767 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
3772 SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
3775 // Flush the command stream to ensure ordering in case the newly
3776 // returned image_id has recently been in use with a different buffer.
3777 helper_->CommandBufferHelper::Flush();
3779 // Create new buffer.
3780 GLuint buffer_id = gpu_memory_buffer_tracker_->CreateBuffer(
3781 width, height, internalformat);
3782 if (buffer_id == 0) {
3783 SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "out of GPU memory.");
3789 GLuint GLES2Implementation::CreateImageCHROMIUM(
3790 GLsizei width, GLsizei height, GLenum internalformat) {
3791 GPU_CLIENT_SINGLE_THREAD_CHECK();
3792 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM("
3795 << GLES2Util::GetStringTextureInternalFormat(internalformat) << ")");
3796 GLuint image_id = CreateImageCHROMIUMHelper(width, height, internalformat);
3801 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
3802 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3805 SetGLError(GL_INVALID_OPERATION, "glDestroyImageCHROMIUM", "invalid image");
3809 // Flush the command stream to make sure all pending commands
3810 // that may refer to the image_id are executed on the service side.
3811 helper_->CommandBufferHelper::Flush();
3812 gpu_memory_buffer_tracker_->RemoveBuffer(image_id);
3815 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
3816 GPU_CLIENT_SINGLE_THREAD_CHECK();
3817 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
3818 << image_id << ")");
3819 DestroyImageCHROMIUMHelper(image_id);
3823 void GLES2Implementation::UnmapImageCHROMIUMHelper(GLuint image_id) {
3824 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3827 SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "invalid image");
3831 if (!gpu_buffer->IsMapped()) {
3832 SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "not mapped");
3835 gpu_buffer->Unmap();
3838 void GLES2Implementation::UnmapImageCHROMIUM(GLuint image_id) {
3839 GPU_CLIENT_SINGLE_THREAD_CHECK();
3840 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapImageCHROMIUM("
3841 << image_id << ")");
3843 UnmapImageCHROMIUMHelper(image_id);
3847 void* GLES2Implementation::MapImageCHROMIUMHelper(GLuint image_id,
3849 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3852 SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "invalid image");
3855 gfx::GpuMemoryBuffer::AccessMode mode;
3858 mode = gfx::GpuMemoryBuffer::WRITE_ONLY;
3861 mode = gfx::GpuMemoryBuffer::READ_ONLY;
3864 mode = gfx::GpuMemoryBuffer::READ_WRITE;
3867 SetGLError(GL_INVALID_ENUM, "glMapImageCHROMIUM",
3868 "invalid GPU access mode");
3872 if (gpu_buffer->IsMapped()) {
3873 SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "already mapped");
3877 void* mapped_buffer = NULL;
3878 gpu_buffer->Map(mode, &mapped_buffer);
3879 return mapped_buffer;
3882 void* GLES2Implementation::MapImageCHROMIUM(
3883 GLuint image_id, GLenum access) {
3884 GPU_CLIENT_SINGLE_THREAD_CHECK();
3885 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapImageCHROMIUM("
3887 << GLES2Util::GetStringEnum(access) << ")");
3889 void* mapped = MapImageCHROMIUMHelper(image_id, access);
3894 void GLES2Implementation::GetImageParameterivCHROMIUMHelper(
3895 GLuint image_id, GLenum pname, GLint* params) {
3896 if (pname != GL_IMAGE_ROWBYTES_CHROMIUM) {
3897 SetGLError(GL_INVALID_ENUM, "glGetImageParameterivCHROMIUM",
3898 "invalid parameter");
3902 gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
3905 SetGLError(GL_INVALID_OPERATION, "glGetImageParameterivCHROMIUM",
3910 if (!gpu_buffer->IsMapped()) {
3912 GL_INVALID_OPERATION, "glGetImageParameterivCHROMIUM", "not mapped");
3916 *params = gpu_buffer->GetStride();
3919 void GLES2Implementation::GetImageParameterivCHROMIUM(
3920 GLuint image_id, GLenum pname, GLint* params) {
3921 GPU_CLIENT_SINGLE_THREAD_CHECK();
3922 GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
3923 GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glImageParameterivCHROMIUM("
3925 << GLES2Util::GetStringBufferParameter(pname) << ", "
3926 << static_cast<const void*>(params) << ")");
3927 GetImageParameterivCHROMIUMHelper(image_id, pname, params);
3931 // Include the auto-generated part of this file. We split this because it means
3932 // we can easily edit the non-auto generated parts right here in this file
3933 // instead of having to edit some template or the code generator.
3934 #include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
3936 } // namespace gles2