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 #include "gpu/command_buffer/service/texture_manager.h" 6 #include "base/bits.h" 7 #include "base/strings/stringprintf.h" 8 #include "gpu/command_buffer/common/gles2_cmd_utils.h" 9 #include "gpu/command_buffer/service/error_state.h" 10 #include "gpu/command_buffer/service/feature_info.h" 11 #include "gpu/command_buffer/service/framebuffer_manager.h" 12 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" 13 #include "gpu/command_buffer/service/mailbox_manager.h" 14 #include "gpu/command_buffer/service/memory_tracking.h" 15 #include "gpu/command_buffer/service/stream_texture_manager.h" 16 17 namespace gpu { 18 namespace gles2 { 19 20 static size_t GLTargetToFaceIndex(GLenum target) { 21 switch (target) { 22 case GL_TEXTURE_2D: 23 case GL_TEXTURE_EXTERNAL_OES: 24 case GL_TEXTURE_RECTANGLE_ARB: 25 return 0; 26 case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 27 return 0; 28 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 29 return 1; 30 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 31 return 2; 32 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 33 return 3; 34 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 35 return 4; 36 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 37 return 5; 38 default: 39 NOTREACHED(); 40 return 0; 41 } 42 } 43 44 static size_t FaceIndexToGLTarget(size_t index) { 45 switch (index) { 46 case 0: 47 return GL_TEXTURE_CUBE_MAP_POSITIVE_X; 48 case 1: 49 return GL_TEXTURE_CUBE_MAP_NEGATIVE_X; 50 case 2: 51 return GL_TEXTURE_CUBE_MAP_POSITIVE_Y; 52 case 3: 53 return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; 54 case 4: 55 return GL_TEXTURE_CUBE_MAP_POSITIVE_Z; 56 case 5: 57 return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; 58 default: 59 NOTREACHED(); 60 return 0; 61 } 62 } 63 64 TextureManager::DestructionObserver::DestructionObserver() {} 65 66 TextureManager::DestructionObserver::~DestructionObserver() {} 67 68 TextureManager::~TextureManager() { 69 FOR_EACH_OBSERVER(DestructionObserver, 70 destruction_observers_, 71 OnTextureManagerDestroying(this)); 72 73 DCHECK(textures_.empty()); 74 75 // If this triggers, that means something is keeping a reference to 76 // a Texture belonging to this. 77 CHECK_EQ(texture_count_, 0u); 78 79 DCHECK_EQ(0, num_unrenderable_textures_); 80 DCHECK_EQ(0, num_unsafe_textures_); 81 DCHECK_EQ(0, num_uncleared_mips_); 82 DCHECK_EQ(0, num_images_); 83 } 84 85 void TextureManager::Destroy(bool have_context) { 86 have_context_ = have_context; 87 textures_.clear(); 88 for (int ii = 0; ii < kNumDefaultTextures; ++ii) { 89 default_textures_[ii] = NULL; 90 } 91 92 if (have_context) { 93 glDeleteTextures(arraysize(black_texture_ids_), black_texture_ids_); 94 } 95 96 DCHECK_EQ(0u, memory_tracker_managed_->GetMemRepresented()); 97 DCHECK_EQ(0u, memory_tracker_unmanaged_->GetMemRepresented()); 98 } 99 100 Texture::Texture(GLuint service_id) 101 : mailbox_manager_(NULL), 102 memory_tracking_ref_(NULL), 103 service_id_(service_id), 104 cleared_(true), 105 num_uncleared_mips_(0), 106 target_(0), 107 min_filter_(GL_NEAREST_MIPMAP_LINEAR), 108 mag_filter_(GL_LINEAR), 109 wrap_s_(GL_REPEAT), 110 wrap_t_(GL_REPEAT), 111 usage_(GL_NONE), 112 pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM), 113 max_level_set_(-1), 114 texture_complete_(false), 115 cube_complete_(false), 116 npot_(false), 117 has_been_bound_(false), 118 framebuffer_attachment_count_(0), 119 stream_texture_(false), 120 immutable_(false), 121 has_images_(false), 122 estimated_size_(0), 123 can_render_condition_(CAN_RENDER_ALWAYS) { 124 } 125 126 Texture::~Texture() { 127 if (mailbox_manager_) 128 mailbox_manager_->TextureDeleted(this); 129 } 130 131 void Texture::AddTextureRef(TextureRef* ref) { 132 DCHECK(refs_.find(ref) == refs_.end()); 133 refs_.insert(ref); 134 if (!memory_tracking_ref_) { 135 memory_tracking_ref_ = ref; 136 GetMemTracker()->TrackMemAlloc(estimated_size()); 137 } 138 } 139 140 void Texture::RemoveTextureRef(TextureRef* ref, bool have_context) { 141 if (memory_tracking_ref_ == ref) { 142 GetMemTracker()->TrackMemFree(estimated_size()); 143 memory_tracking_ref_ = NULL; 144 } 145 size_t result = refs_.erase(ref); 146 DCHECK_EQ(result, 1u); 147 if (refs_.empty()) { 148 if (have_context) { 149 GLuint id = service_id(); 150 glDeleteTextures(1, &id); 151 } 152 delete this; 153 } else if (memory_tracking_ref_ == NULL) { 154 // TODO(piman): tune ownership semantics for cross-context group shared 155 // textures. 156 memory_tracking_ref_ = *refs_.begin(); 157 GetMemTracker()->TrackMemAlloc(estimated_size()); 158 } 159 } 160 161 MemoryTypeTracker* Texture::GetMemTracker() { 162 DCHECK(memory_tracking_ref_); 163 return memory_tracking_ref_->manager()->GetMemTracker(pool_); 164 } 165 166 Texture::LevelInfo::LevelInfo() 167 : cleared(true), 168 target(0), 169 level(-1), 170 internal_format(0), 171 width(0), 172 height(0), 173 depth(0), 174 border(0), 175 format(0), 176 type(0), 177 estimated_size(0) { 178 } 179 180 Texture::LevelInfo::LevelInfo(const LevelInfo& rhs) 181 : cleared(rhs.cleared), 182 target(rhs.target), 183 level(rhs.level), 184 internal_format(rhs.internal_format), 185 width(rhs.width), 186 height(rhs.height), 187 depth(rhs.depth), 188 border(rhs.border), 189 format(rhs.format), 190 type(rhs.type), 191 image(rhs.image), 192 estimated_size(rhs.estimated_size) { 193 } 194 195 Texture::LevelInfo::~LevelInfo() { 196 } 197 198 Texture::CanRenderCondition Texture::GetCanRenderCondition() const { 199 if (target_ == 0) 200 return CAN_RENDER_ALWAYS; 201 202 if (target_ == GL_TEXTURE_EXTERNAL_OES) { 203 if (!IsStreamTexture()) { 204 return CAN_RENDER_NEVER; 205 } 206 } else { 207 if (level_infos_.empty()) { 208 return CAN_RENDER_NEVER; 209 } 210 211 const Texture::LevelInfo& first_face = level_infos_[0][0]; 212 if (first_face.width == 0 || 213 first_face.height == 0 || 214 first_face.depth == 0) { 215 return CAN_RENDER_NEVER; 216 } 217 } 218 219 bool needs_mips = NeedsMips(); 220 if (needs_mips) { 221 if (!texture_complete()) 222 return CAN_RENDER_NEVER; 223 if (target_ == GL_TEXTURE_CUBE_MAP && !cube_complete()) 224 return CAN_RENDER_NEVER; 225 } 226 227 bool is_npot_compatible = !needs_mips && 228 wrap_s_ == GL_CLAMP_TO_EDGE && 229 wrap_t_ == GL_CLAMP_TO_EDGE; 230 231 if (!is_npot_compatible) { 232 if (target_ == GL_TEXTURE_RECTANGLE_ARB) 233 return CAN_RENDER_NEVER; 234 else if (npot()) 235 return CAN_RENDER_ONLY_IF_NPOT; 236 } 237 238 return CAN_RENDER_ALWAYS; 239 } 240 241 bool Texture::CanRender(const FeatureInfo* feature_info) const { 242 switch (can_render_condition_) { 243 case CAN_RENDER_ALWAYS: 244 return true; 245 case CAN_RENDER_NEVER: 246 return false; 247 case CAN_RENDER_ONLY_IF_NPOT: 248 break; 249 } 250 return feature_info->feature_flags().npot_ok; 251 } 252 253 void Texture::AddToSignature( 254 const FeatureInfo* feature_info, 255 GLenum target, 256 GLint level, 257 std::string* signature) const { 258 DCHECK(feature_info); 259 DCHECK(signature); 260 DCHECK_GE(level, 0); 261 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)), 262 level_infos_.size()); 263 DCHECK_LT(static_cast<size_t>(level), 264 level_infos_[GLTargetToFaceIndex(target)].size()); 265 const Texture::LevelInfo& info = 266 level_infos_[GLTargetToFaceIndex(target)][level]; 267 *signature += base::StringPrintf( 268 "|Texture|target=%04x|level=%d|internal_format=%04x" 269 "|width=%d|height=%d|depth=%d|border=%d|format=%04x|type=%04x" 270 "|image=%d|canrender=%d|canrenderto=%d|npot_=%d" 271 "|min_filter=%04x|mag_filter=%04x|wrap_s=%04x|wrap_t=%04x" 272 "|usage=%04x", 273 target, level, info.internal_format, 274 info.width, info.height, info.depth, info.border, 275 info.format, info.type, info.image.get() != NULL, 276 CanRender(feature_info), CanRenderTo(), npot_, 277 min_filter_, mag_filter_, wrap_s_, wrap_t_, 278 usage_); 279 } 280 281 void Texture::SetMailboxManager(MailboxManager* mailbox_manager) { 282 DCHECK(!mailbox_manager_ || mailbox_manager_ == mailbox_manager); 283 mailbox_manager_ = mailbox_manager; 284 } 285 286 bool Texture::MarkMipmapsGenerated( 287 const FeatureInfo* feature_info) { 288 if (!CanGenerateMipmaps(feature_info)) { 289 return false; 290 } 291 for (size_t ii = 0; ii < level_infos_.size(); ++ii) { 292 const Texture::LevelInfo& info1 = level_infos_[ii][0]; 293 GLsizei width = info1.width; 294 GLsizei height = info1.height; 295 GLsizei depth = info1.depth; 296 GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D : 297 FaceIndexToGLTarget(ii); 298 int num_mips = TextureManager::ComputeMipMapCount(width, height, depth); 299 for (int level = 1; level < num_mips; ++level) { 300 width = std::max(1, width >> 1); 301 height = std::max(1, height >> 1); 302 depth = std::max(1, depth >> 1); 303 SetLevelInfo(feature_info, 304 target, 305 level, 306 info1.internal_format, 307 width, 308 height, 309 depth, 310 info1.border, 311 info1.format, 312 info1.type, 313 true); 314 } 315 } 316 317 return true; 318 } 319 320 void Texture::SetTarget( 321 const FeatureInfo* feature_info, GLenum target, GLint max_levels) { 322 DCHECK_EQ(0u, target_); // you can only set this once. 323 target_ = target; 324 size_t num_faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; 325 level_infos_.resize(num_faces); 326 for (size_t ii = 0; ii < num_faces; ++ii) { 327 level_infos_[ii].resize(max_levels); 328 } 329 330 if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) { 331 min_filter_ = GL_LINEAR; 332 wrap_s_ = wrap_t_ = GL_CLAMP_TO_EDGE; 333 } 334 335 if (target == GL_TEXTURE_EXTERNAL_OES) { 336 immutable_ = true; 337 } 338 Update(feature_info); 339 UpdateCanRenderCondition(); 340 } 341 342 bool Texture::CanGenerateMipmaps( 343 const FeatureInfo* feature_info) const { 344 if ((npot() && !feature_info->feature_flags().npot_ok) || 345 level_infos_.empty() || 346 target_ == GL_TEXTURE_EXTERNAL_OES || 347 target_ == GL_TEXTURE_RECTANGLE_ARB) { 348 return false; 349 } 350 351 // Can't generate mips for depth or stencil textures. 352 const Texture::LevelInfo& first = level_infos_[0][0]; 353 uint32 channels = GLES2Util::GetChannelsForFormat(first.format); 354 if (channels & (GLES2Util::kDepth | GLES2Util::kStencil)) { 355 return false; 356 } 357 358 // TODO(gman): Check internal_format, format and type. 359 for (size_t ii = 0; ii < level_infos_.size(); ++ii) { 360 const LevelInfo& info = level_infos_[ii][0]; 361 if ((info.target == 0) || (info.width != first.width) || 362 (info.height != first.height) || (info.depth != 1) || 363 (info.format != first.format) || 364 (info.internal_format != first.internal_format) || 365 (info.type != first.type) || 366 feature_info->validators()->compressed_texture_format.IsValid( 367 info.internal_format) || 368 info.image.get()) { 369 return false; 370 } 371 } 372 return true; 373 } 374 375 void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) { 376 DCHECK_GE(level, 0); 377 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)), 378 level_infos_.size()); 379 DCHECK_LT(static_cast<size_t>(level), 380 level_infos_[GLTargetToFaceIndex(target)].size()); 381 Texture::LevelInfo& info = 382 level_infos_[GLTargetToFaceIndex(target)][level]; 383 UpdateMipCleared(&info, cleared); 384 UpdateCleared(); 385 } 386 387 void Texture::UpdateCleared() { 388 if (level_infos_.empty()) { 389 return; 390 } 391 392 const Texture::LevelInfo& first_face = level_infos_[0][0]; 393 int levels_needed = TextureManager::ComputeMipMapCount( 394 first_face.width, first_face.height, first_face.depth); 395 bool cleared = true; 396 for (size_t ii = 0; ii < level_infos_.size(); ++ii) { 397 for (GLint jj = 0; jj < levels_needed; ++jj) { 398 const Texture::LevelInfo& info = level_infos_[ii][jj]; 399 if (info.width > 0 && info.height > 0 && info.depth > 0 && 400 !info.cleared) { 401 cleared = false; 402 break; 403 } 404 } 405 } 406 UpdateSafeToRenderFrom(cleared); 407 } 408 409 void Texture::UpdateSafeToRenderFrom(bool cleared) { 410 if (cleared_ == cleared) 411 return; 412 cleared_ = cleared; 413 int delta = cleared ? -1 : +1; 414 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it) 415 (*it)->manager()->UpdateSafeToRenderFrom(delta); 416 } 417 418 void Texture::UpdateMipCleared(LevelInfo* info, bool cleared) { 419 if (info->cleared == cleared) 420 return; 421 info->cleared = cleared; 422 int delta = cleared ? -1 : +1; 423 num_uncleared_mips_ += delta; 424 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it) 425 (*it)->manager()->UpdateUnclearedMips(delta); 426 } 427 428 void Texture::UpdateCanRenderCondition() { 429 CanRenderCondition can_render_condition = GetCanRenderCondition(); 430 if (can_render_condition_ == can_render_condition) 431 return; 432 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it) 433 (*it)->manager()->UpdateCanRenderCondition(can_render_condition_, 434 can_render_condition); 435 can_render_condition_ = can_render_condition; 436 } 437 438 void Texture::UpdateHasImages() { 439 if (level_infos_.empty()) 440 return; 441 442 bool has_images = false; 443 for (size_t ii = 0; ii < level_infos_.size(); ++ii) { 444 for (size_t jj = 0; jj < level_infos_[ii].size(); ++jj) { 445 const Texture::LevelInfo& info = level_infos_[ii][jj]; 446 if (info.image.get() != NULL) { 447 has_images = true; 448 break; 449 } 450 } 451 } 452 453 if (has_images_ == has_images) 454 return; 455 has_images_ = has_images; 456 int delta = has_images ? +1 : -1; 457 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it) 458 (*it)->manager()->UpdateNumImages(delta); 459 } 460 461 void Texture::IncAllFramebufferStateChangeCount() { 462 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it) 463 (*it)->manager()->IncFramebufferStateChangeCount(); 464 } 465 466 void Texture::SetLevelInfo( 467 const FeatureInfo* feature_info, 468 GLenum target, 469 GLint level, 470 GLenum internal_format, 471 GLsizei width, 472 GLsizei height, 473 GLsizei depth, 474 GLint border, 475 GLenum format, 476 GLenum type, 477 bool cleared) { 478 DCHECK_GE(level, 0); 479 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)), 480 level_infos_.size()); 481 DCHECK_LT(static_cast<size_t>(level), 482 level_infos_[GLTargetToFaceIndex(target)].size()); 483 DCHECK_GE(width, 0); 484 DCHECK_GE(height, 0); 485 DCHECK_GE(depth, 0); 486 Texture::LevelInfo& info = 487 level_infos_[GLTargetToFaceIndex(target)][level]; 488 info.target = target; 489 info.level = level; 490 info.internal_format = internal_format; 491 info.width = width; 492 info.height = height; 493 info.depth = depth; 494 info.border = border; 495 info.format = format; 496 info.type = type; 497 info.image = 0; 498 499 estimated_size_ -= info.estimated_size; 500 GLES2Util::ComputeImageDataSizes( 501 width, height, format, type, 4, &info.estimated_size, NULL, NULL); 502 estimated_size_ += info.estimated_size; 503 504 UpdateMipCleared(&info, cleared); 505 max_level_set_ = std::max(max_level_set_, level); 506 Update(feature_info); 507 UpdateCleared(); 508 UpdateCanRenderCondition(); 509 UpdateHasImages(); 510 if (IsAttachedToFramebuffer()) { 511 // TODO(gman): If textures tracked which framebuffers they were attached to 512 // we could just mark those framebuffers as not complete. 513 IncAllFramebufferStateChangeCount(); 514 } 515 } 516 517 bool Texture::ValidForTexture( 518 GLint target, 519 GLint level, 520 GLint xoffset, 521 GLint yoffset, 522 GLsizei width, 523 GLsizei height, 524 GLenum format, 525 GLenum type) const { 526 size_t face_index = GLTargetToFaceIndex(target); 527 if (level >= 0 && face_index < level_infos_.size() && 528 static_cast<size_t>(level) < level_infos_[face_index].size()) { 529 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level]; 530 int32 right; 531 int32 top; 532 return SafeAddInt32(xoffset, width, &right) && 533 SafeAddInt32(yoffset, height, &top) && 534 xoffset >= 0 && 535 yoffset >= 0 && 536 right <= info.width && 537 top <= info.height && 538 format == info.internal_format && 539 type == info.type; 540 } 541 return false; 542 } 543 544 bool Texture::GetLevelSize( 545 GLint target, GLint level, GLsizei* width, GLsizei* height) const { 546 DCHECK(width); 547 DCHECK(height); 548 size_t face_index = GLTargetToFaceIndex(target); 549 if (level >= 0 && face_index < level_infos_.size() && 550 static_cast<size_t>(level) < level_infos_[face_index].size()) { 551 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level]; 552 if (info.target != 0) { 553 *width = info.width; 554 *height = info.height; 555 return true; 556 } 557 } 558 return false; 559 } 560 561 bool Texture::GetLevelType( 562 GLint target, GLint level, GLenum* type, GLenum* internal_format) const { 563 DCHECK(type); 564 DCHECK(internal_format); 565 size_t face_index = GLTargetToFaceIndex(target); 566 if (level >= 0 && face_index < level_infos_.size() && 567 static_cast<size_t>(level) < level_infos_[face_index].size()) { 568 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level]; 569 if (info.target != 0) { 570 *type = info.type; 571 *internal_format = info.internal_format; 572 return true; 573 } 574 } 575 return false; 576 } 577 578 GLenum Texture::SetParameter( 579 const FeatureInfo* feature_info, GLenum pname, GLint param) { 580 DCHECK(feature_info); 581 582 if (target_ == GL_TEXTURE_EXTERNAL_OES || 583 target_ == GL_TEXTURE_RECTANGLE_ARB) { 584 if (pname == GL_TEXTURE_MIN_FILTER && 585 (param != GL_NEAREST && param != GL_LINEAR)) 586 return GL_INVALID_ENUM; 587 if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) && 588 param != GL_CLAMP_TO_EDGE) 589 return GL_INVALID_ENUM; 590 } 591 592 switch (pname) { 593 case GL_TEXTURE_MIN_FILTER: 594 if (!feature_info->validators()->texture_min_filter_mode.IsValid(param)) { 595 return GL_INVALID_ENUM; 596 } 597 min_filter_ = param; 598 break; 599 case GL_TEXTURE_MAG_FILTER: 600 if (!feature_info->validators()->texture_mag_filter_mode.IsValid(param)) { 601 return GL_INVALID_ENUM; 602 } 603 mag_filter_ = param; 604 break; 605 case GL_TEXTURE_POOL_CHROMIUM: 606 if (!feature_info->validators()->texture_pool.IsValid(param)) { 607 return GL_INVALID_ENUM; 608 } 609 GetMemTracker()->TrackMemFree(estimated_size()); 610 pool_ = param; 611 GetMemTracker()->TrackMemAlloc(estimated_size()); 612 break; 613 case GL_TEXTURE_WRAP_S: 614 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) { 615 return GL_INVALID_ENUM; 616 } 617 wrap_s_ = param; 618 break; 619 case GL_TEXTURE_WRAP_T: 620 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) { 621 return GL_INVALID_ENUM; 622 } 623 wrap_t_ = param; 624 break; 625 case GL_TEXTURE_MAX_ANISOTROPY_EXT: 626 if (param < 1) { 627 return GL_INVALID_VALUE; 628 } 629 break; 630 case GL_TEXTURE_USAGE_ANGLE: 631 if (!feature_info->validators()->texture_usage.IsValid(param)) { 632 return GL_INVALID_ENUM; 633 } 634 usage_ = param; 635 break; 636 default: 637 NOTREACHED(); 638 return GL_INVALID_ENUM; 639 } 640 Update(feature_info); 641 UpdateCleared(); 642 UpdateCanRenderCondition(); 643 return GL_NO_ERROR; 644 } 645 646 void Texture::Update(const FeatureInfo* feature_info) { 647 // Update npot status. 648 // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others 649 npot_ = target_ == GL_TEXTURE_EXTERNAL_OES; 650 651 if (level_infos_.empty()) { 652 texture_complete_ = false; 653 cube_complete_ = false; 654 return; 655 } 656 657 // checks that the first mip of any face is npot. 658 for (size_t ii = 0; ii < level_infos_.size(); ++ii) { 659 const Texture::LevelInfo& info = level_infos_[ii][0]; 660 if (GLES2Util::IsNPOT(info.width) || 661 GLES2Util::IsNPOT(info.height) || 662 GLES2Util::IsNPOT(info.depth)) { 663 npot_ = true; 664 break; 665 } 666 } 667 668 // Update texture_complete and cube_complete status. 669 const Texture::LevelInfo& first_face = level_infos_[0][0]; 670 int levels_needed = TextureManager::ComputeMipMapCount( 671 first_face.width, first_face.height, first_face.depth); 672 texture_complete_ = 673 max_level_set_ >= (levels_needed - 1) && max_level_set_ >= 0; 674 cube_complete_ = (level_infos_.size() == 6) && 675 (first_face.width == first_face.height); 676 677 if (first_face.width == 0 || first_face.height == 0) { 678 texture_complete_ = false; 679 } 680 if (first_face.type == GL_FLOAT && 681 !feature_info->feature_flags().enable_texture_float_linear && 682 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST || 683 mag_filter_ != GL_NEAREST)) { 684 texture_complete_ = false; 685 } else if (first_face.type == GL_HALF_FLOAT_OES && 686 !feature_info->feature_flags().enable_texture_half_float_linear && 687 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST || 688 mag_filter_ != GL_NEAREST)) { 689 texture_complete_ = false; 690 } 691 for (size_t ii = 0; 692 ii < level_infos_.size() && (cube_complete_ || texture_complete_); 693 ++ii) { 694 const Texture::LevelInfo& level0 = level_infos_[ii][0]; 695 if (level0.target == 0 || 696 level0.width != first_face.width || 697 level0.height != first_face.height || 698 level0.depth != 1 || 699 level0.internal_format != first_face.internal_format || 700 level0.format != first_face.format || 701 level0.type != first_face.type) { 702 cube_complete_ = false; 703 } 704 // Get level0 dimensions 705 GLsizei width = level0.width; 706 GLsizei height = level0.height; 707 GLsizei depth = level0.depth; 708 for (GLint jj = 1; jj < levels_needed; ++jj) { 709 // compute required size for mip. 710 width = std::max(1, width >> 1); 711 height = std::max(1, height >> 1); 712 depth = std::max(1, depth >> 1); 713 const Texture::LevelInfo& info = level_infos_[ii][jj]; 714 if (info.target == 0 || 715 info.width != width || 716 info.height != height || 717 info.depth != depth || 718 info.internal_format != level0.internal_format || 719 info.format != level0.format || 720 info.type != level0.type) { 721 texture_complete_ = false; 722 break; 723 } 724 } 725 } 726 } 727 728 bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) { 729 DCHECK(decoder); 730 if (cleared_) { 731 return true; 732 } 733 734 const Texture::LevelInfo& first_face = level_infos_[0][0]; 735 int levels_needed = TextureManager::ComputeMipMapCount( 736 first_face.width, first_face.height, first_face.depth); 737 738 for (size_t ii = 0; ii < level_infos_.size(); ++ii) { 739 for (GLint jj = 0; jj < levels_needed; ++jj) { 740 Texture::LevelInfo& info = level_infos_[ii][jj]; 741 if (info.target != 0) { 742 if (!ClearLevel(decoder, info.target, jj)) { 743 return false; 744 } 745 } 746 } 747 } 748 UpdateSafeToRenderFrom(true); 749 return true; 750 } 751 752 bool Texture::IsLevelCleared(GLenum target, GLint level) const { 753 size_t face_index = GLTargetToFaceIndex(target); 754 if (face_index >= level_infos_.size() || 755 level >= static_cast<GLint>(level_infos_[face_index].size())) { 756 return true; 757 } 758 759 const Texture::LevelInfo& info = level_infos_[face_index][level]; 760 761 return info.cleared; 762 } 763 764 bool Texture::ClearLevel( 765 GLES2Decoder* decoder, GLenum target, GLint level) { 766 DCHECK(decoder); 767 size_t face_index = GLTargetToFaceIndex(target); 768 if (face_index >= level_infos_.size() || 769 level >= static_cast<GLint>(level_infos_[face_index].size())) { 770 return true; 771 } 772 773 Texture::LevelInfo& info = level_infos_[face_index][level]; 774 775 DCHECK(target == info.target); 776 777 if (info.target == 0 || 778 info.cleared || 779 info.width == 0 || 780 info.height == 0 || 781 info.depth == 0) { 782 return true; 783 } 784 785 // NOTE: It seems kind of gross to call back into the decoder for this 786 // but only the decoder knows all the state (like unpack_alignment_) that's 787 // needed to be able to call GL correctly. 788 bool cleared = decoder->ClearLevel( 789 service_id_, target_, info.target, info.level, info.format, info.type, 790 info.width, info.height, immutable_); 791 UpdateMipCleared(&info, cleared); 792 return info.cleared; 793 } 794 795 void Texture::SetLevelImage( 796 const FeatureInfo* feature_info, 797 GLenum target, 798 GLint level, 799 gfx::GLImage* image) { 800 DCHECK_GE(level, 0); 801 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)), 802 level_infos_.size()); 803 DCHECK_LT(static_cast<size_t>(level), 804 level_infos_[GLTargetToFaceIndex(target)].size()); 805 Texture::LevelInfo& info = 806 level_infos_[GLTargetToFaceIndex(target)][level]; 807 DCHECK_EQ(info.target, target); 808 DCHECK_EQ(info.level, level); 809 info.image = image; 810 UpdateCanRenderCondition(); 811 UpdateHasImages(); 812 } 813 814 gfx::GLImage* Texture::GetLevelImage(GLint target, GLint level) const { 815 size_t face_index = GLTargetToFaceIndex(target); 816 if (level >= 0 && face_index < level_infos_.size() && 817 static_cast<size_t>(level) < level_infos_[face_index].size()) { 818 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level]; 819 if (info.target != 0) { 820 return info.image.get(); 821 } 822 } 823 return 0; 824 } 825 826 827 TextureRef::TextureRef(TextureManager* manager, 828 GLuint client_id, 829 Texture* texture) 830 : manager_(manager), 831 texture_(texture), 832 client_id_(client_id), 833 is_stream_texture_owner_(false) { 834 DCHECK(manager_); 835 DCHECK(texture_); 836 texture_->AddTextureRef(this); 837 manager_->StartTracking(this); 838 } 839 840 scoped_refptr<TextureRef> TextureRef::Create(TextureManager* manager, 841 GLuint client_id, 842 GLuint service_id) { 843 return new TextureRef(manager, client_id, new Texture(service_id)); 844 } 845 846 TextureRef::~TextureRef() { 847 manager_->StopTracking(this); 848 texture_->RemoveTextureRef(this, manager_->have_context_); 849 manager_ = NULL; 850 } 851 852 TextureManager::TextureManager( 853 MemoryTracker* memory_tracker, 854 FeatureInfo* feature_info, 855 GLint max_texture_size, 856 GLint max_cube_map_texture_size) 857 : memory_tracker_managed_( 858 new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)), 859 memory_tracker_unmanaged_( 860 new MemoryTypeTracker(memory_tracker, MemoryTracker::kUnmanaged)), 861 feature_info_(feature_info), 862 framebuffer_manager_(NULL), 863 stream_texture_manager_(NULL), 864 max_texture_size_(max_texture_size), 865 max_cube_map_texture_size_(max_cube_map_texture_size), 866 max_levels_(ComputeMipMapCount(max_texture_size, 867 max_texture_size, 868 max_texture_size)), 869 max_cube_map_levels_(ComputeMipMapCount(max_cube_map_texture_size, 870 max_cube_map_texture_size, 871 max_cube_map_texture_size)), 872 num_unrenderable_textures_(0), 873 num_unsafe_textures_(0), 874 num_uncleared_mips_(0), 875 num_images_(0), 876 texture_count_(0), 877 have_context_(true) { 878 for (int ii = 0; ii < kNumDefaultTextures; ++ii) { 879 black_texture_ids_[ii] = 0; 880 } 881 } 882 883 bool TextureManager::Initialize() { 884 // TODO(gman): The default textures have to be real textures, not the 0 885 // texture because we simulate non shared resources on top of shared 886 // resources and all contexts that share resource share the same default 887 // texture. 888 default_textures_[kTexture2D] = CreateDefaultAndBlackTextures( 889 GL_TEXTURE_2D, &black_texture_ids_[kTexture2D]); 890 default_textures_[kCubeMap] = CreateDefaultAndBlackTextures( 891 GL_TEXTURE_CUBE_MAP, &black_texture_ids_[kCubeMap]); 892 893 if (feature_info_->feature_flags().oes_egl_image_external) { 894 default_textures_[kExternalOES] = CreateDefaultAndBlackTextures( 895 GL_TEXTURE_EXTERNAL_OES, &black_texture_ids_[kExternalOES]); 896 } 897 898 if (feature_info_->feature_flags().arb_texture_rectangle) { 899 default_textures_[kRectangleARB] = CreateDefaultAndBlackTextures( 900 GL_TEXTURE_RECTANGLE_ARB, &black_texture_ids_[kRectangleARB]); 901 } 902 903 return true; 904 } 905 906 scoped_refptr<TextureRef> 907 TextureManager::CreateDefaultAndBlackTextures( 908 GLenum target, 909 GLuint* black_texture) { 910 static uint8 black[] = {0, 0, 0, 255}; 911 912 // Sampling a texture not associated with any EGLImage sibling will return 913 // black values according to the spec. 914 bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES); 915 bool needs_faces = (target == GL_TEXTURE_CUBE_MAP); 916 917 // Make default textures and texture for replacing non-renderable textures. 918 GLuint ids[2]; 919 glGenTextures(arraysize(ids), ids); 920 for (unsigned long ii = 0; ii < arraysize(ids); ++ii) { 921 glBindTexture(target, ids[ii]); 922 if (needs_initialization) { 923 if (needs_faces) { 924 for (int jj = 0; jj < GLES2Util::kNumFaces; ++jj) { 925 glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj), 0, GL_RGBA, 1, 1, 0, 926 GL_RGBA, GL_UNSIGNED_BYTE, black); 927 } 928 } else { 929 glTexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA, 930 GL_UNSIGNED_BYTE, black); 931 } 932 } 933 } 934 glBindTexture(target, 0); 935 936 scoped_refptr<TextureRef> default_texture( 937 TextureRef::Create(this, 0, ids[1])); 938 SetTarget(default_texture.get(), target); 939 if (needs_faces) { 940 for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) { 941 SetLevelInfo(default_texture.get(), 942 GLES2Util::IndexToGLFaceTarget(ii), 943 0, 944 GL_RGBA, 945 1, 946 1, 947 1, 948 0, 949 GL_RGBA, 950 GL_UNSIGNED_BYTE, 951 true); 952 } 953 } else { 954 if (needs_initialization) { 955 SetLevelInfo(default_texture.get(), 956 GL_TEXTURE_2D, 957 0, 958 GL_RGBA, 959 1, 960 1, 961 1, 962 0, 963 GL_RGBA, 964 GL_UNSIGNED_BYTE, 965 true); 966 } else { 967 SetLevelInfo(default_texture.get(), 968 GL_TEXTURE_EXTERNAL_OES, 969 0, 970 GL_RGBA, 971 1, 972 1, 973 1, 974 0, 975 GL_RGBA, 976 GL_UNSIGNED_BYTE, 977 true); 978 } 979 } 980 981 *black_texture = ids[0]; 982 return default_texture; 983 } 984 985 bool TextureManager::ValidForTarget( 986 GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth) { 987 GLsizei max_size = MaxSizeForTarget(target) >> level; 988 return level >= 0 && 989 width >= 0 && 990 height >= 0 && 991 depth >= 0 && 992 level < MaxLevelsForTarget(target) && 993 width <= max_size && 994 height <= max_size && 995 depth <= max_size && 996 (level == 0 || feature_info_->feature_flags().npot_ok || 997 (!GLES2Util::IsNPOT(width) && 998 !GLES2Util::IsNPOT(height) && 999 !GLES2Util::IsNPOT(depth))) && 1000 (target != GL_TEXTURE_CUBE_MAP || (width == height && depth == 1)) && 1001 (target != GL_TEXTURE_2D || (depth == 1)); 1002 } 1003 1004 void TextureManager::SetTarget(TextureRef* ref, GLenum target) { 1005 DCHECK(ref); 1006 ref->texture() 1007 ->SetTarget(feature_info_.get(), target, MaxLevelsForTarget(target)); 1008 } 1009 1010 void TextureManager::SetStreamTexture(TextureRef* ref, bool stream_texture) { 1011 DCHECK(ref); 1012 // Only the owner can mark as non-stream texture. 1013 DCHECK_EQ(stream_texture, !ref->is_stream_texture_owner_); 1014 ref->texture()->SetStreamTexture(stream_texture); 1015 ref->set_is_stream_texture_owner(stream_texture); 1016 } 1017 1018 bool TextureManager::IsStreamTextureOwner(TextureRef* ref) { 1019 DCHECK(ref); 1020 return ref->is_stream_texture_owner(); 1021 } 1022 1023 void TextureManager::SetLevelCleared(TextureRef* ref, 1024 GLenum target, 1025 GLint level, 1026 bool cleared) { 1027 DCHECK(ref); 1028 ref->texture()->SetLevelCleared(target, level, cleared); 1029 } 1030 1031 bool TextureManager::ClearRenderableLevels( 1032 GLES2Decoder* decoder, TextureRef* ref) { 1033 DCHECK(ref); 1034 return ref->texture()->ClearRenderableLevels(decoder); 1035 } 1036 1037 bool TextureManager::ClearTextureLevel( 1038 GLES2Decoder* decoder, TextureRef* ref, 1039 GLenum target, GLint level) { 1040 DCHECK(ref); 1041 Texture* texture = ref->texture(); 1042 if (texture->num_uncleared_mips() == 0) { 1043 return true; 1044 } 1045 bool result = texture->ClearLevel(decoder, target, level); 1046 texture->UpdateCleared(); 1047 return result; 1048 } 1049 1050 void TextureManager::SetLevelInfo( 1051 TextureRef* ref, 1052 GLenum target, 1053 GLint level, 1054 GLenum internal_format, 1055 GLsizei width, 1056 GLsizei height, 1057 GLsizei depth, 1058 GLint border, 1059 GLenum format, 1060 GLenum type, 1061 bool cleared) { 1062 DCHECK(ref); 1063 Texture* texture = ref->texture(); 1064 1065 texture->GetMemTracker()->TrackMemFree(texture->estimated_size()); 1066 texture->SetLevelInfo(feature_info_.get(), 1067 target, 1068 level, 1069 internal_format, 1070 width, 1071 height, 1072 depth, 1073 border, 1074 format, 1075 type, 1076 cleared); 1077 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size()); 1078 } 1079 1080 Texture* TextureManager::Produce(TextureRef* ref) { 1081 DCHECK(ref); 1082 return ref->texture(); 1083 } 1084 1085 TextureRef* TextureManager::Consume( 1086 GLuint client_id, 1087 Texture* texture) { 1088 DCHECK(client_id); 1089 scoped_refptr<TextureRef> ref(new TextureRef(this, client_id, texture)); 1090 bool result = textures_.insert(std::make_pair(client_id, ref)).second; 1091 DCHECK(result); 1092 return ref.get(); 1093 } 1094 1095 void TextureManager::SetParameter( 1096 const char* function_name, ErrorState* error_state, 1097 TextureRef* ref, GLenum pname, GLint param) { 1098 DCHECK(error_state); 1099 DCHECK(ref); 1100 Texture* texture = ref->texture(); 1101 GLenum result = texture->SetParameter(feature_info_.get(), pname, param); 1102 if (result != GL_NO_ERROR) { 1103 if (result == GL_INVALID_ENUM) { 1104 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM( 1105 error_state, function_name, param, "param"); 1106 } else { 1107 ERRORSTATE_SET_GL_ERROR_INVALID_PARAM( 1108 error_state, result, function_name, pname, static_cast<GLint>(param)); 1109 } 1110 } else { 1111 // Texture tracking pools exist only for the command decoder, so 1112 // do not pass them on to the native GL implementation. 1113 if (pname != GL_TEXTURE_POOL_CHROMIUM) { 1114 glTexParameteri(texture->target(), pname, param); 1115 } 1116 } 1117 } 1118 1119 bool TextureManager::MarkMipmapsGenerated(TextureRef* ref) { 1120 DCHECK(ref); 1121 Texture* texture = ref->texture(); 1122 texture->GetMemTracker()->TrackMemFree(texture->estimated_size()); 1123 bool result = texture->MarkMipmapsGenerated(feature_info_.get()); 1124 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size()); 1125 return result; 1126 } 1127 1128 TextureRef* TextureManager::CreateTexture( 1129 GLuint client_id, GLuint service_id) { 1130 DCHECK_NE(0u, service_id); 1131 scoped_refptr<TextureRef> ref(TextureRef::Create( 1132 this, client_id, service_id)); 1133 std::pair<TextureMap::iterator, bool> result = 1134 textures_.insert(std::make_pair(client_id, ref)); 1135 DCHECK(result.second); 1136 return ref.get(); 1137 } 1138 1139 TextureRef* TextureManager::GetTexture( 1140 GLuint client_id) const { 1141 TextureMap::const_iterator it = textures_.find(client_id); 1142 return it != textures_.end() ? it->second.get() : NULL; 1143 } 1144 1145 void TextureManager::RemoveTexture(GLuint client_id) { 1146 TextureMap::iterator it = textures_.find(client_id); 1147 if (it != textures_.end()) { 1148 it->second->reset_client_id(); 1149 textures_.erase(it); 1150 } 1151 } 1152 1153 void TextureManager::StartTracking(TextureRef* ref) { 1154 Texture* texture = ref->texture(); 1155 ++texture_count_; 1156 num_uncleared_mips_ += texture->num_uncleared_mips(); 1157 if (!texture->SafeToRenderFrom()) 1158 ++num_unsafe_textures_; 1159 if (!texture->CanRender(feature_info_.get())) 1160 ++num_unrenderable_textures_; 1161 if (texture->HasImages()) 1162 ++num_images_; 1163 } 1164 1165 void TextureManager::StopTracking(TextureRef* ref) { 1166 FOR_EACH_OBSERVER(DestructionObserver, 1167 destruction_observers_, 1168 OnTextureRefDestroying(ref)); 1169 1170 Texture* texture = ref->texture(); 1171 if (ref->is_stream_texture_owner_ && stream_texture_manager_) { 1172 DCHECK(texture->IsStreamTexture()); 1173 stream_texture_manager_->DestroyStreamTexture(texture->service_id()); 1174 } 1175 1176 --texture_count_; 1177 if (texture->HasImages()) { 1178 DCHECK_NE(0, num_images_); 1179 --num_images_; 1180 } 1181 if (!texture->CanRender(feature_info_.get())) { 1182 DCHECK_NE(0, num_unrenderable_textures_); 1183 --num_unrenderable_textures_; 1184 } 1185 if (!texture->SafeToRenderFrom()) { 1186 DCHECK_NE(0, num_unsafe_textures_); 1187 --num_unsafe_textures_; 1188 } 1189 num_uncleared_mips_ -= texture->num_uncleared_mips(); 1190 DCHECK_GE(num_uncleared_mips_, 0); 1191 } 1192 1193 MemoryTypeTracker* TextureManager::GetMemTracker(GLenum tracking_pool) { 1194 switch(tracking_pool) { 1195 case GL_TEXTURE_POOL_MANAGED_CHROMIUM: 1196 return memory_tracker_managed_.get(); 1197 break; 1198 case GL_TEXTURE_POOL_UNMANAGED_CHROMIUM: 1199 return memory_tracker_unmanaged_.get(); 1200 break; 1201 default: 1202 break; 1203 } 1204 NOTREACHED(); 1205 return NULL; 1206 } 1207 1208 Texture* TextureManager::GetTextureForServiceId(GLuint service_id) const { 1209 // This doesn't need to be fast. It's only used during slow queries. 1210 for (TextureMap::const_iterator it = textures_.begin(); 1211 it != textures_.end(); ++it) { 1212 Texture* texture = it->second->texture(); 1213 if (texture->service_id() == service_id) 1214 return texture; 1215 } 1216 return NULL; 1217 } 1218 1219 GLsizei TextureManager::ComputeMipMapCount( 1220 GLsizei width, GLsizei height, GLsizei depth) { 1221 return 1 + base::bits::Log2Floor(std::max(std::max(width, height), depth)); 1222 } 1223 1224 void TextureManager::SetLevelImage( 1225 TextureRef* ref, 1226 GLenum target, 1227 GLint level, 1228 gfx::GLImage* image) { 1229 DCHECK(ref); 1230 ref->texture()->SetLevelImage(feature_info_.get(), target, level, image); 1231 } 1232 1233 void TextureManager::AddToSignature( 1234 TextureRef* ref, 1235 GLenum target, 1236 GLint level, 1237 std::string* signature) const { 1238 ref->texture()->AddToSignature(feature_info_.get(), target, level, signature); 1239 } 1240 1241 void TextureManager::UpdateSafeToRenderFrom(int delta) { 1242 num_unsafe_textures_ += delta; 1243 DCHECK_GE(num_unsafe_textures_, 0); 1244 } 1245 1246 void TextureManager::UpdateUnclearedMips(int delta) { 1247 num_uncleared_mips_ += delta; 1248 DCHECK_GE(num_uncleared_mips_, 0); 1249 } 1250 1251 void TextureManager::UpdateCanRenderCondition( 1252 Texture::CanRenderCondition old_condition, 1253 Texture::CanRenderCondition new_condition) { 1254 if (old_condition == Texture::CAN_RENDER_NEVER || 1255 (old_condition == Texture::CAN_RENDER_ONLY_IF_NPOT && 1256 !feature_info_->feature_flags().npot_ok)) { 1257 DCHECK_GT(num_unrenderable_textures_, 0); 1258 --num_unrenderable_textures_; 1259 } 1260 if (new_condition == Texture::CAN_RENDER_NEVER || 1261 (new_condition == Texture::CAN_RENDER_ONLY_IF_NPOT && 1262 !feature_info_->feature_flags().npot_ok)) 1263 ++num_unrenderable_textures_; 1264 } 1265 1266 void TextureManager::UpdateNumImages(int delta) { 1267 num_images_ += delta; 1268 DCHECK_GE(num_images_, 0); 1269 } 1270 1271 void TextureManager::IncFramebufferStateChangeCount() { 1272 if (framebuffer_manager_) 1273 framebuffer_manager_->IncFramebufferStateChangeCount(); 1274 } 1275 1276 } // namespace gles2 1277 } // namespace gpu 1278