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