1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "gpu/command_buffer/service/texture_manager.h"
7 #include "base/strings/stringprintf.h"
8 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
9 #include "gpu/command_buffer/service/context_state.h"
10 #include "gpu/command_buffer/service/error_state.h"
11 #include "gpu/command_buffer/service/feature_info.h"
12 #include "gpu/command_buffer/service/framebuffer_manager.h"
13 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
14 #include "gpu/command_buffer/service/mailbox_manager.h"
15 #include "gpu/command_buffer/service/memory_tracking.h"
16 #include "gpu/command_buffer/service/stream_texture_manager.h"
21 static size_t GLTargetToFaceIndex(GLenum target) {
24 case GL_TEXTURE_EXTERNAL_OES:
25 case GL_TEXTURE_RECTANGLE_ARB:
27 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
29 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
31 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
33 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
35 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
37 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
45 static size_t FaceIndexToGLTarget(size_t index) {
48 return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
50 return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
52 return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
54 return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
56 return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
58 return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
65 TextureManager::DestructionObserver::DestructionObserver() {}
67 TextureManager::DestructionObserver::~DestructionObserver() {}
69 TextureManager::~TextureManager() {
70 FOR_EACH_OBSERVER(DestructionObserver,
71 destruction_observers_,
72 OnTextureManagerDestroying(this));
74 DCHECK(textures_.empty());
76 // If this triggers, that means something is keeping a reference to
77 // a Texture belonging to this.
78 CHECK_EQ(texture_count_, 0u);
80 DCHECK_EQ(0, num_unrenderable_textures_);
81 DCHECK_EQ(0, num_unsafe_textures_);
82 DCHECK_EQ(0, num_uncleared_mips_);
83 DCHECK_EQ(0, num_images_);
86 void TextureManager::Destroy(bool have_context) {
87 have_context_ = have_context;
89 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
90 default_textures_[ii] = NULL;
94 glDeleteTextures(arraysize(black_texture_ids_), black_texture_ids_);
97 DCHECK_EQ(0u, memory_tracker_managed_->GetMemRepresented());
98 DCHECK_EQ(0u, memory_tracker_unmanaged_->GetMemRepresented());
101 Texture::Texture(GLuint service_id)
102 : mailbox_manager_(NULL),
103 memory_tracking_ref_(NULL),
104 service_id_(service_id),
106 num_uncleared_mips_(0),
108 min_filter_(GL_NEAREST_MIPMAP_LINEAR),
109 mag_filter_(GL_LINEAR),
113 pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM),
115 texture_complete_(false),
116 cube_complete_(false),
118 has_been_bound_(false),
119 framebuffer_attachment_count_(0),
120 stream_texture_(false),
124 can_render_condition_(CAN_RENDER_ALWAYS) {
127 Texture::~Texture() {
128 if (mailbox_manager_)
129 mailbox_manager_->TextureDeleted(this);
132 void Texture::AddTextureRef(TextureRef* ref) {
133 DCHECK(refs_.find(ref) == refs_.end());
135 if (!memory_tracking_ref_) {
136 memory_tracking_ref_ = ref;
137 GetMemTracker()->TrackMemAlloc(estimated_size());
141 void Texture::RemoveTextureRef(TextureRef* ref, bool have_context) {
142 if (memory_tracking_ref_ == ref) {
143 GetMemTracker()->TrackMemFree(estimated_size());
144 memory_tracking_ref_ = NULL;
146 size_t result = refs_.erase(ref);
147 DCHECK_EQ(result, 1u);
150 GLuint id = service_id();
151 glDeleteTextures(1, &id);
154 } else if (memory_tracking_ref_ == NULL) {
155 // TODO(piman): tune ownership semantics for cross-context group shared
157 memory_tracking_ref_ = *refs_.begin();
158 GetMemTracker()->TrackMemAlloc(estimated_size());
162 MemoryTypeTracker* Texture::GetMemTracker() {
163 DCHECK(memory_tracking_ref_);
164 return memory_tracking_ref_->manager()->GetMemTracker(pool_);
167 Texture::LevelInfo::LevelInfo()
181 Texture::LevelInfo::LevelInfo(const LevelInfo& rhs)
182 : cleared(rhs.cleared),
185 internal_format(rhs.internal_format),
193 estimated_size(rhs.estimated_size) {
196 Texture::LevelInfo::~LevelInfo() {
199 Texture::CanRenderCondition Texture::GetCanRenderCondition() const {
201 return CAN_RENDER_ALWAYS;
203 if (target_ != GL_TEXTURE_EXTERNAL_OES) {
204 if (level_infos_.empty()) {
205 return CAN_RENDER_NEVER;
208 const Texture::LevelInfo& first_face = level_infos_[0][0];
209 if (first_face.width == 0 ||
210 first_face.height == 0 ||
211 first_face.depth == 0) {
212 return CAN_RENDER_NEVER;
216 bool needs_mips = NeedsMips();
218 if (!texture_complete())
219 return CAN_RENDER_NEVER;
220 if (target_ == GL_TEXTURE_CUBE_MAP && !cube_complete())
221 return CAN_RENDER_NEVER;
224 bool is_npot_compatible = !needs_mips &&
225 wrap_s_ == GL_CLAMP_TO_EDGE &&
226 wrap_t_ == GL_CLAMP_TO_EDGE;
228 if (!is_npot_compatible) {
229 if (target_ == GL_TEXTURE_RECTANGLE_ARB)
230 return CAN_RENDER_NEVER;
232 return CAN_RENDER_ONLY_IF_NPOT;
235 return CAN_RENDER_ALWAYS;
238 bool Texture::CanRender(const FeatureInfo* feature_info) const {
239 switch (can_render_condition_) {
240 case CAN_RENDER_ALWAYS:
242 case CAN_RENDER_NEVER:
244 case CAN_RENDER_ONLY_IF_NPOT:
247 return feature_info->feature_flags().npot_ok;
250 void Texture::AddToSignature(
251 const FeatureInfo* feature_info,
254 std::string* signature) const {
255 DCHECK(feature_info);
258 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
259 level_infos_.size());
260 DCHECK_LT(static_cast<size_t>(level),
261 level_infos_[GLTargetToFaceIndex(target)].size());
262 const Texture::LevelInfo& info =
263 level_infos_[GLTargetToFaceIndex(target)][level];
264 *signature += base::StringPrintf(
265 "|Texture|target=%04x|level=%d|internal_format=%04x"
266 "|width=%d|height=%d|depth=%d|border=%d|format=%04x|type=%04x"
267 "|image=%d|canrender=%d|canrenderto=%d|npot_=%d"
268 "|min_filter=%04x|mag_filter=%04x|wrap_s=%04x|wrap_t=%04x"
270 target, level, info.internal_format,
271 info.width, info.height, info.depth, info.border,
272 info.format, info.type, info.image.get() != NULL,
273 CanRender(feature_info), CanRenderTo(), npot_,
274 min_filter_, mag_filter_, wrap_s_, wrap_t_,
278 void Texture::SetMailboxManager(MailboxManager* mailbox_manager) {
279 DCHECK(!mailbox_manager_ || mailbox_manager_ == mailbox_manager);
280 mailbox_manager_ = mailbox_manager;
283 bool Texture::MarkMipmapsGenerated(
284 const FeatureInfo* feature_info) {
285 if (!CanGenerateMipmaps(feature_info)) {
288 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
289 const Texture::LevelInfo& info1 = level_infos_[ii][0];
290 GLsizei width = info1.width;
291 GLsizei height = info1.height;
292 GLsizei depth = info1.depth;
293 GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
294 FaceIndexToGLTarget(ii);
296 TextureManager::ComputeMipMapCount(target_, width, height, depth);
297 for (int level = 1; level < num_mips; ++level) {
298 width = std::max(1, width >> 1);
299 height = std::max(1, height >> 1);
300 depth = std::max(1, depth >> 1);
301 SetLevelInfo(feature_info,
304 info1.internal_format,
318 void Texture::SetTarget(
319 const FeatureInfo* feature_info, GLenum target, GLint max_levels) {
320 DCHECK_EQ(0u, target_); // you can only set this once.
322 size_t num_faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
323 level_infos_.resize(num_faces);
324 for (size_t ii = 0; ii < num_faces; ++ii) {
325 level_infos_[ii].resize(max_levels);
328 if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) {
329 min_filter_ = GL_LINEAR;
330 wrap_s_ = wrap_t_ = GL_CLAMP_TO_EDGE;
333 if (target == GL_TEXTURE_EXTERNAL_OES) {
336 Update(feature_info);
337 UpdateCanRenderCondition();
340 bool Texture::CanGenerateMipmaps(
341 const FeatureInfo* feature_info) const {
342 if ((npot() && !feature_info->feature_flags().npot_ok) ||
343 level_infos_.empty() ||
344 target_ == GL_TEXTURE_EXTERNAL_OES ||
345 target_ == GL_TEXTURE_RECTANGLE_ARB) {
349 // Can't generate mips for depth or stencil textures.
350 const Texture::LevelInfo& first = level_infos_[0][0];
351 uint32 channels = GLES2Util::GetChannelsForFormat(first.format);
352 if (channels & (GLES2Util::kDepth | GLES2Util::kStencil)) {
356 // TODO(gman): Check internal_format, format and type.
357 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
358 const LevelInfo& info = level_infos_[ii][0];
359 if ((info.target == 0) || (info.width != first.width) ||
360 (info.height != first.height) || (info.depth != 1) ||
361 (info.format != first.format) ||
362 (info.internal_format != first.internal_format) ||
363 (info.type != first.type) ||
364 feature_info->validators()->compressed_texture_format.IsValid(
365 info.internal_format) ||
373 void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) {
375 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
376 level_infos_.size());
377 DCHECK_LT(static_cast<size_t>(level),
378 level_infos_[GLTargetToFaceIndex(target)].size());
379 Texture::LevelInfo& info =
380 level_infos_[GLTargetToFaceIndex(target)][level];
381 UpdateMipCleared(&info, cleared);
385 void Texture::UpdateCleared() {
386 if (level_infos_.empty()) {
390 const Texture::LevelInfo& first_face = level_infos_[0][0];
391 int levels_needed = TextureManager::ComputeMipMapCount(
392 target_, first_face.width, first_face.height, first_face.depth);
394 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
395 for (GLint jj = 0; jj < levels_needed; ++jj) {
396 const Texture::LevelInfo& info = level_infos_[ii][jj];
397 if (info.width > 0 && info.height > 0 && info.depth > 0 &&
404 UpdateSafeToRenderFrom(cleared);
407 void Texture::UpdateSafeToRenderFrom(bool cleared) {
408 if (cleared_ == cleared)
411 int delta = cleared ? -1 : +1;
412 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
413 (*it)->manager()->UpdateSafeToRenderFrom(delta);
416 void Texture::UpdateMipCleared(LevelInfo* info, bool cleared) {
417 if (info->cleared == cleared)
419 info->cleared = cleared;
420 int delta = cleared ? -1 : +1;
421 num_uncleared_mips_ += delta;
422 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
423 (*it)->manager()->UpdateUnclearedMips(delta);
426 void Texture::UpdateCanRenderCondition() {
427 CanRenderCondition can_render_condition = GetCanRenderCondition();
428 if (can_render_condition_ == can_render_condition)
430 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
431 (*it)->manager()->UpdateCanRenderCondition(can_render_condition_,
432 can_render_condition);
433 can_render_condition_ = can_render_condition;
436 void Texture::UpdateHasImages() {
437 if (level_infos_.empty())
440 bool has_images = false;
441 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
442 for (size_t jj = 0; jj < level_infos_[ii].size(); ++jj) {
443 const Texture::LevelInfo& info = level_infos_[ii][jj];
444 if (info.image.get() != NULL) {
451 if (has_images_ == has_images)
453 has_images_ = has_images;
454 int delta = has_images ? +1 : -1;
455 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
456 (*it)->manager()->UpdateNumImages(delta);
459 void Texture::IncAllFramebufferStateChangeCount() {
460 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
461 (*it)->manager()->IncFramebufferStateChangeCount();
464 void Texture::SetLevelInfo(
465 const FeatureInfo* feature_info,
468 GLenum internal_format,
477 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
478 level_infos_.size());
479 DCHECK_LT(static_cast<size_t>(level),
480 level_infos_[GLTargetToFaceIndex(target)].size());
482 DCHECK_GE(height, 0);
484 Texture::LevelInfo& info =
485 level_infos_[GLTargetToFaceIndex(target)][level];
486 info.target = target;
488 info.internal_format = internal_format;
490 info.height = height;
492 info.border = border;
493 info.format = format;
497 estimated_size_ -= info.estimated_size;
498 GLES2Util::ComputeImageDataSizes(
499 width, height, format, type, 4, &info.estimated_size, NULL, NULL);
500 estimated_size_ += info.estimated_size;
502 UpdateMipCleared(&info, cleared);
503 max_level_set_ = std::max(max_level_set_, level);
504 Update(feature_info);
506 UpdateCanRenderCondition();
508 if (IsAttachedToFramebuffer()) {
509 // TODO(gman): If textures tracked which framebuffers they were attached to
510 // we could just mark those framebuffers as not complete.
511 IncAllFramebufferStateChangeCount();
515 bool Texture::ValidForTexture(
524 size_t face_index = GLTargetToFaceIndex(target);
525 if (level >= 0 && face_index < level_infos_.size() &&
526 static_cast<size_t>(level) < level_infos_[face_index].size()) {
527 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
530 return SafeAddInt32(xoffset, width, &right) &&
531 SafeAddInt32(yoffset, height, &top) &&
534 right <= info.width &&
535 top <= info.height &&
536 format == info.internal_format &&
542 bool Texture::GetLevelSize(
543 GLint target, GLint level, GLsizei* width, GLsizei* height) const {
546 size_t face_index = GLTargetToFaceIndex(target);
547 if (level >= 0 && face_index < level_infos_.size() &&
548 static_cast<size_t>(level) < level_infos_[face_index].size()) {
549 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
550 if (info.target != 0) {
552 *height = info.height;
559 bool Texture::GetLevelType(
560 GLint target, GLint level, GLenum* type, GLenum* internal_format) const {
562 DCHECK(internal_format);
563 size_t face_index = GLTargetToFaceIndex(target);
564 if (level >= 0 && face_index < level_infos_.size() &&
565 static_cast<size_t>(level) < level_infos_[face_index].size()) {
566 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
567 if (info.target != 0) {
569 *internal_format = info.internal_format;
576 GLenum Texture::SetParameter(
577 const FeatureInfo* feature_info, GLenum pname, GLint param) {
578 DCHECK(feature_info);
580 if (target_ == GL_TEXTURE_EXTERNAL_OES ||
581 target_ == GL_TEXTURE_RECTANGLE_ARB) {
582 if (pname == GL_TEXTURE_MIN_FILTER &&
583 (param != GL_NEAREST && param != GL_LINEAR))
584 return GL_INVALID_ENUM;
585 if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) &&
586 param != GL_CLAMP_TO_EDGE)
587 return GL_INVALID_ENUM;
591 case GL_TEXTURE_MIN_FILTER:
592 if (!feature_info->validators()->texture_min_filter_mode.IsValid(param)) {
593 return GL_INVALID_ENUM;
597 case GL_TEXTURE_MAG_FILTER:
598 if (!feature_info->validators()->texture_mag_filter_mode.IsValid(param)) {
599 return GL_INVALID_ENUM;
603 case GL_TEXTURE_POOL_CHROMIUM:
604 if (!feature_info->validators()->texture_pool.IsValid(param)) {
605 return GL_INVALID_ENUM;
607 GetMemTracker()->TrackMemFree(estimated_size());
609 GetMemTracker()->TrackMemAlloc(estimated_size());
611 case GL_TEXTURE_WRAP_S:
612 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
613 return GL_INVALID_ENUM;
617 case GL_TEXTURE_WRAP_T:
618 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
619 return GL_INVALID_ENUM;
623 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
625 return GL_INVALID_VALUE;
628 case GL_TEXTURE_USAGE_ANGLE:
629 if (!feature_info->validators()->texture_usage.IsValid(param)) {
630 return GL_INVALID_ENUM;
636 return GL_INVALID_ENUM;
638 Update(feature_info);
640 UpdateCanRenderCondition();
644 void Texture::Update(const FeatureInfo* feature_info) {
645 // Update npot status.
646 // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others
647 npot_ = target_ == GL_TEXTURE_EXTERNAL_OES;
649 if (level_infos_.empty()) {
650 texture_complete_ = false;
651 cube_complete_ = false;
655 // checks that the first mip of any face is npot.
656 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
657 const Texture::LevelInfo& info = level_infos_[ii][0];
658 if (GLES2Util::IsNPOT(info.width) ||
659 GLES2Util::IsNPOT(info.height) ||
660 GLES2Util::IsNPOT(info.depth)) {
666 // Update texture_complete and cube_complete status.
667 const Texture::LevelInfo& first_face = level_infos_[0][0];
668 int levels_needed = TextureManager::ComputeMipMapCount(
669 target_, first_face.width, first_face.height, first_face.depth);
671 max_level_set_ >= (levels_needed - 1) && max_level_set_ >= 0;
672 cube_complete_ = (level_infos_.size() == 6) &&
673 (first_face.width == first_face.height);
675 if (first_face.width == 0 || first_face.height == 0) {
676 texture_complete_ = false;
678 if (first_face.type == GL_FLOAT &&
679 !feature_info->feature_flags().enable_texture_float_linear &&
680 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
681 mag_filter_ != GL_NEAREST)) {
682 texture_complete_ = false;
683 } else if (first_face.type == GL_HALF_FLOAT_OES &&
684 !feature_info->feature_flags().enable_texture_half_float_linear &&
685 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
686 mag_filter_ != GL_NEAREST)) {
687 texture_complete_ = false;
690 ii < level_infos_.size() && (cube_complete_ || texture_complete_);
692 const Texture::LevelInfo& level0 = level_infos_[ii][0];
693 if (level0.target == 0 ||
694 level0.width != first_face.width ||
695 level0.height != first_face.height ||
697 level0.internal_format != first_face.internal_format ||
698 level0.format != first_face.format ||
699 level0.type != first_face.type) {
700 cube_complete_ = false;
702 // Get level0 dimensions
703 GLsizei width = level0.width;
704 GLsizei height = level0.height;
705 GLsizei depth = level0.depth;
706 for (GLint jj = 1; jj < levels_needed; ++jj) {
707 // compute required size for mip.
708 width = std::max(1, width >> 1);
709 height = std::max(1, height >> 1);
710 depth = std::max(1, depth >> 1);
711 const Texture::LevelInfo& info = level_infos_[ii][jj];
712 if (info.target == 0 ||
713 info.width != width ||
714 info.height != height ||
715 info.depth != depth ||
716 info.internal_format != level0.internal_format ||
717 info.format != level0.format ||
718 info.type != level0.type) {
719 texture_complete_ = false;
726 bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) {
732 const Texture::LevelInfo& first_face = level_infos_[0][0];
733 int levels_needed = TextureManager::ComputeMipMapCount(
734 target_, first_face.width, first_face.height, first_face.depth);
736 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
737 for (GLint jj = 0; jj < levels_needed; ++jj) {
738 Texture::LevelInfo& info = level_infos_[ii][jj];
739 if (info.target != 0) {
740 if (!ClearLevel(decoder, info.target, jj)) {
746 UpdateSafeToRenderFrom(true);
750 bool Texture::IsLevelCleared(GLenum target, GLint level) const {
751 size_t face_index = GLTargetToFaceIndex(target);
752 if (face_index >= level_infos_.size() ||
753 level >= static_cast<GLint>(level_infos_[face_index].size())) {
757 const Texture::LevelInfo& info = level_infos_[face_index][level];
762 bool Texture::ClearLevel(
763 GLES2Decoder* decoder, GLenum target, GLint level) {
765 size_t face_index = GLTargetToFaceIndex(target);
766 if (face_index >= level_infos_.size() ||
767 level >= static_cast<GLint>(level_infos_[face_index].size())) {
771 Texture::LevelInfo& info = level_infos_[face_index][level];
773 DCHECK(target == info.target);
775 if (info.target == 0 ||
783 // NOTE: It seems kind of gross to call back into the decoder for this
784 // but only the decoder knows all the state (like unpack_alignment_) that's
785 // needed to be able to call GL correctly.
786 bool cleared = decoder->ClearLevel(
787 service_id_, target_, info.target, info.level, info.format, info.type,
788 info.width, info.height, immutable_);
789 UpdateMipCleared(&info, cleared);
793 void Texture::SetLevelImage(
794 const FeatureInfo* feature_info,
797 gfx::GLImage* image) {
799 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
800 level_infos_.size());
801 DCHECK_LT(static_cast<size_t>(level),
802 level_infos_[GLTargetToFaceIndex(target)].size());
803 Texture::LevelInfo& info =
804 level_infos_[GLTargetToFaceIndex(target)][level];
805 DCHECK_EQ(info.target, target);
806 DCHECK_EQ(info.level, level);
808 UpdateCanRenderCondition();
812 gfx::GLImage* Texture::GetLevelImage(GLint target, GLint level) const {
813 size_t face_index = GLTargetToFaceIndex(target);
814 if (level >= 0 && face_index < level_infos_.size() &&
815 static_cast<size_t>(level) < level_infos_[face_index].size()) {
816 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
817 if (info.target != 0) {
818 return info.image.get();
825 TextureRef::TextureRef(TextureManager* manager,
830 client_id_(client_id),
831 is_stream_texture_owner_(false) {
834 texture_->AddTextureRef(this);
835 manager_->StartTracking(this);
838 scoped_refptr<TextureRef> TextureRef::Create(TextureManager* manager,
841 return new TextureRef(manager, client_id, new Texture(service_id));
844 TextureRef::~TextureRef() {
845 manager_->StopTracking(this);
846 texture_->RemoveTextureRef(this, manager_->have_context_);
850 TextureManager::TextureManager(MemoryTracker* memory_tracker,
851 FeatureInfo* feature_info,
852 GLint max_texture_size,
853 GLint max_cube_map_texture_size)
854 : memory_tracker_managed_(new MemoryTypeTracker(memory_tracker,
855 MemoryTracker::kManaged)),
856 memory_tracker_unmanaged_(
857 new MemoryTypeTracker(memory_tracker, MemoryTracker::kUnmanaged)),
858 feature_info_(feature_info),
859 framebuffer_manager_(NULL),
860 stream_texture_manager_(NULL),
861 max_texture_size_(max_texture_size),
862 max_cube_map_texture_size_(max_cube_map_texture_size),
863 max_levels_(ComputeMipMapCount(GL_TEXTURE_2D,
867 max_cube_map_levels_(ComputeMipMapCount(GL_TEXTURE_CUBE_MAP,
868 max_cube_map_texture_size,
869 max_cube_map_texture_size,
870 max_cube_map_texture_size)),
871 num_unrenderable_textures_(0),
872 num_unsafe_textures_(0),
873 num_uncleared_mips_(0),
876 have_context_(true) {
877 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
878 black_texture_ids_[ii] = 0;
882 bool TextureManager::Initialize() {
883 // TODO(gman): The default textures have to be real textures, not the 0
884 // texture because we simulate non shared resources on top of shared
885 // resources and all contexts that share resource share the same default
887 default_textures_[kTexture2D] = CreateDefaultAndBlackTextures(
888 GL_TEXTURE_2D, &black_texture_ids_[kTexture2D]);
889 default_textures_[kCubeMap] = CreateDefaultAndBlackTextures(
890 GL_TEXTURE_CUBE_MAP, &black_texture_ids_[kCubeMap]);
892 if (feature_info_->feature_flags().oes_egl_image_external) {
893 default_textures_[kExternalOES] = CreateDefaultAndBlackTextures(
894 GL_TEXTURE_EXTERNAL_OES, &black_texture_ids_[kExternalOES]);
897 if (feature_info_->feature_flags().arb_texture_rectangle) {
898 default_textures_[kRectangleARB] = CreateDefaultAndBlackTextures(
899 GL_TEXTURE_RECTANGLE_ARB, &black_texture_ids_[kRectangleARB]);
905 scoped_refptr<TextureRef>
906 TextureManager::CreateDefaultAndBlackTextures(
908 GLuint* black_texture) {
909 static uint8 black[] = {0, 0, 0, 255};
911 // Sampling a texture not associated with any EGLImage sibling will return
912 // black values according to the spec.
913 bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES);
914 bool needs_faces = (target == GL_TEXTURE_CUBE_MAP);
916 // Make default textures and texture for replacing non-renderable textures.
918 glGenTextures(arraysize(ids), ids);
919 for (unsigned long ii = 0; ii < arraysize(ids); ++ii) {
920 glBindTexture(target, ids[ii]);
921 if (needs_initialization) {
923 for (int jj = 0; jj < GLES2Util::kNumFaces; ++jj) {
924 glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj), 0, GL_RGBA, 1, 1, 0,
925 GL_RGBA, GL_UNSIGNED_BYTE, black);
928 glTexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA,
929 GL_UNSIGNED_BYTE, black);
933 glBindTexture(target, 0);
935 scoped_refptr<TextureRef> default_texture(
936 TextureRef::Create(this, 0, ids[1]));
937 SetTarget(default_texture.get(), target);
939 for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) {
940 SetLevelInfo(default_texture.get(),
941 GLES2Util::IndexToGLFaceTarget(ii),
953 if (needs_initialization) {
954 SetLevelInfo(default_texture.get(),
966 SetLevelInfo(default_texture.get(),
967 GL_TEXTURE_EXTERNAL_OES,
980 *black_texture = ids[0];
981 return default_texture;
984 bool TextureManager::ValidForTarget(
985 GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth) {
986 GLsizei max_size = MaxSizeForTarget(target) >> level;
991 level < MaxLevelsForTarget(target) &&
993 height <= max_size &&
995 (level == 0 || feature_info_->feature_flags().npot_ok ||
996 (!GLES2Util::IsNPOT(width) &&
997 !GLES2Util::IsNPOT(height) &&
998 !GLES2Util::IsNPOT(depth))) &&
999 (target != GL_TEXTURE_CUBE_MAP || (width == height && depth == 1)) &&
1000 (target != GL_TEXTURE_2D || (depth == 1));
1003 void TextureManager::SetTarget(TextureRef* ref, GLenum target) {
1006 ->SetTarget(feature_info_.get(), target, MaxLevelsForTarget(target));
1009 void TextureManager::SetStreamTexture(TextureRef* ref, bool stream_texture) {
1011 // Only the owner can mark as non-stream texture.
1012 DCHECK_EQ(stream_texture, !ref->is_stream_texture_owner_);
1013 ref->texture()->SetStreamTexture(stream_texture);
1014 ref->set_is_stream_texture_owner(stream_texture);
1017 bool TextureManager::IsStreamTextureOwner(TextureRef* ref) {
1019 return ref->is_stream_texture_owner();
1022 void TextureManager::SetLevelCleared(TextureRef* ref,
1027 ref->texture()->SetLevelCleared(target, level, cleared);
1030 bool TextureManager::ClearRenderableLevels(
1031 GLES2Decoder* decoder, TextureRef* ref) {
1033 return ref->texture()->ClearRenderableLevels(decoder);
1036 bool TextureManager::ClearTextureLevel(
1037 GLES2Decoder* decoder, TextureRef* ref,
1038 GLenum target, GLint level) {
1040 Texture* texture = ref->texture();
1041 if (texture->num_uncleared_mips() == 0) {
1044 bool result = texture->ClearLevel(decoder, target, level);
1045 texture->UpdateCleared();
1049 void TextureManager::SetLevelInfo(
1053 GLenum internal_format,
1062 Texture* texture = ref->texture();
1064 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1065 texture->SetLevelInfo(feature_info_.get(),
1076 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1079 Texture* TextureManager::Produce(TextureRef* ref) {
1081 return ref->texture();
1084 TextureRef* TextureManager::Consume(
1088 scoped_refptr<TextureRef> ref(new TextureRef(this, client_id, texture));
1089 bool result = textures_.insert(std::make_pair(client_id, ref)).second;
1094 void TextureManager::SetParameter(
1095 const char* function_name, ErrorState* error_state,
1096 TextureRef* ref, GLenum pname, GLint param) {
1097 DCHECK(error_state);
1099 Texture* texture = ref->texture();
1100 GLenum result = texture->SetParameter(feature_info_.get(), pname, param);
1101 if (result != GL_NO_ERROR) {
1102 if (result == GL_INVALID_ENUM) {
1103 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1104 error_state, function_name, param, "param");
1106 ERRORSTATE_SET_GL_ERROR_INVALID_PARAM(
1107 error_state, result, function_name, pname, static_cast<GLint>(param));
1110 // Texture tracking pools exist only for the command decoder, so
1111 // do not pass them on to the native GL implementation.
1112 if (pname != GL_TEXTURE_POOL_CHROMIUM) {
1113 glTexParameteri(texture->target(), pname, param);
1118 bool TextureManager::MarkMipmapsGenerated(TextureRef* ref) {
1120 Texture* texture = ref->texture();
1121 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1122 bool result = texture->MarkMipmapsGenerated(feature_info_.get());
1123 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1127 TextureRef* TextureManager::CreateTexture(
1128 GLuint client_id, GLuint service_id) {
1129 DCHECK_NE(0u, service_id);
1130 scoped_refptr<TextureRef> ref(TextureRef::Create(
1131 this, client_id, service_id));
1132 std::pair<TextureMap::iterator, bool> result =
1133 textures_.insert(std::make_pair(client_id, ref));
1134 DCHECK(result.second);
1138 TextureRef* TextureManager::GetTexture(
1139 GLuint client_id) const {
1140 TextureMap::const_iterator it = textures_.find(client_id);
1141 return it != textures_.end() ? it->second.get() : NULL;
1144 void TextureManager::RemoveTexture(GLuint client_id) {
1145 TextureMap::iterator it = textures_.find(client_id);
1146 if (it != textures_.end()) {
1147 it->second->reset_client_id();
1148 textures_.erase(it);
1152 void TextureManager::StartTracking(TextureRef* ref) {
1153 Texture* texture = ref->texture();
1155 num_uncleared_mips_ += texture->num_uncleared_mips();
1156 if (!texture->SafeToRenderFrom())
1157 ++num_unsafe_textures_;
1158 if (!texture->CanRender(feature_info_.get()))
1159 ++num_unrenderable_textures_;
1160 if (texture->HasImages())
1164 void TextureManager::StopTracking(TextureRef* ref) {
1165 FOR_EACH_OBSERVER(DestructionObserver,
1166 destruction_observers_,
1167 OnTextureRefDestroying(ref));
1169 Texture* texture = ref->texture();
1170 if (ref->is_stream_texture_owner_ && stream_texture_manager_) {
1171 DCHECK(texture->IsStreamTexture());
1172 stream_texture_manager_->DestroyStreamTexture(texture->service_id());
1176 if (texture->HasImages()) {
1177 DCHECK_NE(0, num_images_);
1180 if (!texture->CanRender(feature_info_.get())) {
1181 DCHECK_NE(0, num_unrenderable_textures_);
1182 --num_unrenderable_textures_;
1184 if (!texture->SafeToRenderFrom()) {
1185 DCHECK_NE(0, num_unsafe_textures_);
1186 --num_unsafe_textures_;
1188 num_uncleared_mips_ -= texture->num_uncleared_mips();
1189 DCHECK_GE(num_uncleared_mips_, 0);
1192 MemoryTypeTracker* TextureManager::GetMemTracker(GLenum tracking_pool) {
1193 switch(tracking_pool) {
1194 case GL_TEXTURE_POOL_MANAGED_CHROMIUM:
1195 return memory_tracker_managed_.get();
1197 case GL_TEXTURE_POOL_UNMANAGED_CHROMIUM:
1198 return memory_tracker_unmanaged_.get();
1207 Texture* TextureManager::GetTextureForServiceId(GLuint service_id) const {
1208 // This doesn't need to be fast. It's only used during slow queries.
1209 for (TextureMap::const_iterator it = textures_.begin();
1210 it != textures_.end(); ++it) {
1211 Texture* texture = it->second->texture();
1212 if (texture->service_id() == service_id)
1218 GLsizei TextureManager::ComputeMipMapCount(GLenum target,
1223 case GL_TEXTURE_EXTERNAL_OES:
1227 base::bits::Log2Floor(std::max(std::max(width, height), depth));
1231 void TextureManager::SetLevelImage(
1235 gfx::GLImage* image) {
1237 ref->texture()->SetLevelImage(feature_info_.get(), target, level, image);
1240 void TextureManager::AddToSignature(
1244 std::string* signature) const {
1245 ref->texture()->AddToSignature(feature_info_.get(), target, level, signature);
1248 void TextureManager::UpdateSafeToRenderFrom(int delta) {
1249 num_unsafe_textures_ += delta;
1250 DCHECK_GE(num_unsafe_textures_, 0);
1253 void TextureManager::UpdateUnclearedMips(int delta) {
1254 num_uncleared_mips_ += delta;
1255 DCHECK_GE(num_uncleared_mips_, 0);
1258 void TextureManager::UpdateCanRenderCondition(
1259 Texture::CanRenderCondition old_condition,
1260 Texture::CanRenderCondition new_condition) {
1261 if (old_condition == Texture::CAN_RENDER_NEVER ||
1262 (old_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1263 !feature_info_->feature_flags().npot_ok)) {
1264 DCHECK_GT(num_unrenderable_textures_, 0);
1265 --num_unrenderable_textures_;
1267 if (new_condition == Texture::CAN_RENDER_NEVER ||
1268 (new_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1269 !feature_info_->feature_flags().npot_ok))
1270 ++num_unrenderable_textures_;
1273 void TextureManager::UpdateNumImages(int delta) {
1274 num_images_ += delta;
1275 DCHECK_GE(num_images_, 0);
1278 void TextureManager::IncFramebufferStateChangeCount() {
1279 if (framebuffer_manager_)
1280 framebuffer_manager_->IncFramebufferStateChangeCount();
1283 bool TextureManager::ValidateTextureParameters(
1284 ErrorState* error_state, const char* function_name,
1285 GLenum target, GLenum format, GLenum type, GLint level) {
1286 if (!feature_info_->GetTextureFormatValidator(format).IsValid(type)) {
1287 ERRORSTATE_SET_GL_ERROR(
1288 error_state, GL_INVALID_OPERATION, function_name,
1289 (std::string("invalid type ") +
1290 GLES2Util::GetStringEnum(type) + " for format " +
1291 GLES2Util::GetStringEnum(format)).c_str());
1295 uint32 channels = GLES2Util::GetChannelsForFormat(format);
1296 if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) {
1297 ERRORSTATE_SET_GL_ERROR(
1298 error_state, GL_INVALID_OPERATION, function_name,
1299 (std::string("invalid type ") +
1300 GLES2Util::GetStringEnum(type) + " for format " +
1301 GLES2Util::GetStringEnum(format)).c_str());
1307 // Gets the texture id for a given target.
1308 TextureRef* TextureManager::GetTextureInfoForTarget(
1309 ContextState* state, GLenum target) {
1310 TextureUnit& unit = state->texture_units[state->active_texture_unit];
1311 TextureRef* texture = NULL;
1314 texture = unit.bound_texture_2d.get();
1316 case GL_TEXTURE_CUBE_MAP:
1317 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1318 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1319 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1320 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1321 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1322 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1323 texture = unit.bound_texture_cube_map.get();
1325 case GL_TEXTURE_EXTERNAL_OES:
1326 texture = unit.bound_texture_external_oes.get();
1328 case GL_TEXTURE_RECTANGLE_ARB:
1329 texture = unit.bound_texture_rectangle_arb.get();
1338 TextureRef* TextureManager::GetTextureInfoForTargetUnlessDefault(
1339 ContextState* state, GLenum target) {
1340 TextureRef* texture = GetTextureInfoForTarget(state, target);
1343 if (texture == GetDefaultTextureInfo(target))
1348 bool TextureManager::ValidateTexImage2D(
1349 ContextState* state,
1350 const char* function_name,
1351 const DoTextImage2DArguments& args,
1352 TextureRef** texture_ref) {
1353 ErrorState* error_state = state->GetErrorState();
1354 const Validators* validators = feature_info_->validators();
1355 if (!validators->texture_target.IsValid(args.target)) {
1356 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1357 error_state, function_name, args.target, "target");
1360 if (!validators->texture_format.IsValid(args.internal_format)) {
1361 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1362 error_state, function_name, args.internal_format,
1366 if (!validators->texture_format.IsValid(args.format)) {
1367 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1368 error_state, function_name, args.format, "format");
1371 if (!validators->pixel_type.IsValid(args.type)) {
1372 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1373 error_state, function_name, args.type, "type");
1376 if (args.format != args.internal_format) {
1377 ERRORSTATE_SET_GL_ERROR(
1378 error_state, GL_INVALID_OPERATION, function_name,
1379 "format != internalFormat");
1382 if (!ValidateTextureParameters(
1383 error_state, function_name, args.target, args.format, args.type,
1387 if (!ValidForTarget(args.target, args.level, args.width, args.height, 1) ||
1389 ERRORSTATE_SET_GL_ERROR(
1390 error_state, GL_INVALID_VALUE, function_name,
1391 "dimensions out of range");
1394 if ((GLES2Util::GetChannelsForFormat(args.format) &
1395 (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && args.pixels) {
1396 ERRORSTATE_SET_GL_ERROR(
1397 error_state, GL_INVALID_OPERATION,
1398 function_name, "can not supply data for depth or stencil textures");
1402 TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target);
1403 if (!local_texture_ref) {
1404 ERRORSTATE_SET_GL_ERROR(
1405 error_state, GL_INVALID_OPERATION, function_name,
1406 "unknown texture for target");
1409 if (local_texture_ref->texture()->IsImmutable()) {
1410 ERRORSTATE_SET_GL_ERROR(
1411 error_state, GL_INVALID_OPERATION, function_name,
1412 "texture is immutable");
1416 // TODO - verify that using the managed vs unmanaged does not matter.
1417 // They both use the same MemoryTracker, and this call just re-routes
1419 if (!memory_tracker_managed_->EnsureGPUMemoryAvailable(args.pixels_size)) {
1420 ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, "glTexImage2D",
1425 // Write the TextureReference since this is valid.
1426 *texture_ref = local_texture_ref;
1430 void TextureManager::ValidateAndDoTexImage2D(
1431 DecoderTextureState* texture_state,
1432 ContextState* state,
1433 DecoderFramebufferState* framebuffer_state,
1434 const DoTextImage2DArguments& args) {
1435 TextureRef* texture_ref;
1436 if (!ValidateTexImage2D(state, "glTexImage2D", args, &texture_ref)) {
1440 DoTexImage2D(texture_state, state->GetErrorState(), framebuffer_state,
1444 void TextureManager::DoTexImage2D(
1445 DecoderTextureState* texture_state,
1446 ErrorState* error_state,
1447 DecoderFramebufferState* framebuffer_state,
1448 TextureRef* texture_ref,
1449 const DoTextImage2DArguments& args) {
1450 Texture* texture = texture_ref->texture();
1451 GLsizei tex_width = 0;
1452 GLsizei tex_height = 0;
1453 GLenum tex_type = 0;
1454 GLenum tex_format = 0;
1455 bool level_is_same =
1456 texture->GetLevelSize(args.target, args.level, &tex_width, &tex_height) &&
1457 texture->GetLevelType(args.target, args.level, &tex_type, &tex_format) &&
1458 args.width == tex_width && args.height == tex_height &&
1459 args.type == tex_type && args.format == tex_format;
1461 if (level_is_same && !args.pixels) {
1462 // Just set the level texture but mark the texture as uncleared.
1465 args.target, args.level, args.internal_format, args.width, args.height,
1466 1, args.border, args.format, args.type, false);
1467 texture_state->tex_image_2d_failed = false;
1471 if (texture->IsAttachedToFramebuffer()) {
1472 framebuffer_state->clear_state_dirty = true;
1475 if (!texture_state->teximage2d_faster_than_texsubimage2d &&
1476 level_is_same && args.pixels) {
1478 ScopedTextureUploadTimer timer(texture_state);
1479 glTexSubImage2D(args.target, args.level, 0, 0, args.width, args.height,
1480 args.format, args.type, args.pixels);
1482 SetLevelCleared(texture_ref, args.target, args.level, true);
1483 texture_state->tex_image_2d_failed = false;
1487 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glTexImage2D");
1489 ScopedTextureUploadTimer timer(texture_state);
1491 args.target, args.level, args.internal_format, args.width, args.height,
1492 args.border, args.format, args.type, args.pixels);
1494 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glTexImage2D");
1495 if (error == GL_NO_ERROR) {
1498 args.target, args.level, args.internal_format, args.width, args.height,
1499 1, args.border, args.format, args.type, args.pixels != NULL);
1500 texture_state->tex_image_2d_failed = false;
1504 ScopedTextureUploadTimer::ScopedTextureUploadTimer(
1505 DecoderTextureState* texture_state)
1506 : texture_state_(texture_state),
1507 begin_time_(base::TimeTicks::HighResNow()) {
1510 ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
1511 texture_state_->texture_upload_count++;
1512 texture_state_->total_texture_upload_time +=
1513 base::TimeTicks::HighResNow() - begin_time_;
1516 } // namespace gles2