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"
20 static size_t GLTargetToFaceIndex(GLenum target) {
23 case GL_TEXTURE_EXTERNAL_OES:
24 case GL_TEXTURE_RECTANGLE_ARB:
26 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
28 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
30 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
32 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
34 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
36 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
44 static size_t FaceIndexToGLTarget(size_t index) {
47 return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
49 return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
51 return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
53 return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
55 return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
57 return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
64 TextureManager::DestructionObserver::DestructionObserver() {}
66 TextureManager::DestructionObserver::~DestructionObserver() {}
68 TextureManager::~TextureManager() {
69 FOR_EACH_OBSERVER(DestructionObserver,
70 destruction_observers_,
71 OnTextureManagerDestroying(this));
73 DCHECK(textures_.empty());
75 // If this triggers, that means something is keeping a reference to
76 // a Texture belonging to this.
77 CHECK_EQ(texture_count_, 0u);
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_);
85 void TextureManager::Destroy(bool have_context) {
86 have_context_ = have_context;
88 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
89 default_textures_[ii] = NULL;
93 glDeleteTextures(arraysize(black_texture_ids_), black_texture_ids_);
96 DCHECK_EQ(0u, memory_tracker_managed_->GetMemRepresented());
97 DCHECK_EQ(0u, memory_tracker_unmanaged_->GetMemRepresented());
100 Texture::Texture(GLuint service_id)
101 : mailbox_manager_(NULL),
102 memory_tracking_ref_(NULL),
103 service_id_(service_id),
105 num_uncleared_mips_(0),
107 min_filter_(GL_NEAREST_MIPMAP_LINEAR),
108 mag_filter_(GL_LINEAR),
112 pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM),
114 texture_complete_(false),
115 cube_complete_(false),
117 has_been_bound_(false),
118 framebuffer_attachment_count_(0),
122 can_render_condition_(CAN_RENDER_ALWAYS) {
125 Texture::~Texture() {
126 if (mailbox_manager_)
127 mailbox_manager_->TextureDeleted(this);
130 void Texture::AddTextureRef(TextureRef* ref) {
131 DCHECK(refs_.find(ref) == refs_.end());
133 if (!memory_tracking_ref_) {
134 memory_tracking_ref_ = ref;
135 GetMemTracker()->TrackMemAlloc(estimated_size());
139 void Texture::RemoveTextureRef(TextureRef* ref, bool have_context) {
140 if (memory_tracking_ref_ == ref) {
141 GetMemTracker()->TrackMemFree(estimated_size());
142 memory_tracking_ref_ = NULL;
144 size_t result = refs_.erase(ref);
145 DCHECK_EQ(result, 1u);
148 GLuint id = service_id();
149 glDeleteTextures(1, &id);
152 } else if (memory_tracking_ref_ == NULL) {
153 // TODO(piman): tune ownership semantics for cross-context group shared
155 memory_tracking_ref_ = *refs_.begin();
156 GetMemTracker()->TrackMemAlloc(estimated_size());
160 MemoryTypeTracker* Texture::GetMemTracker() {
161 DCHECK(memory_tracking_ref_);
162 return memory_tracking_ref_->manager()->GetMemTracker(pool_);
165 Texture::LevelInfo::LevelInfo()
179 Texture::LevelInfo::LevelInfo(const LevelInfo& rhs)
180 : cleared(rhs.cleared),
183 internal_format(rhs.internal_format),
191 estimated_size(rhs.estimated_size) {
194 Texture::LevelInfo::~LevelInfo() {
197 Texture::CanRenderCondition Texture::GetCanRenderCondition() const {
199 return CAN_RENDER_ALWAYS;
201 if (target_ != GL_TEXTURE_EXTERNAL_OES) {
202 if (level_infos_.empty()) {
203 return CAN_RENDER_NEVER;
206 const Texture::LevelInfo& first_face = level_infos_[0][0];
207 if (first_face.width == 0 ||
208 first_face.height == 0 ||
209 first_face.depth == 0) {
210 return CAN_RENDER_NEVER;
214 bool needs_mips = NeedsMips();
216 if (!texture_complete())
217 return CAN_RENDER_NEVER;
218 if (target_ == GL_TEXTURE_CUBE_MAP && !cube_complete())
219 return CAN_RENDER_NEVER;
222 bool is_npot_compatible = !needs_mips &&
223 wrap_s_ == GL_CLAMP_TO_EDGE &&
224 wrap_t_ == GL_CLAMP_TO_EDGE;
226 if (!is_npot_compatible) {
227 if (target_ == GL_TEXTURE_RECTANGLE_ARB)
228 return CAN_RENDER_NEVER;
230 return CAN_RENDER_ONLY_IF_NPOT;
233 return CAN_RENDER_ALWAYS;
236 bool Texture::CanRender(const FeatureInfo* feature_info) const {
237 switch (can_render_condition_) {
238 case CAN_RENDER_ALWAYS:
240 case CAN_RENDER_NEVER:
242 case CAN_RENDER_ONLY_IF_NPOT:
245 return feature_info->feature_flags().npot_ok;
248 void Texture::AddToSignature(
249 const FeatureInfo* feature_info,
252 std::string* signature) const {
253 DCHECK(feature_info);
256 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
257 level_infos_.size());
258 DCHECK_LT(static_cast<size_t>(level),
259 level_infos_[GLTargetToFaceIndex(target)].size());
260 const Texture::LevelInfo& info =
261 level_infos_[GLTargetToFaceIndex(target)][level];
262 *signature += base::StringPrintf(
263 "|Texture|target=%04x|level=%d|internal_format=%04x"
264 "|width=%d|height=%d|depth=%d|border=%d|format=%04x|type=%04x"
265 "|image=%d|canrender=%d|canrenderto=%d|npot_=%d"
266 "|min_filter=%04x|mag_filter=%04x|wrap_s=%04x|wrap_t=%04x"
268 target, level, info.internal_format,
269 info.width, info.height, info.depth, info.border,
270 info.format, info.type, info.image.get() != NULL,
271 CanRender(feature_info), CanRenderTo(), npot_,
272 min_filter_, mag_filter_, wrap_s_, wrap_t_,
276 void Texture::SetMailboxManager(MailboxManager* mailbox_manager) {
277 DCHECK(!mailbox_manager_ || mailbox_manager_ == mailbox_manager);
278 mailbox_manager_ = mailbox_manager;
281 bool Texture::MarkMipmapsGenerated(
282 const FeatureInfo* feature_info) {
283 if (!CanGenerateMipmaps(feature_info)) {
286 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
287 const Texture::LevelInfo& info1 = level_infos_[ii][0];
288 GLsizei width = info1.width;
289 GLsizei height = info1.height;
290 GLsizei depth = info1.depth;
291 GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
292 FaceIndexToGLTarget(ii);
294 TextureManager::ComputeMipMapCount(target_, width, height, depth);
295 for (int level = 1; level < num_mips; ++level) {
296 width = std::max(1, width >> 1);
297 height = std::max(1, height >> 1);
298 depth = std::max(1, depth >> 1);
299 SetLevelInfo(feature_info,
302 info1.internal_format,
316 void Texture::SetTarget(
317 const FeatureInfo* feature_info, GLenum target, GLint max_levels) {
318 DCHECK_EQ(0u, target_); // you can only set this once.
320 size_t num_faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
321 level_infos_.resize(num_faces);
322 for (size_t ii = 0; ii < num_faces; ++ii) {
323 level_infos_[ii].resize(max_levels);
326 if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) {
327 min_filter_ = GL_LINEAR;
328 wrap_s_ = wrap_t_ = GL_CLAMP_TO_EDGE;
331 if (target == GL_TEXTURE_EXTERNAL_OES) {
334 Update(feature_info);
335 UpdateCanRenderCondition();
338 bool Texture::CanGenerateMipmaps(
339 const FeatureInfo* feature_info) const {
340 if ((npot() && !feature_info->feature_flags().npot_ok) ||
341 level_infos_.empty() ||
342 target_ == GL_TEXTURE_EXTERNAL_OES ||
343 target_ == GL_TEXTURE_RECTANGLE_ARB) {
347 // Can't generate mips for depth or stencil textures.
348 const Texture::LevelInfo& first = level_infos_[0][0];
349 uint32 channels = GLES2Util::GetChannelsForFormat(first.format);
350 if (channels & (GLES2Util::kDepth | GLES2Util::kStencil)) {
354 // TODO(gman): Check internal_format, format and type.
355 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
356 const LevelInfo& info = level_infos_[ii][0];
357 if ((info.target == 0) || (info.width != first.width) ||
358 (info.height != first.height) || (info.depth != 1) ||
359 (info.format != first.format) ||
360 (info.internal_format != first.internal_format) ||
361 (info.type != first.type) ||
362 feature_info->validators()->compressed_texture_format.IsValid(
363 info.internal_format) ||
371 void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) {
373 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
374 level_infos_.size());
375 DCHECK_LT(static_cast<size_t>(level),
376 level_infos_[GLTargetToFaceIndex(target)].size());
377 Texture::LevelInfo& info =
378 level_infos_[GLTargetToFaceIndex(target)][level];
379 UpdateMipCleared(&info, cleared);
383 void Texture::UpdateCleared() {
384 if (level_infos_.empty()) {
388 const Texture::LevelInfo& first_face = level_infos_[0][0];
389 int levels_needed = TextureManager::ComputeMipMapCount(
390 target_, first_face.width, first_face.height, first_face.depth);
392 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
393 for (GLint jj = 0; jj < levels_needed; ++jj) {
394 const Texture::LevelInfo& info = level_infos_[ii][jj];
395 if (info.width > 0 && info.height > 0 && info.depth > 0 &&
402 UpdateSafeToRenderFrom(cleared);
405 void Texture::UpdateSafeToRenderFrom(bool cleared) {
406 if (cleared_ == cleared)
409 int delta = cleared ? -1 : +1;
410 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
411 (*it)->manager()->UpdateSafeToRenderFrom(delta);
414 void Texture::UpdateMipCleared(LevelInfo* info, bool cleared) {
415 if (info->cleared == cleared)
417 info->cleared = cleared;
418 int delta = cleared ? -1 : +1;
419 num_uncleared_mips_ += delta;
420 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
421 (*it)->manager()->UpdateUnclearedMips(delta);
424 void Texture::UpdateCanRenderCondition() {
425 CanRenderCondition can_render_condition = GetCanRenderCondition();
426 if (can_render_condition_ == can_render_condition)
428 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
429 (*it)->manager()->UpdateCanRenderCondition(can_render_condition_,
430 can_render_condition);
431 can_render_condition_ = can_render_condition;
434 void Texture::UpdateHasImages() {
435 if (level_infos_.empty())
438 bool has_images = false;
439 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
440 for (size_t jj = 0; jj < level_infos_[ii].size(); ++jj) {
441 const Texture::LevelInfo& info = level_infos_[ii][jj];
442 if (info.image.get() != NULL) {
449 if (has_images_ == has_images)
451 has_images_ = has_images;
452 int delta = has_images ? +1 : -1;
453 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
454 (*it)->manager()->UpdateNumImages(delta);
457 void Texture::IncAllFramebufferStateChangeCount() {
458 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
459 (*it)->manager()->IncFramebufferStateChangeCount();
462 void Texture::SetLevelInfo(
463 const FeatureInfo* feature_info,
466 GLenum internal_format,
475 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
476 level_infos_.size());
477 DCHECK_LT(static_cast<size_t>(level),
478 level_infos_[GLTargetToFaceIndex(target)].size());
480 DCHECK_GE(height, 0);
482 Texture::LevelInfo& info =
483 level_infos_[GLTargetToFaceIndex(target)][level];
484 info.target = target;
486 info.internal_format = internal_format;
488 info.height = height;
490 info.border = border;
491 info.format = format;
495 estimated_size_ -= info.estimated_size;
496 GLES2Util::ComputeImageDataSizes(
497 width, height, format, type, 4, &info.estimated_size, NULL, NULL);
498 estimated_size_ += info.estimated_size;
500 UpdateMipCleared(&info, cleared);
501 max_level_set_ = std::max(max_level_set_, level);
502 Update(feature_info);
504 UpdateCanRenderCondition();
506 if (IsAttachedToFramebuffer()) {
507 // TODO(gman): If textures tracked which framebuffers they were attached to
508 // we could just mark those framebuffers as not complete.
509 IncAllFramebufferStateChangeCount();
513 bool Texture::ValidForTexture(
521 size_t face_index = GLTargetToFaceIndex(target);
522 if (level >= 0 && face_index < level_infos_.size() &&
523 static_cast<size_t>(level) < level_infos_[face_index].size()) {
524 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
527 return SafeAddInt32(xoffset, width, &right) &&
528 SafeAddInt32(yoffset, height, &top) &&
531 right <= info.width &&
532 top <= info.height &&
538 bool Texture::GetLevelSize(
539 GLint target, GLint level, GLsizei* width, GLsizei* height) const {
542 size_t face_index = GLTargetToFaceIndex(target);
543 if (level >= 0 && face_index < level_infos_.size() &&
544 static_cast<size_t>(level) < level_infos_[face_index].size()) {
545 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
546 if (info.target != 0) {
548 *height = info.height;
555 bool Texture::GetLevelType(
556 GLint target, GLint level, GLenum* type, GLenum* internal_format) const {
558 DCHECK(internal_format);
559 size_t face_index = GLTargetToFaceIndex(target);
560 if (level >= 0 && face_index < level_infos_.size() &&
561 static_cast<size_t>(level) < level_infos_[face_index].size()) {
562 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
563 if (info.target != 0) {
565 *internal_format = info.internal_format;
572 GLenum Texture::SetParameter(
573 const FeatureInfo* feature_info, GLenum pname, GLint param) {
574 DCHECK(feature_info);
576 if (target_ == GL_TEXTURE_EXTERNAL_OES ||
577 target_ == GL_TEXTURE_RECTANGLE_ARB) {
578 if (pname == GL_TEXTURE_MIN_FILTER &&
579 (param != GL_NEAREST && param != GL_LINEAR))
580 return GL_INVALID_ENUM;
581 if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) &&
582 param != GL_CLAMP_TO_EDGE)
583 return GL_INVALID_ENUM;
587 case GL_TEXTURE_MIN_FILTER:
588 if (!feature_info->validators()->texture_min_filter_mode.IsValid(param)) {
589 return GL_INVALID_ENUM;
593 case GL_TEXTURE_MAG_FILTER:
594 if (!feature_info->validators()->texture_mag_filter_mode.IsValid(param)) {
595 return GL_INVALID_ENUM;
599 case GL_TEXTURE_POOL_CHROMIUM:
600 if (!feature_info->validators()->texture_pool.IsValid(param)) {
601 return GL_INVALID_ENUM;
603 GetMemTracker()->TrackMemFree(estimated_size());
605 GetMemTracker()->TrackMemAlloc(estimated_size());
607 case GL_TEXTURE_WRAP_S:
608 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
609 return GL_INVALID_ENUM;
613 case GL_TEXTURE_WRAP_T:
614 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
615 return GL_INVALID_ENUM;
619 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
621 return GL_INVALID_VALUE;
624 case GL_TEXTURE_USAGE_ANGLE:
625 if (!feature_info->validators()->texture_usage.IsValid(param)) {
626 return GL_INVALID_ENUM;
632 return GL_INVALID_ENUM;
634 Update(feature_info);
636 UpdateCanRenderCondition();
640 void Texture::Update(const FeatureInfo* feature_info) {
641 // Update npot status.
642 // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others
643 npot_ = target_ == GL_TEXTURE_EXTERNAL_OES;
645 if (level_infos_.empty()) {
646 texture_complete_ = false;
647 cube_complete_ = false;
651 // checks that the first mip of any face is npot.
652 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
653 const Texture::LevelInfo& info = level_infos_[ii][0];
654 if (GLES2Util::IsNPOT(info.width) ||
655 GLES2Util::IsNPOT(info.height) ||
656 GLES2Util::IsNPOT(info.depth)) {
662 // Update texture_complete and cube_complete status.
663 const Texture::LevelInfo& first_face = level_infos_[0][0];
664 int levels_needed = TextureManager::ComputeMipMapCount(
665 target_, first_face.width, first_face.height, first_face.depth);
667 max_level_set_ >= (levels_needed - 1) && max_level_set_ >= 0;
668 cube_complete_ = (level_infos_.size() == 6) &&
669 (first_face.width == first_face.height);
671 if (first_face.width == 0 || first_face.height == 0) {
672 texture_complete_ = false;
674 if (first_face.type == GL_FLOAT &&
675 !feature_info->feature_flags().enable_texture_float_linear &&
676 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
677 mag_filter_ != GL_NEAREST)) {
678 texture_complete_ = false;
679 } else if (first_face.type == GL_HALF_FLOAT_OES &&
680 !feature_info->feature_flags().enable_texture_half_float_linear &&
681 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
682 mag_filter_ != GL_NEAREST)) {
683 texture_complete_ = false;
686 ii < level_infos_.size() && (cube_complete_ || texture_complete_);
688 const Texture::LevelInfo& level0 = level_infos_[ii][0];
689 if (level0.target == 0 ||
690 level0.width != first_face.width ||
691 level0.height != first_face.height ||
693 level0.internal_format != first_face.internal_format ||
694 level0.format != first_face.format ||
695 level0.type != first_face.type) {
696 cube_complete_ = false;
698 // Get level0 dimensions
699 GLsizei width = level0.width;
700 GLsizei height = level0.height;
701 GLsizei depth = level0.depth;
702 for (GLint jj = 1; jj < levels_needed; ++jj) {
703 // compute required size for mip.
704 width = std::max(1, width >> 1);
705 height = std::max(1, height >> 1);
706 depth = std::max(1, depth >> 1);
707 const Texture::LevelInfo& info = level_infos_[ii][jj];
708 if (info.target == 0 ||
709 info.width != width ||
710 info.height != height ||
711 info.depth != depth ||
712 info.internal_format != level0.internal_format ||
713 info.format != level0.format ||
714 info.type != level0.type) {
715 texture_complete_ = false;
722 bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) {
728 const Texture::LevelInfo& first_face = level_infos_[0][0];
729 int levels_needed = TextureManager::ComputeMipMapCount(
730 target_, first_face.width, first_face.height, first_face.depth);
732 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
733 for (GLint jj = 0; jj < levels_needed; ++jj) {
734 Texture::LevelInfo& info = level_infos_[ii][jj];
735 if (info.target != 0) {
736 if (!ClearLevel(decoder, info.target, jj)) {
742 UpdateSafeToRenderFrom(true);
746 bool Texture::IsLevelCleared(GLenum target, GLint level) const {
747 size_t face_index = GLTargetToFaceIndex(target);
748 if (face_index >= level_infos_.size() ||
749 level >= static_cast<GLint>(level_infos_[face_index].size())) {
753 const Texture::LevelInfo& info = level_infos_[face_index][level];
758 bool Texture::ClearLevel(
759 GLES2Decoder* decoder, GLenum target, GLint level) {
761 size_t face_index = GLTargetToFaceIndex(target);
762 if (face_index >= level_infos_.size() ||
763 level >= static_cast<GLint>(level_infos_[face_index].size())) {
767 Texture::LevelInfo& info = level_infos_[face_index][level];
769 DCHECK(target == info.target);
771 if (info.target == 0 ||
779 // NOTE: It seems kind of gross to call back into the decoder for this
780 // but only the decoder knows all the state (like unpack_alignment_) that's
781 // needed to be able to call GL correctly.
782 bool cleared = decoder->ClearLevel(
783 service_id_, target_, info.target, info.level, info.format, info.type,
784 info.width, info.height, immutable_);
785 UpdateMipCleared(&info, cleared);
789 void Texture::SetLevelImage(
790 const FeatureInfo* feature_info,
793 gfx::GLImage* image) {
795 DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
796 level_infos_.size());
797 DCHECK_LT(static_cast<size_t>(level),
798 level_infos_[GLTargetToFaceIndex(target)].size());
799 Texture::LevelInfo& info =
800 level_infos_[GLTargetToFaceIndex(target)][level];
801 DCHECK_EQ(info.target, target);
802 DCHECK_EQ(info.level, level);
804 UpdateCanRenderCondition();
808 gfx::GLImage* Texture::GetLevelImage(GLint target, GLint level) const {
809 size_t face_index = GLTargetToFaceIndex(target);
810 if (level >= 0 && face_index < level_infos_.size() &&
811 static_cast<size_t>(level) < level_infos_[face_index].size()) {
812 const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
813 if (info.target != 0) {
814 return info.image.get();
821 TextureRef::TextureRef(TextureManager* manager,
826 client_id_(client_id) {
829 texture_->AddTextureRef(this);
830 manager_->StartTracking(this);
833 scoped_refptr<TextureRef> TextureRef::Create(TextureManager* manager,
836 return new TextureRef(manager, client_id, new Texture(service_id));
839 TextureRef::~TextureRef() {
840 manager_->StopTracking(this);
841 texture_->RemoveTextureRef(this, manager_->have_context_);
845 TextureManager::TextureManager(MemoryTracker* memory_tracker,
846 FeatureInfo* feature_info,
847 GLint max_texture_size,
848 GLint max_cube_map_texture_size)
849 : memory_tracker_managed_(new MemoryTypeTracker(memory_tracker,
850 MemoryTracker::kManaged)),
851 memory_tracker_unmanaged_(
852 new MemoryTypeTracker(memory_tracker, MemoryTracker::kUnmanaged)),
853 feature_info_(feature_info),
854 framebuffer_manager_(NULL),
855 max_texture_size_(max_texture_size),
856 max_cube_map_texture_size_(max_cube_map_texture_size),
857 max_levels_(ComputeMipMapCount(GL_TEXTURE_2D,
861 max_cube_map_levels_(ComputeMipMapCount(GL_TEXTURE_CUBE_MAP,
862 max_cube_map_texture_size,
863 max_cube_map_texture_size,
864 max_cube_map_texture_size)),
865 num_unrenderable_textures_(0),
866 num_unsafe_textures_(0),
867 num_uncleared_mips_(0),
870 have_context_(true) {
871 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
872 black_texture_ids_[ii] = 0;
876 bool TextureManager::Initialize() {
877 // TODO(gman): The default textures have to be real textures, not the 0
878 // texture because we simulate non shared resources on top of shared
879 // resources and all contexts that share resource share the same default
881 default_textures_[kTexture2D] = CreateDefaultAndBlackTextures(
882 GL_TEXTURE_2D, &black_texture_ids_[kTexture2D]);
883 default_textures_[kCubeMap] = CreateDefaultAndBlackTextures(
884 GL_TEXTURE_CUBE_MAP, &black_texture_ids_[kCubeMap]);
886 if (feature_info_->feature_flags().oes_egl_image_external) {
887 default_textures_[kExternalOES] = CreateDefaultAndBlackTextures(
888 GL_TEXTURE_EXTERNAL_OES, &black_texture_ids_[kExternalOES]);
891 if (feature_info_->feature_flags().arb_texture_rectangle) {
892 default_textures_[kRectangleARB] = CreateDefaultAndBlackTextures(
893 GL_TEXTURE_RECTANGLE_ARB, &black_texture_ids_[kRectangleARB]);
899 scoped_refptr<TextureRef>
900 TextureManager::CreateDefaultAndBlackTextures(
902 GLuint* black_texture) {
903 static uint8 black[] = {0, 0, 0, 255};
905 // Sampling a texture not associated with any EGLImage sibling will return
906 // black values according to the spec.
907 bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES);
908 bool needs_faces = (target == GL_TEXTURE_CUBE_MAP);
910 // Make default textures and texture for replacing non-renderable textures.
912 glGenTextures(arraysize(ids), ids);
913 for (unsigned long ii = 0; ii < arraysize(ids); ++ii) {
914 glBindTexture(target, ids[ii]);
915 if (needs_initialization) {
917 for (int jj = 0; jj < GLES2Util::kNumFaces; ++jj) {
918 glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj), 0, GL_RGBA, 1, 1, 0,
919 GL_RGBA, GL_UNSIGNED_BYTE, black);
922 glTexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA,
923 GL_UNSIGNED_BYTE, black);
927 glBindTexture(target, 0);
929 scoped_refptr<TextureRef> default_texture(
930 TextureRef::Create(this, 0, ids[1]));
931 SetTarget(default_texture.get(), target);
933 for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) {
934 SetLevelInfo(default_texture.get(),
935 GLES2Util::IndexToGLFaceTarget(ii),
947 if (needs_initialization) {
948 SetLevelInfo(default_texture.get(),
960 SetLevelInfo(default_texture.get(),
961 GL_TEXTURE_EXTERNAL_OES,
974 *black_texture = ids[0];
975 return default_texture;
978 bool TextureManager::ValidForTarget(
979 GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth) {
980 GLsizei max_size = MaxSizeForTarget(target) >> level;
985 level < MaxLevelsForTarget(target) &&
987 height <= max_size &&
989 (level == 0 || feature_info_->feature_flags().npot_ok ||
990 (!GLES2Util::IsNPOT(width) &&
991 !GLES2Util::IsNPOT(height) &&
992 !GLES2Util::IsNPOT(depth))) &&
993 (target != GL_TEXTURE_CUBE_MAP || (width == height && depth == 1)) &&
994 (target != GL_TEXTURE_2D || (depth == 1));
997 void TextureManager::SetTarget(TextureRef* ref, GLenum target) {
1000 ->SetTarget(feature_info_.get(), target, MaxLevelsForTarget(target));
1003 void TextureManager::SetLevelCleared(TextureRef* ref,
1008 ref->texture()->SetLevelCleared(target, level, cleared);
1011 bool TextureManager::ClearRenderableLevels(
1012 GLES2Decoder* decoder, TextureRef* ref) {
1014 return ref->texture()->ClearRenderableLevels(decoder);
1017 bool TextureManager::ClearTextureLevel(
1018 GLES2Decoder* decoder, TextureRef* ref,
1019 GLenum target, GLint level) {
1021 Texture* texture = ref->texture();
1022 if (texture->num_uncleared_mips() == 0) {
1025 bool result = texture->ClearLevel(decoder, target, level);
1026 texture->UpdateCleared();
1030 void TextureManager::SetLevelInfo(
1034 GLenum internal_format,
1043 Texture* texture = ref->texture();
1045 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1046 texture->SetLevelInfo(feature_info_.get(),
1057 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1060 Texture* TextureManager::Produce(TextureRef* ref) {
1062 return ref->texture();
1065 TextureRef* TextureManager::Consume(
1069 scoped_refptr<TextureRef> ref(new TextureRef(this, client_id, texture));
1070 bool result = textures_.insert(std::make_pair(client_id, ref)).second;
1075 void TextureManager::SetParameter(
1076 const char* function_name, ErrorState* error_state,
1077 TextureRef* ref, GLenum pname, GLint param) {
1078 DCHECK(error_state);
1080 Texture* texture = ref->texture();
1081 GLenum result = texture->SetParameter(feature_info_.get(), pname, param);
1082 if (result != GL_NO_ERROR) {
1083 if (result == GL_INVALID_ENUM) {
1084 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1085 error_state, function_name, param, "param");
1087 ERRORSTATE_SET_GL_ERROR_INVALID_PARAM(
1088 error_state, result, function_name, pname, static_cast<GLint>(param));
1091 // Texture tracking pools exist only for the command decoder, so
1092 // do not pass them on to the native GL implementation.
1093 if (pname != GL_TEXTURE_POOL_CHROMIUM) {
1094 glTexParameteri(texture->target(), pname, param);
1099 bool TextureManager::MarkMipmapsGenerated(TextureRef* ref) {
1101 Texture* texture = ref->texture();
1102 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1103 bool result = texture->MarkMipmapsGenerated(feature_info_.get());
1104 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1108 TextureRef* TextureManager::CreateTexture(
1109 GLuint client_id, GLuint service_id) {
1110 DCHECK_NE(0u, service_id);
1111 scoped_refptr<TextureRef> ref(TextureRef::Create(
1112 this, client_id, service_id));
1113 std::pair<TextureMap::iterator, bool> result =
1114 textures_.insert(std::make_pair(client_id, ref));
1115 DCHECK(result.second);
1119 TextureRef* TextureManager::GetTexture(
1120 GLuint client_id) const {
1121 TextureMap::const_iterator it = textures_.find(client_id);
1122 return it != textures_.end() ? it->second.get() : NULL;
1125 void TextureManager::RemoveTexture(GLuint client_id) {
1126 TextureMap::iterator it = textures_.find(client_id);
1127 if (it != textures_.end()) {
1128 it->second->reset_client_id();
1129 textures_.erase(it);
1133 void TextureManager::StartTracking(TextureRef* ref) {
1134 Texture* texture = ref->texture();
1136 num_uncleared_mips_ += texture->num_uncleared_mips();
1137 if (!texture->SafeToRenderFrom())
1138 ++num_unsafe_textures_;
1139 if (!texture->CanRender(feature_info_.get()))
1140 ++num_unrenderable_textures_;
1141 if (texture->HasImages())
1145 void TextureManager::StopTracking(TextureRef* ref) {
1146 FOR_EACH_OBSERVER(DestructionObserver,
1147 destruction_observers_,
1148 OnTextureRefDestroying(ref));
1150 Texture* texture = ref->texture();
1153 if (texture->HasImages()) {
1154 DCHECK_NE(0, num_images_);
1157 if (!texture->CanRender(feature_info_.get())) {
1158 DCHECK_NE(0, num_unrenderable_textures_);
1159 --num_unrenderable_textures_;
1161 if (!texture->SafeToRenderFrom()) {
1162 DCHECK_NE(0, num_unsafe_textures_);
1163 --num_unsafe_textures_;
1165 num_uncleared_mips_ -= texture->num_uncleared_mips();
1166 DCHECK_GE(num_uncleared_mips_, 0);
1169 MemoryTypeTracker* TextureManager::GetMemTracker(GLenum tracking_pool) {
1170 switch(tracking_pool) {
1171 case GL_TEXTURE_POOL_MANAGED_CHROMIUM:
1172 return memory_tracker_managed_.get();
1174 case GL_TEXTURE_POOL_UNMANAGED_CHROMIUM:
1175 return memory_tracker_unmanaged_.get();
1184 Texture* TextureManager::GetTextureForServiceId(GLuint service_id) const {
1185 // This doesn't need to be fast. It's only used during slow queries.
1186 for (TextureMap::const_iterator it = textures_.begin();
1187 it != textures_.end(); ++it) {
1188 Texture* texture = it->second->texture();
1189 if (texture->service_id() == service_id)
1195 GLsizei TextureManager::ComputeMipMapCount(GLenum target,
1200 case GL_TEXTURE_EXTERNAL_OES:
1204 base::bits::Log2Floor(std::max(std::max(width, height), depth));
1208 void TextureManager::SetLevelImage(
1212 gfx::GLImage* image) {
1214 ref->texture()->SetLevelImage(feature_info_.get(), target, level, image);
1217 void TextureManager::AddToSignature(
1221 std::string* signature) const {
1222 ref->texture()->AddToSignature(feature_info_.get(), target, level, signature);
1225 void TextureManager::UpdateSafeToRenderFrom(int delta) {
1226 num_unsafe_textures_ += delta;
1227 DCHECK_GE(num_unsafe_textures_, 0);
1230 void TextureManager::UpdateUnclearedMips(int delta) {
1231 num_uncleared_mips_ += delta;
1232 DCHECK_GE(num_uncleared_mips_, 0);
1235 void TextureManager::UpdateCanRenderCondition(
1236 Texture::CanRenderCondition old_condition,
1237 Texture::CanRenderCondition new_condition) {
1238 if (old_condition == Texture::CAN_RENDER_NEVER ||
1239 (old_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1240 !feature_info_->feature_flags().npot_ok)) {
1241 DCHECK_GT(num_unrenderable_textures_, 0);
1242 --num_unrenderable_textures_;
1244 if (new_condition == Texture::CAN_RENDER_NEVER ||
1245 (new_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1246 !feature_info_->feature_flags().npot_ok))
1247 ++num_unrenderable_textures_;
1250 void TextureManager::UpdateNumImages(int delta) {
1251 num_images_ += delta;
1252 DCHECK_GE(num_images_, 0);
1255 void TextureManager::IncFramebufferStateChangeCount() {
1256 if (framebuffer_manager_)
1257 framebuffer_manager_->IncFramebufferStateChangeCount();
1260 bool TextureManager::ValidateFormatAndTypeCombination(
1261 ErrorState* error_state, const char* function_name, GLenum format,
1263 if (!feature_info_->GetTextureFormatValidator(format).IsValid(type)) {
1264 ERRORSTATE_SET_GL_ERROR(
1265 error_state, GL_INVALID_OPERATION, function_name,
1266 (std::string("invalid type ") +
1267 GLES2Util::GetStringEnum(type) + " for format " +
1268 GLES2Util::GetStringEnum(format)).c_str());
1274 bool TextureManager::ValidateTextureParameters(
1275 ErrorState* error_state, const char* function_name,
1276 GLenum format, GLenum type, GLenum internal_format, GLint level) {
1277 const Validators* validators = feature_info_->validators();
1278 if (!validators->texture_format.IsValid(format)) {
1279 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1280 error_state, function_name, format, "format");
1283 if (!validators->pixel_type.IsValid(type)) {
1284 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1285 error_state, function_name, type, "type");
1288 if (format != internal_format &&
1289 !((internal_format == GL_RGBA32F && format == GL_RGBA) ||
1290 (internal_format == GL_RGB32F && format == GL_RGB))) {
1291 ERRORSTATE_SET_GL_ERROR(
1292 error_state, GL_INVALID_OPERATION, function_name,
1293 "format != internalformat");
1296 uint32 channels = GLES2Util::GetChannelsForFormat(format);
1297 if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) {
1298 ERRORSTATE_SET_GL_ERROR(
1299 error_state, GL_INVALID_OPERATION, function_name,
1300 (std::string("invalid format ") + GLES2Util::GetStringEnum(format) +
1301 " for level != 0").c_str());
1304 return ValidateFormatAndTypeCombination(error_state, function_name,
1308 // Gets the texture id for a given target.
1309 TextureRef* TextureManager::GetTextureInfoForTarget(
1310 ContextState* state, GLenum target) {
1311 TextureUnit& unit = state->texture_units[state->active_texture_unit];
1312 TextureRef* texture = NULL;
1315 texture = unit.bound_texture_2d.get();
1317 case GL_TEXTURE_CUBE_MAP:
1318 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1319 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1320 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1321 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1322 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1323 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1324 texture = unit.bound_texture_cube_map.get();
1326 case GL_TEXTURE_EXTERNAL_OES:
1327 texture = unit.bound_texture_external_oes.get();
1329 case GL_TEXTURE_RECTANGLE_ARB:
1330 texture = unit.bound_texture_rectangle_arb.get();
1339 TextureRef* TextureManager::GetTextureInfoForTargetUnlessDefault(
1340 ContextState* state, GLenum target) {
1341 TextureRef* texture = GetTextureInfoForTarget(state, target);
1344 if (texture == GetDefaultTextureInfo(target))
1349 bool TextureManager::ValidateTexImage2D(
1350 ContextState* state,
1351 const char* function_name,
1352 const DoTextImage2DArguments& args,
1353 TextureRef** texture_ref) {
1354 ErrorState* error_state = state->GetErrorState();
1355 const Validators* validators = feature_info_->validators();
1356 if (!validators->texture_target.IsValid(args.target)) {
1357 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1358 error_state, function_name, args.target, "target");
1361 if (!validators->texture_internal_format.IsValid(args.internal_format)) {
1362 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1363 error_state, function_name, args.internal_format,
1367 if (!ValidateTextureParameters(
1368 error_state, function_name, args.format, args.type,
1369 args.internal_format, args.level)) {
1372 if (!ValidForTarget(args.target, args.level, args.width, args.height, 1) ||
1374 ERRORSTATE_SET_GL_ERROR(
1375 error_state, GL_INVALID_VALUE, function_name,
1376 "dimensions out of range");
1379 if ((GLES2Util::GetChannelsForFormat(args.format) &
1380 (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && args.pixels) {
1381 ERRORSTATE_SET_GL_ERROR(
1382 error_state, GL_INVALID_OPERATION,
1383 function_name, "can not supply data for depth or stencil textures");
1387 TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target);
1388 if (!local_texture_ref) {
1389 ERRORSTATE_SET_GL_ERROR(
1390 error_state, GL_INVALID_OPERATION, function_name,
1391 "unknown texture for target");
1394 if (local_texture_ref->texture()->IsImmutable()) {
1395 ERRORSTATE_SET_GL_ERROR(
1396 error_state, GL_INVALID_OPERATION, function_name,
1397 "texture is immutable");
1401 // TODO - verify that using the managed vs unmanaged does not matter.
1402 // They both use the same MemoryTracker, and this call just re-routes
1404 if (!memory_tracker_managed_->EnsureGPUMemoryAvailable(args.pixels_size)) {
1405 ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, function_name,
1410 // Write the TextureReference since this is valid.
1411 *texture_ref = local_texture_ref;
1415 void TextureManager::ValidateAndDoTexImage2D(
1416 DecoderTextureState* texture_state,
1417 ContextState* state,
1418 DecoderFramebufferState* framebuffer_state,
1419 const DoTextImage2DArguments& args) {
1420 TextureRef* texture_ref;
1421 if (!ValidateTexImage2D(state, "glTexImage2D", args, &texture_ref)) {
1425 DoTexImage2D(texture_state, state->GetErrorState(), framebuffer_state,
1429 void TextureManager::DoTexImage2D(
1430 DecoderTextureState* texture_state,
1431 ErrorState* error_state,
1432 DecoderFramebufferState* framebuffer_state,
1433 TextureRef* texture_ref,
1434 const DoTextImage2DArguments& args) {
1435 Texture* texture = texture_ref->texture();
1436 GLsizei tex_width = 0;
1437 GLsizei tex_height = 0;
1438 GLenum tex_type = 0;
1439 GLenum tex_format = 0;
1440 bool level_is_same =
1441 texture->GetLevelSize(args.target, args.level, &tex_width, &tex_height) &&
1442 texture->GetLevelType(args.target, args.level, &tex_type, &tex_format) &&
1443 args.width == tex_width && args.height == tex_height &&
1444 args.type == tex_type && args.format == tex_format;
1446 if (level_is_same && !args.pixels) {
1447 // Just set the level texture but mark the texture as uncleared.
1450 args.target, args.level, args.internal_format, args.width, args.height,
1451 1, args.border, args.format, args.type, false);
1452 texture_state->tex_image_2d_failed = false;
1456 if (texture->IsAttachedToFramebuffer()) {
1457 framebuffer_state->clear_state_dirty = true;
1460 if (texture_state->texsubimage2d_faster_than_teximage2d &&
1461 level_is_same && args.pixels) {
1463 ScopedTextureUploadTimer timer(texture_state);
1464 glTexSubImage2D(args.target, args.level, 0, 0, args.width, args.height,
1465 args.format, args.type, args.pixels);
1467 SetLevelCleared(texture_ref, args.target, args.level, true);
1468 texture_state->tex_image_2d_failed = false;
1472 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glTexImage2D");
1474 ScopedTextureUploadTimer timer(texture_state);
1476 args.target, args.level, args.internal_format, args.width, args.height,
1477 args.border, args.format, args.type, args.pixels);
1479 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glTexImage2D");
1480 if (error == GL_NO_ERROR) {
1483 args.target, args.level, args.internal_format, args.width, args.height,
1484 1, args.border, args.format, args.type, args.pixels != NULL);
1485 texture_state->tex_image_2d_failed = false;
1489 ScopedTextureUploadTimer::ScopedTextureUploadTimer(
1490 DecoderTextureState* texture_state)
1491 : texture_state_(texture_state),
1492 begin_time_(base::TimeTicks::HighResNow()) {
1495 ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
1496 texture_state_->texture_upload_count++;
1497 texture_state_->total_texture_upload_time +=
1498 base::TimeTicks::HighResNow() - begin_time_;
1501 } // namespace gles2