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