Disable tab_switching.tough_energy_cases on Linux
[chromium-blink-merge.git] / gpu / command_buffer / service / texture_manager.cc
blob90b7d2a236bac599bb4ba8c2f967485f6de5963c
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 <algorithm>
8 #include <utility>
10 #include "base/bits.h"
11 #include "base/strings/stringprintf.h"
12 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
13 #include "gpu/command_buffer/service/context_state.h"
14 #include "gpu/command_buffer/service/error_state.h"
15 #include "gpu/command_buffer/service/feature_info.h"
16 #include "gpu/command_buffer/service/framebuffer_manager.h"
17 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
18 #include "gpu/command_buffer/service/mailbox_manager.h"
19 #include "gpu/command_buffer/service/memory_tracking.h"
20 #include "ui/gl/gl_implementation.h"
22 namespace gpu {
23 namespace gles2 {
25 // This should contain everything to uniquely identify a Texture.
26 static const char TextureTag[] = "|Texture|";
27 struct TextureSignature {
28 GLenum target_;
29 GLint level_;
30 GLenum min_filter_;
31 GLenum mag_filter_;
32 GLenum wrap_r_;
33 GLenum wrap_s_;
34 GLenum wrap_t_;
35 GLenum usage_;
36 GLenum internal_format_;
37 GLenum compare_func_;
38 GLenum compare_mode_;
39 GLsizei width_;
40 GLsizei height_;
41 GLsizei depth_;
42 GLfloat max_lod_;
43 GLfloat min_lod_;
44 GLint base_level_;
45 GLint border_;
46 GLint max_level_;
47 GLenum format_;
48 GLenum type_;
49 bool has_image_;
50 bool can_render_;
51 bool can_render_to_;
52 bool npot_;
54 // Since we will be hashing this signature structure, the padding must be
55 // zero initialized. Although the C++11 specifications specify that this is
56 // true, we will use a constructor with a memset to further enforce it instead
57 // of relying on compilers adhering to this deep dark corner specification.
58 TextureSignature(GLenum target,
59 GLint level,
60 GLenum min_filter,
61 GLenum mag_filter,
62 GLenum wrap_r,
63 GLenum wrap_s,
64 GLenum wrap_t,
65 GLenum usage,
66 GLenum internal_format,
67 GLenum compare_func,
68 GLenum compare_mode,
69 GLsizei width,
70 GLsizei height,
71 GLsizei depth,
72 GLfloat max_lod,
73 GLfloat min_lod,
74 GLint base_level,
75 GLint border,
76 GLint max_level,
77 GLenum format,
78 GLenum type,
79 bool has_image,
80 bool can_render,
81 bool can_render_to,
82 bool npot) {
83 memset(this, 0, sizeof(TextureSignature));
84 target_ = target;
85 level_ = level;
86 min_filter_ = min_filter;
87 mag_filter_ = mag_filter;
88 wrap_r_ = wrap_r;
89 wrap_s_ = wrap_s;
90 wrap_t_ = wrap_t;
91 usage_ = usage;
92 internal_format_ = internal_format;
93 compare_func_ = compare_func;
94 compare_mode_ = compare_mode;
95 width_ = width;
96 height_ = height;
97 depth_ = depth;
98 max_lod_ = max_lod;
99 min_lod_ = min_lod;
100 base_level_ = base_level;
101 border_ = border;
102 max_level_ = max_level;
103 format_ = format;
104 type_ = type;
105 has_image_ = has_image;
106 can_render_ = can_render;
107 can_render_to_ = can_render_to;
108 npot_ = npot;
112 TextureManager::DestructionObserver::DestructionObserver() {}
114 TextureManager::DestructionObserver::~DestructionObserver() {}
116 TextureManager::~TextureManager() {
117 for (unsigned int i = 0; i < destruction_observers_.size(); i++)
118 destruction_observers_[i]->OnTextureManagerDestroying(this);
120 DCHECK(textures_.empty());
122 // If this triggers, that means something is keeping a reference to
123 // a Texture belonging to this.
124 CHECK_EQ(texture_count_, 0u);
126 DCHECK_EQ(0, num_unrenderable_textures_);
127 DCHECK_EQ(0, num_unsafe_textures_);
128 DCHECK_EQ(0, num_uncleared_mips_);
129 DCHECK_EQ(0, num_images_);
132 void TextureManager::Destroy(bool have_context) {
133 have_context_ = have_context;
134 textures_.clear();
135 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
136 default_textures_[ii] = NULL;
139 if (have_context) {
140 glDeleteTextures(arraysize(black_texture_ids_), black_texture_ids_);
143 DCHECK_EQ(0u, memory_tracker_managed_->GetMemRepresented());
144 DCHECK_EQ(0u, memory_tracker_unmanaged_->GetMemRepresented());
147 Texture::Texture(GLuint service_id)
148 : mailbox_manager_(NULL),
149 memory_tracking_ref_(NULL),
150 service_id_(service_id),
151 cleared_(true),
152 num_uncleared_mips_(0),
153 num_npot_faces_(0),
154 target_(0),
155 min_filter_(GL_NEAREST_MIPMAP_LINEAR),
156 mag_filter_(GL_LINEAR),
157 wrap_r_(GL_REPEAT),
158 wrap_s_(GL_REPEAT),
159 wrap_t_(GL_REPEAT),
160 usage_(GL_NONE),
161 pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM),
162 compare_func_(GL_LEQUAL),
163 compare_mode_(GL_NONE),
164 max_lod_(1000.0f),
165 min_lod_(-1000.0f),
166 base_level_(0),
167 max_level_(1000),
168 max_level_set_(-1),
169 texture_complete_(false),
170 texture_mips_dirty_(false),
171 texture_mips_complete_(false),
172 cube_complete_(false),
173 texture_level0_dirty_(false),
174 texture_level0_complete_(false),
175 npot_(false),
176 has_been_bound_(false),
177 framebuffer_attachment_count_(0),
178 immutable_(false),
179 has_images_(false),
180 estimated_size_(0),
181 can_render_condition_(CAN_RENDER_ALWAYS),
182 texture_max_anisotropy_initialized_(false) {
185 Texture::~Texture() {
186 if (mailbox_manager_)
187 mailbox_manager_->TextureDeleted(this);
190 void Texture::AddTextureRef(TextureRef* ref) {
191 DCHECK(refs_.find(ref) == refs_.end());
192 refs_.insert(ref);
193 if (!memory_tracking_ref_) {
194 memory_tracking_ref_ = ref;
195 GetMemTracker()->TrackMemAlloc(estimated_size());
199 void Texture::RemoveTextureRef(TextureRef* ref, bool have_context) {
200 if (memory_tracking_ref_ == ref) {
201 GetMemTracker()->TrackMemFree(estimated_size());
202 memory_tracking_ref_ = NULL;
204 size_t result = refs_.erase(ref);
205 DCHECK_EQ(result, 1u);
206 if (refs_.empty()) {
207 if (have_context) {
208 GLuint id = service_id();
209 glDeleteTextures(1, &id);
211 delete this;
212 } else if (memory_tracking_ref_ == NULL) {
213 // TODO(piman): tune ownership semantics for cross-context group shared
214 // textures.
215 memory_tracking_ref_ = *refs_.begin();
216 GetMemTracker()->TrackMemAlloc(estimated_size());
220 MemoryTypeTracker* Texture::GetMemTracker() {
221 DCHECK(memory_tracking_ref_);
222 return memory_tracking_ref_->manager()->GetMemTracker(pool_);
225 Texture::LevelInfo::LevelInfo()
226 : cleared(true),
227 target(0),
228 level(-1),
229 internal_format(0),
230 width(0),
231 height(0),
232 depth(0),
233 border(0),
234 format(0),
235 type(0),
236 estimated_size(0) {
239 Texture::LevelInfo::LevelInfo(const LevelInfo& rhs)
240 : cleared(rhs.cleared),
241 target(rhs.target),
242 level(rhs.level),
243 internal_format(rhs.internal_format),
244 width(rhs.width),
245 height(rhs.height),
246 depth(rhs.depth),
247 border(rhs.border),
248 format(rhs.format),
249 type(rhs.type),
250 image(rhs.image),
251 estimated_size(rhs.estimated_size) {
254 Texture::LevelInfo::~LevelInfo() {
257 Texture::FaceInfo::FaceInfo()
258 : num_mip_levels(0) {
261 Texture::FaceInfo::~FaceInfo() {
264 Texture::CanRenderCondition Texture::GetCanRenderCondition() const {
265 if (target_ == 0)
266 return CAN_RENDER_ALWAYS;
268 if (target_ != GL_TEXTURE_EXTERNAL_OES) {
269 if (face_infos_.empty()) {
270 return CAN_RENDER_NEVER;
273 const Texture::LevelInfo& first_face = face_infos_[0].level_infos[0];
274 if (first_face.width == 0 ||
275 first_face.height == 0 ||
276 first_face.depth == 0) {
277 return CAN_RENDER_NEVER;
281 bool needs_mips = NeedsMips();
282 if (needs_mips) {
283 if (!texture_complete())
284 return CAN_RENDER_NEVER;
285 if (target_ == GL_TEXTURE_CUBE_MAP && !cube_complete())
286 return CAN_RENDER_NEVER;
289 bool is_npot_compatible = !needs_mips &&
290 wrap_s_ == GL_CLAMP_TO_EDGE &&
291 wrap_t_ == GL_CLAMP_TO_EDGE;
293 if (!is_npot_compatible) {
294 if (target_ == GL_TEXTURE_RECTANGLE_ARB)
295 return CAN_RENDER_NEVER;
296 else if (npot())
297 return CAN_RENDER_ONLY_IF_NPOT;
300 return CAN_RENDER_ALWAYS;
303 bool Texture::CanRender(const FeatureInfo* feature_info) const {
304 switch (can_render_condition_) {
305 case CAN_RENDER_ALWAYS:
306 return true;
307 case CAN_RENDER_NEVER:
308 return false;
309 case CAN_RENDER_ONLY_IF_NPOT:
310 break;
312 return feature_info->feature_flags().npot_ok;
315 void Texture::AddToSignature(
316 const FeatureInfo* feature_info,
317 GLenum target,
318 GLint level,
319 std::string* signature) const {
320 DCHECK(feature_info);
321 DCHECK(signature);
322 DCHECK_GE(level, 0);
323 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
324 DCHECK_LT(static_cast<size_t>(face_index),
325 face_infos_.size());
326 DCHECK_LT(static_cast<size_t>(level),
327 face_infos_[face_index].level_infos.size());
329 const Texture::LevelInfo& info =
330 face_infos_[face_index].level_infos[level];
332 TextureSignature signature_data(target,
333 level,
334 min_filter_,
335 mag_filter_,
336 wrap_r_,
337 wrap_s_,
338 wrap_t_,
339 usage_,
340 info.internal_format,
341 compare_func_,
342 compare_mode_,
343 info.width,
344 info.height,
345 info.depth,
346 max_lod_,
347 min_lod_,
348 base_level_,
349 info.border,
350 max_level_,
351 info.format,
352 info.type,
353 info.image.get() != NULL,
354 CanRender(feature_info),
355 CanRenderTo(),
356 npot_);
358 signature->append(TextureTag, sizeof(TextureTag));
359 signature->append(reinterpret_cast<const char*>(&signature_data),
360 sizeof(signature_data));
363 void Texture::SetMailboxManager(MailboxManager* mailbox_manager) {
364 DCHECK(!mailbox_manager_ || mailbox_manager_ == mailbox_manager);
365 mailbox_manager_ = mailbox_manager;
368 bool Texture::MarkMipmapsGenerated(
369 const FeatureInfo* feature_info) {
370 if (!CanGenerateMipmaps(feature_info)) {
371 return false;
373 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
374 const Texture::FaceInfo& face_info = face_infos_[ii];
375 const Texture::LevelInfo& level0_info = face_info.level_infos[0];
376 GLsizei width = level0_info.width;
377 GLsizei height = level0_info.height;
378 GLsizei depth = level0_info.depth;
379 GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
380 GLES2Util::IndexToGLFaceTarget(ii);
382 const GLsizei num_mips = face_info.num_mip_levels;
383 for (GLsizei level = 1; level < num_mips; ++level) {
384 width = std::max(1, width >> 1);
385 height = std::max(1, height >> 1);
386 depth = std::max(1, depth >> 1);
387 SetLevelInfo(feature_info,
388 target,
389 level,
390 level0_info.internal_format,
391 width,
392 height,
393 depth,
394 level0_info.border,
395 level0_info.format,
396 level0_info.type,
397 true);
401 return true;
404 void Texture::SetTarget(
405 const FeatureInfo* feature_info, GLenum target, GLint max_levels) {
406 DCHECK_EQ(0u, target_); // you can only set this once.
407 target_ = target;
408 size_t num_faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
409 face_infos_.resize(num_faces);
410 for (size_t ii = 0; ii < num_faces; ++ii) {
411 face_infos_[ii].level_infos.resize(max_levels);
414 if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) {
415 min_filter_ = GL_LINEAR;
416 wrap_s_ = wrap_t_ = GL_CLAMP_TO_EDGE;
419 if (target == GL_TEXTURE_EXTERNAL_OES) {
420 immutable_ = true;
422 Update(feature_info);
423 UpdateCanRenderCondition();
426 bool Texture::CanGenerateMipmaps(
427 const FeatureInfo* feature_info) const {
428 if ((npot() && !feature_info->feature_flags().npot_ok) ||
429 face_infos_.empty() ||
430 target_ == GL_TEXTURE_EXTERNAL_OES ||
431 target_ == GL_TEXTURE_RECTANGLE_ARB) {
432 return false;
435 // Can't generate mips for depth or stencil textures.
436 const Texture::LevelInfo& first = face_infos_[0].level_infos[0];
437 uint32 channels = GLES2Util::GetChannelsForFormat(first.format);
438 if (channels & (GLES2Util::kDepth | GLES2Util::kStencil)) {
439 return false;
442 // TODO(gman): Check internal_format, format and type.
443 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
444 const LevelInfo& info = face_infos_[ii].level_infos[0];
445 if ((info.target == 0) || (info.width != first.width) ||
446 (info.height != first.height) || (info.depth != 1) ||
447 (info.format != first.format) ||
448 (info.internal_format != first.internal_format) ||
449 (info.type != first.type) ||
450 feature_info->validators()->compressed_texture_format.IsValid(
451 info.internal_format) ||
452 info.image.get()) {
453 return false;
456 return true;
459 bool Texture::TextureIsNPOT(GLsizei width,
460 GLsizei height,
461 GLsizei depth) {
462 return (GLES2Util::IsNPOT(width) ||
463 GLES2Util::IsNPOT(height) ||
464 GLES2Util::IsNPOT(depth));
467 bool Texture::TextureFaceComplete(const Texture::LevelInfo& first_face,
468 size_t face_index,
469 GLenum target,
470 GLenum internal_format,
471 GLsizei width,
472 GLsizei height,
473 GLsizei depth,
474 GLenum format,
475 GLenum type) {
476 bool complete = (target != 0 && depth == 1);
477 if (face_index != 0) {
478 complete &= (width == first_face.width &&
479 height == first_face.height &&
480 internal_format == first_face.internal_format &&
481 format == first_face.format &&
482 type == first_face.type);
484 return complete;
487 bool Texture::TextureMipComplete(const Texture::LevelInfo& level0_face,
488 GLenum target,
489 GLint level,
490 GLenum internal_format,
491 GLsizei width,
492 GLsizei height,
493 GLsizei depth,
494 GLenum format,
495 GLenum type) {
496 bool complete = (target != 0);
497 if (level != 0) {
498 const GLsizei mip_width = std::max(1, level0_face.width >> level);
499 const GLsizei mip_height = std::max(1, level0_face.height >> level);
500 const GLsizei mip_depth = std::max(1, level0_face.depth >> level);
502 complete &= (width == mip_width &&
503 height == mip_height &&
504 depth == mip_depth &&
505 internal_format == level0_face.internal_format &&
506 format == level0_face.format &&
507 type == level0_face.type);
509 return complete;
512 void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) {
513 DCHECK_GE(level, 0);
514 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
515 DCHECK_LT(static_cast<size_t>(face_index),
516 face_infos_.size());
517 DCHECK_LT(static_cast<size_t>(level),
518 face_infos_[face_index].level_infos.size());
519 Texture::LevelInfo& info =
520 face_infos_[face_index].level_infos[level];
521 UpdateMipCleared(&info, cleared);
522 UpdateCleared();
525 void Texture::UpdateCleared() {
526 if (face_infos_.empty()) {
527 return;
530 const bool cleared = (num_uncleared_mips_ == 0);
532 // If texture is uncleared and is attached to a framebuffer,
533 // that framebuffer must be marked possibly incomplete.
534 if (!cleared && IsAttachedToFramebuffer()) {
535 IncAllFramebufferStateChangeCount();
538 UpdateSafeToRenderFrom(cleared);
541 void Texture::UpdateSafeToRenderFrom(bool cleared) {
542 if (cleared_ == cleared)
543 return;
544 cleared_ = cleared;
545 int delta = cleared ? -1 : +1;
546 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
547 (*it)->manager()->UpdateSafeToRenderFrom(delta);
550 void Texture::UpdateMipCleared(LevelInfo* info, bool cleared) {
551 if (info->cleared == cleared)
552 return;
553 info->cleared = cleared;
554 int delta = cleared ? -1 : +1;
555 num_uncleared_mips_ += delta;
556 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
557 (*it)->manager()->UpdateUnclearedMips(delta);
560 void Texture::UpdateCanRenderCondition() {
561 CanRenderCondition can_render_condition = GetCanRenderCondition();
562 if (can_render_condition_ == can_render_condition)
563 return;
564 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
565 (*it)->manager()->UpdateCanRenderCondition(can_render_condition_,
566 can_render_condition);
567 can_render_condition_ = can_render_condition;
570 void Texture::UpdateHasImages() {
571 if (face_infos_.empty())
572 return;
574 bool has_images = false;
575 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
576 for (size_t jj = 0; jj < face_infos_[ii].level_infos.size(); ++jj) {
577 const Texture::LevelInfo& info = face_infos_[ii].level_infos[jj];
578 if (info.image.get() != NULL) {
579 has_images = true;
580 break;
585 if (has_images_ == has_images)
586 return;
587 has_images_ = has_images;
588 int delta = has_images ? +1 : -1;
589 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
590 (*it)->manager()->UpdateNumImages(delta);
593 void Texture::IncAllFramebufferStateChangeCount() {
594 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
595 (*it)->manager()->IncFramebufferStateChangeCount();
598 void Texture::SetLevelInfo(
599 const FeatureInfo* feature_info,
600 GLenum target,
601 GLint level,
602 GLenum internal_format,
603 GLsizei width,
604 GLsizei height,
605 GLsizei depth,
606 GLint border,
607 GLenum format,
608 GLenum type,
609 bool cleared) {
610 DCHECK_GE(level, 0);
611 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
612 DCHECK_LT(static_cast<size_t>(face_index),
613 face_infos_.size());
614 DCHECK_LT(static_cast<size_t>(level),
615 face_infos_[face_index].level_infos.size());
616 DCHECK_GE(width, 0);
617 DCHECK_GE(height, 0);
618 DCHECK_GE(depth, 0);
619 Texture::LevelInfo& info =
620 face_infos_[face_index].level_infos[level];
622 // Update counters only if any attributes have changed. Counters are
623 // comparisons between the old and new values so it must be done before any
624 // assignment has been done to the LevelInfo.
625 if (info.target != target ||
626 info.internal_format != internal_format ||
627 info.width != width ||
628 info.height != height ||
629 info.depth != depth ||
630 info.format != format ||
631 info.type != type) {
632 if (level == 0) {
633 // Calculate the mip level count.
634 face_infos_[face_index].num_mip_levels =
635 TextureManager::ComputeMipMapCount(target_, width, height, depth);
637 // Update NPOT face count for the first level.
638 bool prev_npot = TextureIsNPOT(info.width, info.height, info.depth);
639 bool now_npot = TextureIsNPOT(width, height, depth);
640 if (prev_npot != now_npot)
641 num_npot_faces_ += now_npot ? 1 : -1;
643 // Signify that level 0 has been changed, so they need to be reverified.
644 texture_level0_dirty_ = true;
647 // Signify that at least one of the mips has changed.
648 texture_mips_dirty_ = true;
651 info.target = target;
652 info.level = level;
653 info.internal_format = internal_format;
654 info.width = width;
655 info.height = height;
656 info.depth = depth;
657 info.border = border;
658 info.format = format;
659 info.type = type;
660 info.image = 0;
662 estimated_size_ -= info.estimated_size;
663 GLES2Util::ComputeImageDataSizes(
664 width, height, 1, format, type, 4, &info.estimated_size, NULL, NULL);
665 estimated_size_ += info.estimated_size;
667 UpdateMipCleared(&info, cleared);
668 max_level_set_ = std::max(max_level_set_, level);
669 Update(feature_info);
670 UpdateCleared();
671 UpdateCanRenderCondition();
672 UpdateHasImages();
673 if (IsAttachedToFramebuffer()) {
674 // TODO(gman): If textures tracked which framebuffers they were attached to
675 // we could just mark those framebuffers as not complete.
676 IncAllFramebufferStateChangeCount();
680 bool Texture::ValidForTexture(
681 GLint target,
682 GLint level,
683 GLint xoffset,
684 GLint yoffset,
685 GLint zoffset,
686 GLsizei width,
687 GLsizei height,
688 GLsizei depth,
689 GLenum type) const {
690 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
691 if (level >= 0 && face_index < face_infos_.size() &&
692 static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
693 const LevelInfo& info = face_infos_[face_index].level_infos[level];
694 int32 max_x;
695 int32 max_y;
696 int32 max_z;
697 return SafeAddInt32(xoffset, width, &max_x) &&
698 SafeAddInt32(yoffset, height, &max_y) &&
699 SafeAddInt32(zoffset, depth, &max_z) &&
700 xoffset >= 0 &&
701 yoffset >= 0 &&
702 zoffset >= 0 &&
703 max_x <= info.width &&
704 max_y <= info.height &&
705 max_z <= info.depth &&
706 type == info.type;
708 return false;
711 bool Texture::GetLevelSize(
712 GLint target, GLint level,
713 GLsizei* width, GLsizei* height, GLsizei* depth) const {
714 DCHECK(width);
715 DCHECK(height);
716 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
717 if (level >= 0 && face_index < face_infos_.size() &&
718 static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
719 const LevelInfo& info = face_infos_[face_index].level_infos[level];
720 if (info.target != 0) {
721 *width = info.width;
722 *height = info.height;
723 if (depth)
724 *depth = info.depth;
725 return true;
728 return false;
731 bool Texture::GetLevelType(
732 GLint target, GLint level, GLenum* type, GLenum* internal_format) const {
733 DCHECK(type);
734 DCHECK(internal_format);
735 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
736 if (level >= 0 && face_index < face_infos_.size() &&
737 static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
738 const LevelInfo& info = face_infos_[face_index].level_infos[level];
739 if (info.target != 0) {
740 *type = info.type;
741 *internal_format = info.internal_format;
742 return true;
745 return false;
748 GLenum Texture::SetParameteri(
749 const FeatureInfo* feature_info, GLenum pname, GLint param) {
750 DCHECK(feature_info);
752 if (target_ == GL_TEXTURE_EXTERNAL_OES ||
753 target_ == GL_TEXTURE_RECTANGLE_ARB) {
754 if (pname == GL_TEXTURE_MIN_FILTER &&
755 (param != GL_NEAREST && param != GL_LINEAR))
756 return GL_INVALID_ENUM;
757 if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) &&
758 param != GL_CLAMP_TO_EDGE)
759 return GL_INVALID_ENUM;
762 switch (pname) {
763 case GL_TEXTURE_MIN_FILTER:
764 if (!feature_info->validators()->texture_min_filter_mode.IsValid(param)) {
765 return GL_INVALID_ENUM;
767 min_filter_ = param;
768 break;
769 case GL_TEXTURE_MAG_FILTER:
770 if (!feature_info->validators()->texture_mag_filter_mode.IsValid(param)) {
771 return GL_INVALID_ENUM;
773 mag_filter_ = param;
774 break;
775 case GL_TEXTURE_POOL_CHROMIUM:
776 if (!feature_info->validators()->texture_pool.IsValid(param)) {
777 return GL_INVALID_ENUM;
779 GetMemTracker()->TrackMemFree(estimated_size());
780 pool_ = param;
781 GetMemTracker()->TrackMemAlloc(estimated_size());
782 break;
783 case GL_TEXTURE_WRAP_R:
784 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
785 return GL_INVALID_ENUM;
787 wrap_r_ = param;
788 break;
789 case GL_TEXTURE_WRAP_S:
790 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
791 return GL_INVALID_ENUM;
793 wrap_s_ = param;
794 break;
795 case GL_TEXTURE_WRAP_T:
796 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
797 return GL_INVALID_ENUM;
799 wrap_t_ = param;
800 break;
801 case GL_TEXTURE_COMPARE_FUNC:
802 if (!feature_info->validators()->texture_compare_func.IsValid(param)) {
803 return GL_INVALID_ENUM;
805 compare_func_ = param;
806 break;
807 case GL_TEXTURE_COMPARE_MODE:
808 if (!feature_info->validators()->texture_compare_mode.IsValid(param)) {
809 return GL_INVALID_ENUM;
811 compare_mode_ = param;
812 break;
813 case GL_TEXTURE_BASE_LEVEL:
814 if (param < 0) {
815 return GL_INVALID_VALUE;
817 base_level_ = param;
818 break;
819 case GL_TEXTURE_MAX_LEVEL:
820 if (param < 0) {
821 return GL_INVALID_VALUE;
823 max_level_ = param;
824 break;
825 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
826 if (param < 1) {
827 return GL_INVALID_VALUE;
829 break;
830 case GL_TEXTURE_USAGE_ANGLE:
831 if (!feature_info->validators()->texture_usage.IsValid(param)) {
832 return GL_INVALID_ENUM;
834 usage_ = param;
835 break;
836 default:
837 NOTREACHED();
838 return GL_INVALID_ENUM;
840 Update(feature_info);
841 UpdateCleared();
842 UpdateCanRenderCondition();
843 return GL_NO_ERROR;
846 GLenum Texture::SetParameterf(
847 const FeatureInfo* feature_info, GLenum pname, GLfloat param) {
848 switch (pname) {
849 case GL_TEXTURE_MIN_FILTER:
850 case GL_TEXTURE_MAG_FILTER:
851 case GL_TEXTURE_POOL_CHROMIUM:
852 case GL_TEXTURE_WRAP_S:
853 case GL_TEXTURE_WRAP_T:
854 case GL_TEXTURE_USAGE_ANGLE:
856 GLint iparam = static_cast<GLint>(param);
857 return SetParameteri(feature_info, pname, iparam);
859 case GL_TEXTURE_MIN_LOD:
860 min_lod_ = param;
861 break;
862 case GL_TEXTURE_MAX_LOD:
863 max_lod_ = param;
864 break;
865 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
866 if (param < 1.f) {
867 return GL_INVALID_VALUE;
869 break;
870 default:
871 NOTREACHED();
872 return GL_INVALID_ENUM;
874 return GL_NO_ERROR;
877 void Texture::Update(const FeatureInfo* feature_info) {
878 // Update npot status.
879 // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others
880 npot_ = (target_ == GL_TEXTURE_EXTERNAL_OES) || (num_npot_faces_ > 0);
882 if (face_infos_.empty()) {
883 texture_complete_ = false;
884 cube_complete_ = false;
885 return;
888 // Update texture_complete and cube_complete status.
889 const Texture::FaceInfo& first_face = face_infos_[0];
890 const Texture::LevelInfo& first_level = first_face.level_infos[0];
891 const GLsizei levels_needed = first_face.num_mip_levels;
893 texture_complete_ =
894 max_level_set_ >= (levels_needed - 1) && max_level_set_ >= 0;
895 cube_complete_ = (face_infos_.size() == 6) &&
896 (first_level.width == first_level.height);
898 if (first_level.width == 0 || first_level.height == 0) {
899 texture_complete_ = false;
900 } else if (first_level.type == GL_FLOAT &&
901 !feature_info->feature_flags().enable_texture_float_linear &&
902 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
903 mag_filter_ != GL_NEAREST)) {
904 texture_complete_ = false;
905 } else if (first_level.type == GL_HALF_FLOAT_OES &&
906 !feature_info->feature_flags().enable_texture_half_float_linear &&
907 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
908 mag_filter_ != GL_NEAREST)) {
909 texture_complete_ = false;
912 if (cube_complete_ && texture_level0_dirty_) {
913 texture_level0_complete_ = true;
914 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
915 const Texture::LevelInfo& level0 = face_infos_[ii].level_infos[0];
916 if (!TextureFaceComplete(first_level,
918 level0.target,
919 level0.internal_format,
920 level0.width,
921 level0.height,
922 level0.depth,
923 level0.format,
924 level0.type)) {
925 texture_level0_complete_ = false;
926 break;
929 texture_level0_dirty_ = false;
931 cube_complete_ &= texture_level0_complete_;
933 if (texture_complete_ && texture_mips_dirty_) {
934 texture_mips_complete_ = true;
935 for (size_t ii = 0;
936 ii < face_infos_.size() && texture_mips_complete_;
937 ++ii) {
938 const Texture::FaceInfo& face_info = face_infos_[ii];
939 const Texture::LevelInfo& level0 = face_info.level_infos[0];
940 for (GLsizei jj = 1; jj < levels_needed; ++jj) {
941 const Texture::LevelInfo& level_info = face_infos_[ii].level_infos[jj];
942 if (!TextureMipComplete(level0,
943 level_info.target,
945 level_info.internal_format,
946 level_info.width,
947 level_info.height,
948 level_info.depth,
949 level_info.format,
950 level_info.type)) {
951 texture_mips_complete_ = false;
952 break;
956 texture_mips_dirty_ = false;
958 texture_complete_ &= texture_mips_complete_;
961 bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) {
962 DCHECK(decoder);
963 if (cleared_) {
964 return true;
967 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
968 const Texture::FaceInfo& face_info = face_infos_[ii];
969 for (GLint jj = 0; jj < face_info.num_mip_levels; ++jj) {
970 const Texture::LevelInfo& info = face_info.level_infos[jj];
971 if (info.target != 0) {
972 if (!ClearLevel(decoder, info.target, jj)) {
973 return false;
978 UpdateSafeToRenderFrom(true);
979 return true;
982 bool Texture::IsLevelCleared(GLenum target, GLint level) const {
983 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
984 if (face_index >= face_infos_.size() ||
985 level >= static_cast<GLint>(face_infos_[face_index].level_infos.size())) {
986 return true;
989 const Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
991 return info.cleared;
994 void Texture::InitTextureMaxAnisotropyIfNeeded(GLenum target) {
995 if (texture_max_anisotropy_initialized_)
996 return;
997 texture_max_anisotropy_initialized_ = true;
998 GLfloat params[] = { 1.0f };
999 glTexParameterfv(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, params);
1002 bool Texture::ClearLevel(
1003 GLES2Decoder* decoder, GLenum target, GLint level) {
1004 DCHECK(decoder);
1005 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
1006 if (face_index >= face_infos_.size() ||
1007 level >= static_cast<GLint>(face_infos_[face_index].level_infos.size())) {
1008 return true;
1011 Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
1013 DCHECK(target == info.target);
1015 if (info.target == 0 ||
1016 info.cleared ||
1017 info.width == 0 ||
1018 info.height == 0 ||
1019 info.depth == 0) {
1020 return true;
1023 // NOTE: It seems kind of gross to call back into the decoder for this
1024 // but only the decoder knows all the state (like unpack_alignment_) that's
1025 // needed to be able to call GL correctly.
1026 bool cleared = decoder->ClearLevel(
1027 this, info.target, info.level, info.internal_format, info.format,
1028 info.type, info.width, info.height, immutable_);
1029 UpdateMipCleared(&info, cleared);
1030 return info.cleared;
1033 void Texture::SetLevelImage(
1034 const FeatureInfo* feature_info,
1035 GLenum target,
1036 GLint level,
1037 gfx::GLImage* image) {
1038 DCHECK_GE(level, 0);
1039 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
1040 DCHECK_LT(static_cast<size_t>(face_index),
1041 face_infos_.size());
1042 DCHECK_LT(static_cast<size_t>(level),
1043 face_infos_[face_index].level_infos.size());
1044 Texture::LevelInfo& info =
1045 face_infos_[face_index].level_infos[level];
1046 DCHECK_EQ(info.target, target);
1047 DCHECK_EQ(info.level, level);
1048 info.image = image;
1049 UpdateCanRenderCondition();
1050 UpdateHasImages();
1053 gfx::GLImage* Texture::GetLevelImage(GLint target, GLint level) const {
1054 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES &&
1055 target != GL_TEXTURE_RECTANGLE_ARB) {
1056 return NULL;
1059 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
1060 if (level >= 0 && face_index < face_infos_.size() &&
1061 static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
1062 const LevelInfo& info = face_infos_[face_index].level_infos[level];
1063 if (info.target != 0) {
1064 return info.image.get();
1067 return NULL;
1070 void Texture::OnWillModifyPixels() {
1071 gfx::GLImage* image = GetLevelImage(target(), 0);
1072 if (image)
1073 image->WillModifyTexImage();
1076 void Texture::OnDidModifyPixels() {
1077 gfx::GLImage* image = GetLevelImage(target(), 0);
1078 if (image)
1079 image->DidModifyTexImage();
1082 TextureRef::TextureRef(TextureManager* manager,
1083 GLuint client_id,
1084 Texture* texture)
1085 : manager_(manager),
1086 texture_(texture),
1087 client_id_(client_id),
1088 num_observers_(0) {
1089 DCHECK(manager_);
1090 DCHECK(texture_);
1091 texture_->AddTextureRef(this);
1092 manager_->StartTracking(this);
1095 scoped_refptr<TextureRef> TextureRef::Create(TextureManager* manager,
1096 GLuint client_id,
1097 GLuint service_id) {
1098 return new TextureRef(manager, client_id, new Texture(service_id));
1101 TextureRef::~TextureRef() {
1102 manager_->StopTracking(this);
1103 texture_->RemoveTextureRef(this, manager_->have_context_);
1104 manager_ = NULL;
1107 TextureManager::TextureManager(MemoryTracker* memory_tracker,
1108 FeatureInfo* feature_info,
1109 GLint max_texture_size,
1110 GLint max_cube_map_texture_size,
1111 GLint max_rectangle_texture_size,
1112 GLint max_3d_texture_size,
1113 bool use_default_textures)
1114 : memory_tracker_managed_(
1115 new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)),
1116 memory_tracker_unmanaged_(
1117 new MemoryTypeTracker(memory_tracker, MemoryTracker::kUnmanaged)),
1118 feature_info_(feature_info),
1119 framebuffer_manager_(NULL),
1120 max_texture_size_(max_texture_size),
1121 max_cube_map_texture_size_(max_cube_map_texture_size),
1122 max_rectangle_texture_size_(max_rectangle_texture_size),
1123 max_3d_texture_size_(max_3d_texture_size),
1124 max_levels_(ComputeMipMapCount(GL_TEXTURE_2D,
1125 max_texture_size,
1126 max_texture_size,
1127 max_texture_size)),
1128 max_cube_map_levels_(ComputeMipMapCount(GL_TEXTURE_CUBE_MAP,
1129 max_cube_map_texture_size,
1130 max_cube_map_texture_size,
1131 max_cube_map_texture_size)),
1132 max_3d_levels_(ComputeMipMapCount(GL_TEXTURE_3D,
1133 // Same as GL_TEXTURE_2D_ARRAY
1134 max_3d_texture_size,
1135 max_3d_texture_size,
1136 max_3d_texture_size)),
1137 use_default_textures_(use_default_textures),
1138 num_unrenderable_textures_(0),
1139 num_unsafe_textures_(0),
1140 num_uncleared_mips_(0),
1141 num_images_(0),
1142 texture_count_(0),
1143 have_context_(true) {
1144 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
1145 black_texture_ids_[ii] = 0;
1149 bool TextureManager::Initialize() {
1150 // TODO(gman): The default textures have to be real textures, not the 0
1151 // texture because we simulate non shared resources on top of shared
1152 // resources and all contexts that share resource share the same default
1153 // texture.
1154 default_textures_[kTexture2D] = CreateDefaultAndBlackTextures(
1155 GL_TEXTURE_2D, &black_texture_ids_[kTexture2D]);
1156 default_textures_[kCubeMap] = CreateDefaultAndBlackTextures(
1157 GL_TEXTURE_CUBE_MAP, &black_texture_ids_[kCubeMap]);
1159 if (feature_info_->feature_flags().oes_egl_image_external) {
1160 default_textures_[kExternalOES] = CreateDefaultAndBlackTextures(
1161 GL_TEXTURE_EXTERNAL_OES, &black_texture_ids_[kExternalOES]);
1164 if (feature_info_->feature_flags().arb_texture_rectangle) {
1165 default_textures_[kRectangleARB] = CreateDefaultAndBlackTextures(
1166 GL_TEXTURE_RECTANGLE_ARB, &black_texture_ids_[kRectangleARB]);
1169 return true;
1172 scoped_refptr<TextureRef>
1173 TextureManager::CreateDefaultAndBlackTextures(
1174 GLenum target,
1175 GLuint* black_texture) {
1176 static uint8 black[] = {0, 0, 0, 255};
1178 // Sampling a texture not associated with any EGLImage sibling will return
1179 // black values according to the spec.
1180 bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES);
1181 bool needs_faces = (target == GL_TEXTURE_CUBE_MAP);
1183 // Make default textures and texture for replacing non-renderable textures.
1184 GLuint ids[2];
1185 const int num_ids = use_default_textures_ ? 2 : 1;
1186 glGenTextures(num_ids, ids);
1187 for (int ii = 0; ii < num_ids; ++ii) {
1188 glBindTexture(target, ids[ii]);
1189 if (needs_initialization) {
1190 if (needs_faces) {
1191 for (int jj = 0; jj < GLES2Util::kNumFaces; ++jj) {
1192 glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj), 0, GL_RGBA, 1, 1, 0,
1193 GL_RGBA, GL_UNSIGNED_BYTE, black);
1195 } else {
1196 glTexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA,
1197 GL_UNSIGNED_BYTE, black);
1201 glBindTexture(target, 0);
1203 scoped_refptr<TextureRef> default_texture;
1204 if (use_default_textures_) {
1205 default_texture = TextureRef::Create(this, 0, ids[1]);
1206 SetTarget(default_texture.get(), target);
1207 if (needs_faces) {
1208 for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) {
1209 SetLevelInfo(default_texture.get(),
1210 GLES2Util::IndexToGLFaceTarget(ii),
1212 GL_RGBA,
1217 GL_RGBA,
1218 GL_UNSIGNED_BYTE,
1219 true);
1221 } else {
1222 if (needs_initialization) {
1223 SetLevelInfo(default_texture.get(),
1224 GL_TEXTURE_2D,
1226 GL_RGBA,
1231 GL_RGBA,
1232 GL_UNSIGNED_BYTE,
1233 true);
1234 } else {
1235 SetLevelInfo(default_texture.get(),
1236 GL_TEXTURE_EXTERNAL_OES,
1238 GL_RGBA,
1243 GL_RGBA,
1244 GL_UNSIGNED_BYTE,
1245 true);
1250 *black_texture = ids[0];
1251 return default_texture;
1254 bool TextureManager::ValidForTarget(
1255 GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth) {
1256 GLsizei max_size = MaxSizeForTarget(target) >> level;
1257 return level >= 0 &&
1258 width >= 0 &&
1259 height >= 0 &&
1260 depth >= 0 &&
1261 level < MaxLevelsForTarget(target) &&
1262 width <= max_size &&
1263 height <= max_size &&
1264 depth <= max_size &&
1265 (level == 0 || feature_info_->feature_flags().npot_ok ||
1266 (!GLES2Util::IsNPOT(width) &&
1267 !GLES2Util::IsNPOT(height) &&
1268 !GLES2Util::IsNPOT(depth))) &&
1269 (target != GL_TEXTURE_CUBE_MAP || (width == height && depth == 1)) &&
1270 (target != GL_TEXTURE_2D || (depth == 1));
1273 void TextureManager::SetTarget(TextureRef* ref, GLenum target) {
1274 DCHECK(ref);
1275 ref->texture()
1276 ->SetTarget(feature_info_.get(), target, MaxLevelsForTarget(target));
1279 void TextureManager::SetLevelCleared(TextureRef* ref,
1280 GLenum target,
1281 GLint level,
1282 bool cleared) {
1283 DCHECK(ref);
1284 ref->texture()->SetLevelCleared(target, level, cleared);
1287 bool TextureManager::ClearRenderableLevels(
1288 GLES2Decoder* decoder, TextureRef* ref) {
1289 DCHECK(ref);
1290 return ref->texture()->ClearRenderableLevels(decoder);
1293 bool TextureManager::ClearTextureLevel(
1294 GLES2Decoder* decoder, TextureRef* ref,
1295 GLenum target, GLint level) {
1296 DCHECK(ref);
1297 Texture* texture = ref->texture();
1298 if (texture->num_uncleared_mips() == 0) {
1299 return true;
1301 bool result = texture->ClearLevel(decoder, target, level);
1302 texture->UpdateCleared();
1303 return result;
1306 void TextureManager::SetLevelInfo(
1307 TextureRef* ref,
1308 GLenum target,
1309 GLint level,
1310 GLenum internal_format,
1311 GLsizei width,
1312 GLsizei height,
1313 GLsizei depth,
1314 GLint border,
1315 GLenum format,
1316 GLenum type,
1317 bool cleared) {
1318 DCHECK(ref);
1319 Texture* texture = ref->texture();
1321 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1322 texture->SetLevelInfo(feature_info_.get(),
1323 target,
1324 level,
1325 internal_format,
1326 width,
1327 height,
1328 depth,
1329 border,
1330 format,
1331 type,
1332 cleared);
1333 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1336 Texture* TextureManager::Produce(TextureRef* ref) {
1337 DCHECK(ref);
1338 return ref->texture();
1341 TextureRef* TextureManager::Consume(
1342 GLuint client_id,
1343 Texture* texture) {
1344 DCHECK(client_id);
1345 scoped_refptr<TextureRef> ref(new TextureRef(this, client_id, texture));
1346 bool result = textures_.insert(std::make_pair(client_id, ref)).second;
1347 DCHECK(result);
1348 return ref.get();
1351 void TextureManager::SetParameteri(
1352 const char* function_name, ErrorState* error_state,
1353 TextureRef* ref, GLenum pname, GLint param) {
1354 DCHECK(error_state);
1355 DCHECK(ref);
1356 Texture* texture = ref->texture();
1357 GLenum result = texture->SetParameteri(feature_info_.get(), pname, param);
1358 if (result != GL_NO_ERROR) {
1359 if (result == GL_INVALID_ENUM) {
1360 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1361 error_state, function_name, param, "param");
1362 } else {
1363 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMI(
1364 error_state, result, function_name, pname, param);
1366 } else {
1367 // Texture tracking pools exist only for the command decoder, so
1368 // do not pass them on to the native GL implementation.
1369 if (pname != GL_TEXTURE_POOL_CHROMIUM) {
1370 glTexParameteri(texture->target(), pname, param);
1375 void TextureManager::SetParameterf(
1376 const char* function_name, ErrorState* error_state,
1377 TextureRef* ref, GLenum pname, GLfloat param) {
1378 DCHECK(error_state);
1379 DCHECK(ref);
1380 Texture* texture = ref->texture();
1381 GLenum result = texture->SetParameterf(feature_info_.get(), pname, param);
1382 if (result != GL_NO_ERROR) {
1383 if (result == GL_INVALID_ENUM) {
1384 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1385 error_state, function_name, pname, "pname");
1386 } else {
1387 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMF(
1388 error_state, result, function_name, pname, param);
1390 } else {
1391 // Texture tracking pools exist only for the command decoder, so
1392 // do not pass them on to the native GL implementation.
1393 if (pname != GL_TEXTURE_POOL_CHROMIUM) {
1394 glTexParameterf(texture->target(), pname, param);
1399 bool TextureManager::MarkMipmapsGenerated(TextureRef* ref) {
1400 DCHECK(ref);
1401 Texture* texture = ref->texture();
1402 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1403 bool result = texture->MarkMipmapsGenerated(feature_info_.get());
1404 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1405 return result;
1408 TextureRef* TextureManager::CreateTexture(
1409 GLuint client_id, GLuint service_id) {
1410 DCHECK_NE(0u, service_id);
1411 scoped_refptr<TextureRef> ref(TextureRef::Create(
1412 this, client_id, service_id));
1413 std::pair<TextureMap::iterator, bool> result =
1414 textures_.insert(std::make_pair(client_id, ref));
1415 DCHECK(result.second);
1416 return ref.get();
1419 TextureRef* TextureManager::GetTexture(
1420 GLuint client_id) const {
1421 TextureMap::const_iterator it = textures_.find(client_id);
1422 return it != textures_.end() ? it->second.get() : NULL;
1425 void TextureManager::RemoveTexture(GLuint client_id) {
1426 TextureMap::iterator it = textures_.find(client_id);
1427 if (it != textures_.end()) {
1428 it->second->reset_client_id();
1429 textures_.erase(it);
1433 void TextureManager::StartTracking(TextureRef* ref) {
1434 Texture* texture = ref->texture();
1435 ++texture_count_;
1436 num_uncleared_mips_ += texture->num_uncleared_mips();
1437 if (!texture->SafeToRenderFrom())
1438 ++num_unsafe_textures_;
1439 if (!texture->CanRender(feature_info_.get()))
1440 ++num_unrenderable_textures_;
1441 if (texture->HasImages())
1442 ++num_images_;
1445 void TextureManager::StopTracking(TextureRef* ref) {
1446 if (ref->num_observers()) {
1447 for (unsigned int i = 0; i < destruction_observers_.size(); i++) {
1448 destruction_observers_[i]->OnTextureRefDestroying(ref);
1450 DCHECK_EQ(ref->num_observers(), 0);
1453 Texture* texture = ref->texture();
1455 --texture_count_;
1456 if (texture->HasImages()) {
1457 DCHECK_NE(0, num_images_);
1458 --num_images_;
1460 if (!texture->CanRender(feature_info_.get())) {
1461 DCHECK_NE(0, num_unrenderable_textures_);
1462 --num_unrenderable_textures_;
1464 if (!texture->SafeToRenderFrom()) {
1465 DCHECK_NE(0, num_unsafe_textures_);
1466 --num_unsafe_textures_;
1468 num_uncleared_mips_ -= texture->num_uncleared_mips();
1469 DCHECK_GE(num_uncleared_mips_, 0);
1472 MemoryTypeTracker* TextureManager::GetMemTracker(GLenum tracking_pool) {
1473 switch (tracking_pool) {
1474 case GL_TEXTURE_POOL_MANAGED_CHROMIUM:
1475 return memory_tracker_managed_.get();
1476 break;
1477 case GL_TEXTURE_POOL_UNMANAGED_CHROMIUM:
1478 return memory_tracker_unmanaged_.get();
1479 break;
1480 default:
1481 break;
1483 NOTREACHED();
1484 return NULL;
1487 Texture* TextureManager::GetTextureForServiceId(GLuint service_id) const {
1488 // This doesn't need to be fast. It's only used during slow queries.
1489 for (TextureMap::const_iterator it = textures_.begin();
1490 it != textures_.end(); ++it) {
1491 Texture* texture = it->second->texture();
1492 if (texture->service_id() == service_id)
1493 return texture;
1495 return NULL;
1498 GLsizei TextureManager::ComputeMipMapCount(GLenum target,
1499 GLsizei width,
1500 GLsizei height,
1501 GLsizei depth) {
1502 switch (target) {
1503 case GL_TEXTURE_EXTERNAL_OES:
1504 return 1;
1505 default:
1506 return 1 +
1507 base::bits::Log2Floor(std::max(std::max(width, height), depth));
1511 void TextureManager::SetLevelImage(
1512 TextureRef* ref,
1513 GLenum target,
1514 GLint level,
1515 gfx::GLImage* image) {
1516 DCHECK(ref);
1517 ref->texture()->SetLevelImage(feature_info_.get(), target, level, image);
1520 size_t TextureManager::GetSignatureSize() const {
1521 return sizeof(TextureTag) + sizeof(TextureSignature);
1524 void TextureManager::AddToSignature(
1525 TextureRef* ref,
1526 GLenum target,
1527 GLint level,
1528 std::string* signature) const {
1529 ref->texture()->AddToSignature(feature_info_.get(), target, level, signature);
1532 void TextureManager::UpdateSafeToRenderFrom(int delta) {
1533 num_unsafe_textures_ += delta;
1534 DCHECK_GE(num_unsafe_textures_, 0);
1537 void TextureManager::UpdateUnclearedMips(int delta) {
1538 num_uncleared_mips_ += delta;
1539 DCHECK_GE(num_uncleared_mips_, 0);
1542 void TextureManager::UpdateCanRenderCondition(
1543 Texture::CanRenderCondition old_condition,
1544 Texture::CanRenderCondition new_condition) {
1545 if (old_condition == Texture::CAN_RENDER_NEVER ||
1546 (old_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1547 !feature_info_->feature_flags().npot_ok)) {
1548 DCHECK_GT(num_unrenderable_textures_, 0);
1549 --num_unrenderable_textures_;
1551 if (new_condition == Texture::CAN_RENDER_NEVER ||
1552 (new_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1553 !feature_info_->feature_flags().npot_ok))
1554 ++num_unrenderable_textures_;
1557 void TextureManager::UpdateNumImages(int delta) {
1558 num_images_ += delta;
1559 DCHECK_GE(num_images_, 0);
1562 void TextureManager::IncFramebufferStateChangeCount() {
1563 if (framebuffer_manager_)
1564 framebuffer_manager_->IncFramebufferStateChangeCount();
1567 bool TextureManager::ValidateFormatAndTypeCombination(
1568 ErrorState* error_state, const char* function_name, GLenum format,
1569 GLenum type) {
1570 if (!feature_info_->GetTextureFormatValidator(format).IsValid(type)) {
1571 ERRORSTATE_SET_GL_ERROR(
1572 error_state, GL_INVALID_OPERATION, function_name,
1573 (std::string("invalid type ") +
1574 GLES2Util::GetStringEnum(type) + " for format " +
1575 GLES2Util::GetStringEnum(format)).c_str());
1576 return false;
1578 return true;
1581 bool TextureManager::ValidateTextureParameters(
1582 ErrorState* error_state, const char* function_name,
1583 GLenum format, GLenum type, GLenum internal_format, GLint level) {
1584 const Validators* validators = feature_info_->validators();
1585 if (!validators->texture_format.IsValid(format)) {
1586 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1587 error_state, function_name, format, "format");
1588 return false;
1590 if (!validators->pixel_type.IsValid(type)) {
1591 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1592 error_state, function_name, type, "type");
1593 return false;
1595 if (format != internal_format &&
1596 !((internal_format == GL_RGBA32F && format == GL_RGBA) ||
1597 (internal_format == GL_RGB32F && format == GL_RGB))) {
1598 ERRORSTATE_SET_GL_ERROR(
1599 error_state, GL_INVALID_OPERATION, function_name,
1600 "format != internalformat");
1601 return false;
1603 uint32 channels = GLES2Util::GetChannelsForFormat(format);
1604 if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) {
1605 ERRORSTATE_SET_GL_ERROR(
1606 error_state, GL_INVALID_OPERATION, function_name,
1607 (std::string("invalid format ") + GLES2Util::GetStringEnum(format) +
1608 " for level != 0").c_str());
1609 return false;
1611 return ValidateFormatAndTypeCombination(error_state, function_name,
1612 format, type);
1615 // Gets the texture id for a given target.
1616 TextureRef* TextureManager::GetTextureInfoForTarget(
1617 ContextState* state, GLenum target) {
1618 TextureUnit& unit = state->texture_units[state->active_texture_unit];
1619 TextureRef* texture = NULL;
1620 switch (target) {
1621 case GL_TEXTURE_2D:
1622 texture = unit.bound_texture_2d.get();
1623 break;
1624 case GL_TEXTURE_CUBE_MAP:
1625 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1626 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1627 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1628 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1629 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1630 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1631 texture = unit.bound_texture_cube_map.get();
1632 break;
1633 case GL_TEXTURE_EXTERNAL_OES:
1634 texture = unit.bound_texture_external_oes.get();
1635 break;
1636 case GL_TEXTURE_RECTANGLE_ARB:
1637 texture = unit.bound_texture_rectangle_arb.get();
1638 break;
1639 case GL_TEXTURE_3D:
1640 texture = unit.bound_texture_3d.get();
1641 break;
1642 case GL_TEXTURE_2D_ARRAY:
1643 texture = unit.bound_texture_2d_array.get();
1644 break;
1645 default:
1646 NOTREACHED();
1647 return NULL;
1649 return texture;
1652 TextureRef* TextureManager::GetTextureInfoForTargetUnlessDefault(
1653 ContextState* state, GLenum target) {
1654 TextureRef* texture = GetTextureInfoForTarget(state, target);
1655 if (!texture)
1656 return NULL;
1657 if (texture == GetDefaultTextureInfo(target))
1658 return NULL;
1659 return texture;
1662 bool TextureManager::ValidateTexImage2D(
1663 ContextState* state,
1664 const char* function_name,
1665 const DoTextImage2DArguments& args,
1666 TextureRef** texture_ref) {
1667 ErrorState* error_state = state->GetErrorState();
1668 const Validators* validators = feature_info_->validators();
1669 if (!validators->texture_target.IsValid(args.target)) {
1670 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1671 error_state, function_name, args.target, "target");
1672 return false;
1674 if (!validators->texture_internal_format.IsValid(args.internal_format)) {
1675 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1676 error_state, function_name, args.internal_format,
1677 "internalformat");
1678 return false;
1680 if (!ValidateTextureParameters(
1681 error_state, function_name, args.format, args.type,
1682 args.internal_format, args.level)) {
1683 return false;
1685 if (!ValidForTarget(args.target, args.level, args.width, args.height, 1) ||
1686 args.border != 0) {
1687 ERRORSTATE_SET_GL_ERROR(
1688 error_state, GL_INVALID_VALUE, function_name,
1689 "dimensions out of range");
1690 return false;
1692 if ((GLES2Util::GetChannelsForFormat(args.format) &
1693 (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && args.pixels) {
1694 ERRORSTATE_SET_GL_ERROR(
1695 error_state, GL_INVALID_OPERATION,
1696 function_name, "can not supply data for depth or stencil textures");
1697 return false;
1700 TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target);
1701 if (!local_texture_ref) {
1702 ERRORSTATE_SET_GL_ERROR(
1703 error_state, GL_INVALID_OPERATION, function_name,
1704 "unknown texture for target");
1705 return false;
1707 if (local_texture_ref->texture()->IsImmutable()) {
1708 ERRORSTATE_SET_GL_ERROR(
1709 error_state, GL_INVALID_OPERATION, function_name,
1710 "texture is immutable");
1711 return false;
1714 if (!memory_tracker_managed_->EnsureGPUMemoryAvailable(args.pixels_size)) {
1715 ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, function_name,
1716 "out of memory");
1717 return false;
1720 // Write the TextureReference since this is valid.
1721 *texture_ref = local_texture_ref;
1722 return true;
1725 void TextureManager::ValidateAndDoTexImage2D(
1726 DecoderTextureState* texture_state,
1727 ContextState* state,
1728 DecoderFramebufferState* framebuffer_state,
1729 const DoTextImage2DArguments& args) {
1730 TextureRef* texture_ref;
1731 if (!ValidateTexImage2D(state, "glTexImage2D", args, &texture_ref)) {
1732 return;
1735 DoTexImage2D(texture_state, state->GetErrorState(), framebuffer_state,
1736 texture_ref, args);
1739 GLenum TextureManager::AdjustTexFormat(GLenum format) const {
1740 // TODO(bajones): GLES 3 allows for internal format and format to differ.
1741 // This logic may need to change as a result.
1742 if (gfx::GetGLImplementation() == gfx::kGLImplementationDesktopGL) {
1743 if (format == GL_SRGB_EXT)
1744 return GL_RGB;
1745 if (format == GL_SRGB_ALPHA_EXT)
1746 return GL_RGBA;
1748 return format;
1751 void TextureManager::DoTexImage2D(
1752 DecoderTextureState* texture_state,
1753 ErrorState* error_state,
1754 DecoderFramebufferState* framebuffer_state,
1755 TextureRef* texture_ref,
1756 const DoTextImage2DArguments& args) {
1757 Texture* texture = texture_ref->texture();
1758 GLsizei tex_width = 0;
1759 GLsizei tex_height = 0;
1760 GLenum tex_type = 0;
1761 GLenum tex_format = 0;
1762 bool level_is_same =
1763 texture->GetLevelSize(
1764 args.target, args.level, &tex_width, &tex_height, nullptr) &&
1765 texture->GetLevelType(args.target, args.level, &tex_type, &tex_format) &&
1766 args.width == tex_width && args.height == tex_height &&
1767 args.type == tex_type && args.format == tex_format;
1769 if (level_is_same && !args.pixels) {
1770 // Just set the level texture but mark the texture as uncleared.
1771 SetLevelInfo(
1772 texture_ref,
1773 args.target, args.level, args.internal_format, args.width, args.height,
1774 1, args.border, args.format, args.type, false);
1775 texture_state->tex_image_2d_failed = false;
1776 return;
1779 if (texture->IsAttachedToFramebuffer()) {
1780 framebuffer_state->clear_state_dirty = true;
1783 if (texture_state->texsubimage2d_faster_than_teximage2d &&
1784 level_is_same && args.pixels) {
1786 ScopedTextureUploadTimer timer(texture_state);
1787 glTexSubImage2D(args.target, args.level, 0, 0, args.width, args.height,
1788 AdjustTexFormat(args.format), args.type, args.pixels);
1790 SetLevelCleared(texture_ref, args.target, args.level, true);
1791 texture_state->tex_image_2d_failed = false;
1792 return;
1795 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glTexImage2D");
1797 ScopedTextureUploadTimer timer(texture_state);
1798 glTexImage2D(
1799 args.target, args.level, args.internal_format, args.width, args.height,
1800 args.border, AdjustTexFormat(args.format), args.type, args.pixels);
1802 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glTexImage2D");
1803 if (error == GL_NO_ERROR) {
1804 SetLevelInfo(
1805 texture_ref,
1806 args.target, args.level, args.internal_format, args.width, args.height,
1807 1, args.border, args.format, args.type, args.pixels != NULL);
1808 texture_state->tex_image_2d_failed = false;
1812 ScopedTextureUploadTimer::ScopedTextureUploadTimer(
1813 DecoderTextureState* texture_state)
1814 : texture_state_(texture_state),
1815 begin_time_(base::TimeTicks::Now()) {
1818 ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
1819 texture_state_->texture_upload_count++;
1820 texture_state_->total_texture_upload_time +=
1821 base::TimeTicks::Now() - begin_time_;
1824 } // namespace gles2
1825 } // namespace gpu