Make GL bindings conditional
[chromium-blink-merge.git] / gpu / command_buffer / service / texture_manager.cc
blobb066e8d13d9ae977efa4c35ef97d7552744210f9
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_s_;
33 GLenum wrap_t_;
34 GLenum usage_;
35 GLenum internal_format_;
36 GLsizei width_;
37 GLsizei height_;
38 GLsizei depth_;
39 GLint border_;
40 GLenum format_;
41 GLenum type_;
42 bool has_image_;
43 bool can_render_;
44 bool can_render_to_;
45 bool npot_;
47 // Since we will be hashing this signature structure, the padding must be
48 // zero initialized. Although the C++11 specifications specify that this is
49 // true, we will use a constructor with a memset to further enforce it instead
50 // of relying on compilers adhering to this deep dark corner specification.
51 TextureSignature(GLenum target,
52 GLint level,
53 GLenum min_filter,
54 GLenum mag_filter,
55 GLenum wrap_s,
56 GLenum wrap_t,
57 GLenum usage,
58 GLenum internal_format,
59 GLsizei width,
60 GLsizei height,
61 GLsizei depth,
62 GLint border,
63 GLenum format,
64 GLenum type,
65 bool has_image,
66 bool can_render,
67 bool can_render_to,
68 bool npot) {
69 memset(this, 0, sizeof(TextureSignature));
70 target_ = target;
71 level_ = level;
72 min_filter_ = min_filter;
73 mag_filter_ = mag_filter;
74 wrap_s_ = wrap_s;
75 wrap_t_ = wrap_t;
76 usage_ = usage;
77 internal_format_ = internal_format;
78 width_ = width;
79 height_ = height;
80 depth_ = depth;
81 border_ = border;
82 format_ = format;
83 type_ = type;
84 has_image_ = has_image;
85 can_render_ = can_render;
86 can_render_to_ = can_render_to;
87 npot_ = npot;
91 TextureManager::DestructionObserver::DestructionObserver() {}
93 TextureManager::DestructionObserver::~DestructionObserver() {}
95 TextureManager::~TextureManager() {
96 for (unsigned int i = 0; i < destruction_observers_.size(); i++)
97 destruction_observers_[i]->OnTextureManagerDestroying(this);
99 DCHECK(textures_.empty());
101 // If this triggers, that means something is keeping a reference to
102 // a Texture belonging to this.
103 CHECK_EQ(texture_count_, 0u);
105 DCHECK_EQ(0, num_unrenderable_textures_);
106 DCHECK_EQ(0, num_unsafe_textures_);
107 DCHECK_EQ(0, num_uncleared_mips_);
108 DCHECK_EQ(0, num_images_);
111 void TextureManager::Destroy(bool have_context) {
112 have_context_ = have_context;
113 textures_.clear();
114 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
115 default_textures_[ii] = NULL;
118 if (have_context) {
119 glDeleteTextures(arraysize(black_texture_ids_), black_texture_ids_);
122 DCHECK_EQ(0u, memory_tracker_managed_->GetMemRepresented());
123 DCHECK_EQ(0u, memory_tracker_unmanaged_->GetMemRepresented());
126 Texture::Texture(GLuint service_id)
127 : mailbox_manager_(NULL),
128 memory_tracking_ref_(NULL),
129 service_id_(service_id),
130 cleared_(true),
131 num_uncleared_mips_(0),
132 num_npot_faces_(0),
133 target_(0),
134 min_filter_(GL_NEAREST_MIPMAP_LINEAR),
135 mag_filter_(GL_LINEAR),
136 wrap_s_(GL_REPEAT),
137 wrap_t_(GL_REPEAT),
138 usage_(GL_NONE),
139 pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM),
140 max_level_set_(-1),
141 texture_complete_(false),
142 texture_mips_dirty_(false),
143 texture_mips_complete_(false),
144 cube_complete_(false),
145 texture_level0_dirty_(false),
146 texture_level0_complete_(false),
147 npot_(false),
148 has_been_bound_(false),
149 framebuffer_attachment_count_(0),
150 immutable_(false),
151 has_images_(false),
152 estimated_size_(0),
153 can_render_condition_(CAN_RENDER_ALWAYS),
154 texture_max_anisotropy_initialized_(false) {
157 Texture::~Texture() {
158 if (mailbox_manager_)
159 mailbox_manager_->TextureDeleted(this);
162 void Texture::AddTextureRef(TextureRef* ref) {
163 DCHECK(refs_.find(ref) == refs_.end());
164 refs_.insert(ref);
165 if (!memory_tracking_ref_) {
166 memory_tracking_ref_ = ref;
167 GetMemTracker()->TrackMemAlloc(estimated_size());
171 void Texture::RemoveTextureRef(TextureRef* ref, bool have_context) {
172 if (memory_tracking_ref_ == ref) {
173 GetMemTracker()->TrackMemFree(estimated_size());
174 memory_tracking_ref_ = NULL;
176 size_t result = refs_.erase(ref);
177 DCHECK_EQ(result, 1u);
178 if (refs_.empty()) {
179 if (have_context) {
180 GLuint id = service_id();
181 glDeleteTextures(1, &id);
183 delete this;
184 } else if (memory_tracking_ref_ == NULL) {
185 // TODO(piman): tune ownership semantics for cross-context group shared
186 // textures.
187 memory_tracking_ref_ = *refs_.begin();
188 GetMemTracker()->TrackMemAlloc(estimated_size());
192 MemoryTypeTracker* Texture::GetMemTracker() {
193 DCHECK(memory_tracking_ref_);
194 return memory_tracking_ref_->manager()->GetMemTracker(pool_);
197 Texture::LevelInfo::LevelInfo()
198 : cleared(true),
199 target(0),
200 level(-1),
201 internal_format(0),
202 width(0),
203 height(0),
204 depth(0),
205 border(0),
206 format(0),
207 type(0),
208 estimated_size(0) {
211 Texture::LevelInfo::LevelInfo(const LevelInfo& rhs)
212 : cleared(rhs.cleared),
213 target(rhs.target),
214 level(rhs.level),
215 internal_format(rhs.internal_format),
216 width(rhs.width),
217 height(rhs.height),
218 depth(rhs.depth),
219 border(rhs.border),
220 format(rhs.format),
221 type(rhs.type),
222 image(rhs.image),
223 estimated_size(rhs.estimated_size) {
226 Texture::LevelInfo::~LevelInfo() {
229 Texture::FaceInfo::FaceInfo()
230 : num_mip_levels(0) {
233 Texture::FaceInfo::~FaceInfo() {
236 Texture::CanRenderCondition Texture::GetCanRenderCondition() const {
237 if (target_ == 0)
238 return CAN_RENDER_ALWAYS;
240 if (target_ != GL_TEXTURE_EXTERNAL_OES) {
241 if (face_infos_.empty()) {
242 return CAN_RENDER_NEVER;
245 const Texture::LevelInfo& first_face = face_infos_[0].level_infos[0];
246 if (first_face.width == 0 ||
247 first_face.height == 0 ||
248 first_face.depth == 0) {
249 return CAN_RENDER_NEVER;
253 bool needs_mips = NeedsMips();
254 if (needs_mips) {
255 if (!texture_complete())
256 return CAN_RENDER_NEVER;
257 if (target_ == GL_TEXTURE_CUBE_MAP && !cube_complete())
258 return CAN_RENDER_NEVER;
261 bool is_npot_compatible = !needs_mips &&
262 wrap_s_ == GL_CLAMP_TO_EDGE &&
263 wrap_t_ == GL_CLAMP_TO_EDGE;
265 if (!is_npot_compatible) {
266 if (target_ == GL_TEXTURE_RECTANGLE_ARB)
267 return CAN_RENDER_NEVER;
268 else if (npot())
269 return CAN_RENDER_ONLY_IF_NPOT;
272 return CAN_RENDER_ALWAYS;
275 bool Texture::CanRender(const FeatureInfo* feature_info) const {
276 switch (can_render_condition_) {
277 case CAN_RENDER_ALWAYS:
278 return true;
279 case CAN_RENDER_NEVER:
280 return false;
281 case CAN_RENDER_ONLY_IF_NPOT:
282 break;
284 return feature_info->feature_flags().npot_ok;
287 void Texture::AddToSignature(
288 const FeatureInfo* feature_info,
289 GLenum target,
290 GLint level,
291 std::string* signature) const {
292 DCHECK(feature_info);
293 DCHECK(signature);
294 DCHECK_GE(level, 0);
295 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
296 DCHECK_LT(static_cast<size_t>(face_index),
297 face_infos_.size());
298 DCHECK_LT(static_cast<size_t>(level),
299 face_infos_[face_index].level_infos.size());
301 const Texture::LevelInfo& info =
302 face_infos_[face_index].level_infos[level];
304 TextureSignature signature_data(target,
305 level,
306 min_filter_,
307 mag_filter_,
308 wrap_s_,
309 wrap_t_,
310 usage_,
311 info.internal_format,
312 info.width,
313 info.height,
314 info.depth,
315 info.border,
316 info.format,
317 info.type,
318 info.image.get() != NULL,
319 CanRender(feature_info),
320 CanRenderTo(),
321 npot_);
323 signature->append(TextureTag, sizeof(TextureTag));
324 signature->append(reinterpret_cast<const char*>(&signature_data),
325 sizeof(signature_data));
328 void Texture::SetMailboxManager(MailboxManager* mailbox_manager) {
329 DCHECK(!mailbox_manager_ || mailbox_manager_ == mailbox_manager);
330 mailbox_manager_ = mailbox_manager;
333 bool Texture::MarkMipmapsGenerated(
334 const FeatureInfo* feature_info) {
335 if (!CanGenerateMipmaps(feature_info)) {
336 return false;
338 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
339 const Texture::FaceInfo& face_info = face_infos_[ii];
340 const Texture::LevelInfo& level0_info = face_info.level_infos[0];
341 GLsizei width = level0_info.width;
342 GLsizei height = level0_info.height;
343 GLsizei depth = level0_info.depth;
344 GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
345 GLES2Util::IndexToGLFaceTarget(ii);
347 const GLsizei num_mips = face_info.num_mip_levels;
348 for (GLsizei level = 1; level < num_mips; ++level) {
349 width = std::max(1, width >> 1);
350 height = std::max(1, height >> 1);
351 depth = std::max(1, depth >> 1);
352 SetLevelInfo(feature_info,
353 target,
354 level,
355 level0_info.internal_format,
356 width,
357 height,
358 depth,
359 level0_info.border,
360 level0_info.format,
361 level0_info.type,
362 true);
366 return true;
369 void Texture::SetTarget(
370 const FeatureInfo* feature_info, GLenum target, GLint max_levels) {
371 DCHECK_EQ(0u, target_); // you can only set this once.
372 target_ = target;
373 size_t num_faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
374 face_infos_.resize(num_faces);
375 for (size_t ii = 0; ii < num_faces; ++ii) {
376 face_infos_[ii].level_infos.resize(max_levels);
379 if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) {
380 min_filter_ = GL_LINEAR;
381 wrap_s_ = wrap_t_ = GL_CLAMP_TO_EDGE;
384 if (target == GL_TEXTURE_EXTERNAL_OES) {
385 immutable_ = true;
387 Update(feature_info);
388 UpdateCanRenderCondition();
391 bool Texture::CanGenerateMipmaps(
392 const FeatureInfo* feature_info) const {
393 if ((npot() && !feature_info->feature_flags().npot_ok) ||
394 face_infos_.empty() ||
395 target_ == GL_TEXTURE_EXTERNAL_OES ||
396 target_ == GL_TEXTURE_RECTANGLE_ARB) {
397 return false;
400 // Can't generate mips for depth or stencil textures.
401 const Texture::LevelInfo& first = face_infos_[0].level_infos[0];
402 uint32 channels = GLES2Util::GetChannelsForFormat(first.format);
403 if (channels & (GLES2Util::kDepth | GLES2Util::kStencil)) {
404 return false;
407 // TODO(gman): Check internal_format, format and type.
408 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
409 const LevelInfo& info = face_infos_[ii].level_infos[0];
410 if ((info.target == 0) || (info.width != first.width) ||
411 (info.height != first.height) || (info.depth != 1) ||
412 (info.format != first.format) ||
413 (info.internal_format != first.internal_format) ||
414 (info.type != first.type) ||
415 feature_info->validators()->compressed_texture_format.IsValid(
416 info.internal_format) ||
417 info.image.get()) {
418 return false;
421 return true;
424 bool Texture::TextureIsNPOT(GLsizei width,
425 GLsizei height,
426 GLsizei depth) {
427 return (GLES2Util::IsNPOT(width) ||
428 GLES2Util::IsNPOT(height) ||
429 GLES2Util::IsNPOT(depth));
432 bool Texture::TextureFaceComplete(const Texture::LevelInfo& first_face,
433 size_t face_index,
434 GLenum target,
435 GLenum internal_format,
436 GLsizei width,
437 GLsizei height,
438 GLsizei depth,
439 GLenum format,
440 GLenum type) {
441 bool complete = (target != 0 && depth == 1);
442 if (face_index != 0) {
443 complete &= (width == first_face.width &&
444 height == first_face.height &&
445 internal_format == first_face.internal_format &&
446 format == first_face.format &&
447 type == first_face.type);
449 return complete;
452 bool Texture::TextureMipComplete(const Texture::LevelInfo& level0_face,
453 GLenum target,
454 GLint level,
455 GLenum internal_format,
456 GLsizei width,
457 GLsizei height,
458 GLsizei depth,
459 GLenum format,
460 GLenum type) {
461 bool complete = (target != 0);
462 if (level != 0) {
463 const GLsizei mip_width = std::max(1, level0_face.width >> level);
464 const GLsizei mip_height = std::max(1, level0_face.height >> level);
465 const GLsizei mip_depth = std::max(1, level0_face.depth >> level);
467 complete &= (width == mip_width &&
468 height == mip_height &&
469 depth == mip_depth &&
470 internal_format == level0_face.internal_format &&
471 format == level0_face.format &&
472 type == level0_face.type);
474 return complete;
477 void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) {
478 DCHECK_GE(level, 0);
479 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
480 DCHECK_LT(static_cast<size_t>(face_index),
481 face_infos_.size());
482 DCHECK_LT(static_cast<size_t>(level),
483 face_infos_[face_index].level_infos.size());
484 Texture::LevelInfo& info =
485 face_infos_[face_index].level_infos[level];
486 UpdateMipCleared(&info, cleared);
487 UpdateCleared();
490 void Texture::UpdateCleared() {
491 if (face_infos_.empty()) {
492 return;
495 const bool cleared = (num_uncleared_mips_ == 0);
497 // If texture is uncleared and is attached to a framebuffer,
498 // that framebuffer must be marked possibly incomplete.
499 if (!cleared && IsAttachedToFramebuffer()) {
500 IncAllFramebufferStateChangeCount();
503 UpdateSafeToRenderFrom(cleared);
506 void Texture::UpdateSafeToRenderFrom(bool cleared) {
507 if (cleared_ == cleared)
508 return;
509 cleared_ = cleared;
510 int delta = cleared ? -1 : +1;
511 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
512 (*it)->manager()->UpdateSafeToRenderFrom(delta);
515 void Texture::UpdateMipCleared(LevelInfo* info, bool cleared) {
516 if (info->cleared == cleared)
517 return;
518 info->cleared = cleared;
519 int delta = cleared ? -1 : +1;
520 num_uncleared_mips_ += delta;
521 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
522 (*it)->manager()->UpdateUnclearedMips(delta);
525 void Texture::UpdateCanRenderCondition() {
526 CanRenderCondition can_render_condition = GetCanRenderCondition();
527 if (can_render_condition_ == can_render_condition)
528 return;
529 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
530 (*it)->manager()->UpdateCanRenderCondition(can_render_condition_,
531 can_render_condition);
532 can_render_condition_ = can_render_condition;
535 void Texture::UpdateHasImages() {
536 if (face_infos_.empty())
537 return;
539 bool has_images = false;
540 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
541 for (size_t jj = 0; jj < face_infos_[ii].level_infos.size(); ++jj) {
542 const Texture::LevelInfo& info = face_infos_[ii].level_infos[jj];
543 if (info.image.get() != NULL) {
544 has_images = true;
545 break;
550 if (has_images_ == has_images)
551 return;
552 has_images_ = has_images;
553 int delta = has_images ? +1 : -1;
554 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
555 (*it)->manager()->UpdateNumImages(delta);
558 void Texture::IncAllFramebufferStateChangeCount() {
559 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
560 (*it)->manager()->IncFramebufferStateChangeCount();
563 void Texture::SetLevelInfo(
564 const FeatureInfo* feature_info,
565 GLenum target,
566 GLint level,
567 GLenum internal_format,
568 GLsizei width,
569 GLsizei height,
570 GLsizei depth,
571 GLint border,
572 GLenum format,
573 GLenum type,
574 bool cleared) {
575 DCHECK_GE(level, 0);
576 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
577 DCHECK_LT(static_cast<size_t>(face_index),
578 face_infos_.size());
579 DCHECK_LT(static_cast<size_t>(level),
580 face_infos_[face_index].level_infos.size());
581 DCHECK_GE(width, 0);
582 DCHECK_GE(height, 0);
583 DCHECK_GE(depth, 0);
584 Texture::LevelInfo& info =
585 face_infos_[face_index].level_infos[level];
587 // Update counters only if any attributes have changed. Counters are
588 // comparisons between the old and new values so it must be done before any
589 // assignment has been done to the LevelInfo.
590 if (info.target != target ||
591 info.internal_format != internal_format ||
592 info.width != width ||
593 info.height != height ||
594 info.depth != depth ||
595 info.format != format ||
596 info.type != type) {
597 if (level == 0) {
598 // Calculate the mip level count.
599 face_infos_[face_index].num_mip_levels =
600 TextureManager::ComputeMipMapCount(target_, width, height, depth);
602 // Update NPOT face count for the first level.
603 bool prev_npot = TextureIsNPOT(info.width, info.height, info.depth);
604 bool now_npot = TextureIsNPOT(width, height, depth);
605 if (prev_npot != now_npot)
606 num_npot_faces_ += now_npot ? 1 : -1;
608 // Signify that level 0 has been changed, so they need to be reverified.
609 texture_level0_dirty_ = true;
612 // Signify that at least one of the mips has changed.
613 texture_mips_dirty_ = true;
616 info.target = target;
617 info.level = level;
618 info.internal_format = internal_format;
619 info.width = width;
620 info.height = height;
621 info.depth = depth;
622 info.border = border;
623 info.format = format;
624 info.type = type;
625 info.image = 0;
627 estimated_size_ -= info.estimated_size;
628 GLES2Util::ComputeImageDataSizes(
629 width, height, 1, format, type, 4, &info.estimated_size, NULL, NULL);
630 estimated_size_ += info.estimated_size;
632 UpdateMipCleared(&info, cleared);
633 max_level_set_ = std::max(max_level_set_, level);
634 Update(feature_info);
635 UpdateCleared();
636 UpdateCanRenderCondition();
637 UpdateHasImages();
638 if (IsAttachedToFramebuffer()) {
639 // TODO(gman): If textures tracked which framebuffers they were attached to
640 // we could just mark those framebuffers as not complete.
641 IncAllFramebufferStateChangeCount();
645 bool Texture::ValidForTexture(
646 GLint target,
647 GLint level,
648 GLint xoffset,
649 GLint yoffset,
650 GLsizei width,
651 GLsizei height,
652 GLenum type) const {
653 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
654 if (level >= 0 && face_index < face_infos_.size() &&
655 static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
656 const LevelInfo& info = face_infos_[face_index].level_infos[level];
657 int32 right;
658 int32 top;
659 return SafeAddInt32(xoffset, width, &right) &&
660 SafeAddInt32(yoffset, height, &top) &&
661 xoffset >= 0 &&
662 yoffset >= 0 &&
663 right <= info.width &&
664 top <= info.height &&
665 type == info.type;
667 return false;
670 bool Texture::GetLevelSize(
671 GLint target, GLint level, GLsizei* width, GLsizei* height) const {
672 DCHECK(width);
673 DCHECK(height);
674 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
675 if (level >= 0 && face_index < face_infos_.size() &&
676 static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
677 const LevelInfo& info = face_infos_[face_index].level_infos[level];
678 if (info.target != 0) {
679 *width = info.width;
680 *height = info.height;
681 return true;
684 return false;
687 bool Texture::GetLevelType(
688 GLint target, GLint level, GLenum* type, GLenum* internal_format) const {
689 DCHECK(type);
690 DCHECK(internal_format);
691 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
692 if (level >= 0 && face_index < face_infos_.size() &&
693 static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
694 const LevelInfo& info = face_infos_[face_index].level_infos[level];
695 if (info.target != 0) {
696 *type = info.type;
697 *internal_format = info.internal_format;
698 return true;
701 return false;
704 GLenum Texture::SetParameteri(
705 const FeatureInfo* feature_info, GLenum pname, GLint param) {
706 DCHECK(feature_info);
708 if (target_ == GL_TEXTURE_EXTERNAL_OES ||
709 target_ == GL_TEXTURE_RECTANGLE_ARB) {
710 if (pname == GL_TEXTURE_MIN_FILTER &&
711 (param != GL_NEAREST && param != GL_LINEAR))
712 return GL_INVALID_ENUM;
713 if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) &&
714 param != GL_CLAMP_TO_EDGE)
715 return GL_INVALID_ENUM;
718 switch (pname) {
719 case GL_TEXTURE_MIN_FILTER:
720 if (!feature_info->validators()->texture_min_filter_mode.IsValid(param)) {
721 return GL_INVALID_ENUM;
723 min_filter_ = param;
724 break;
725 case GL_TEXTURE_MAG_FILTER:
726 if (!feature_info->validators()->texture_mag_filter_mode.IsValid(param)) {
727 return GL_INVALID_ENUM;
729 mag_filter_ = param;
730 break;
731 case GL_TEXTURE_POOL_CHROMIUM:
732 if (!feature_info->validators()->texture_pool.IsValid(param)) {
733 return GL_INVALID_ENUM;
735 GetMemTracker()->TrackMemFree(estimated_size());
736 pool_ = param;
737 GetMemTracker()->TrackMemAlloc(estimated_size());
738 break;
739 case GL_TEXTURE_WRAP_S:
740 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
741 return GL_INVALID_ENUM;
743 wrap_s_ = param;
744 break;
745 case GL_TEXTURE_WRAP_T:
746 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
747 return GL_INVALID_ENUM;
749 wrap_t_ = param;
750 break;
751 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
752 if (param < 1) {
753 return GL_INVALID_VALUE;
755 break;
756 case GL_TEXTURE_USAGE_ANGLE:
757 if (!feature_info->validators()->texture_usage.IsValid(param)) {
758 return GL_INVALID_ENUM;
760 usage_ = param;
761 break;
762 default:
763 NOTREACHED();
764 return GL_INVALID_ENUM;
766 Update(feature_info);
767 UpdateCleared();
768 UpdateCanRenderCondition();
769 return GL_NO_ERROR;
772 GLenum Texture::SetParameterf(
773 const FeatureInfo* feature_info, GLenum pname, GLfloat param) {
774 switch (pname) {
775 case GL_TEXTURE_MIN_FILTER:
776 case GL_TEXTURE_MAG_FILTER:
777 case GL_TEXTURE_POOL_CHROMIUM:
778 case GL_TEXTURE_WRAP_S:
779 case GL_TEXTURE_WRAP_T:
780 case GL_TEXTURE_USAGE_ANGLE:
782 GLint iparam = static_cast<GLint>(param);
783 return SetParameteri(feature_info, pname, iparam);
785 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
786 if (param < 1.f) {
787 return GL_INVALID_VALUE;
789 break;
790 default:
791 NOTREACHED();
792 return GL_INVALID_ENUM;
794 return GL_NO_ERROR;
797 void Texture::Update(const FeatureInfo* feature_info) {
798 // Update npot status.
799 // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others
800 npot_ = (target_ == GL_TEXTURE_EXTERNAL_OES) || (num_npot_faces_ > 0);
802 if (face_infos_.empty()) {
803 texture_complete_ = false;
804 cube_complete_ = false;
805 return;
808 // Update texture_complete and cube_complete status.
809 const Texture::FaceInfo& first_face = face_infos_[0];
810 const Texture::LevelInfo& first_level = first_face.level_infos[0];
811 const GLsizei levels_needed = first_face.num_mip_levels;
813 texture_complete_ =
814 max_level_set_ >= (levels_needed - 1) && max_level_set_ >= 0;
815 cube_complete_ = (face_infos_.size() == 6) &&
816 (first_level.width == first_level.height);
818 if (first_level.width == 0 || first_level.height == 0) {
819 texture_complete_ = false;
820 } else if (first_level.type == GL_FLOAT &&
821 !feature_info->feature_flags().enable_texture_float_linear &&
822 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
823 mag_filter_ != GL_NEAREST)) {
824 texture_complete_ = false;
825 } else if (first_level.type == GL_HALF_FLOAT_OES &&
826 !feature_info->feature_flags().enable_texture_half_float_linear &&
827 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
828 mag_filter_ != GL_NEAREST)) {
829 texture_complete_ = false;
832 if (cube_complete_ && texture_level0_dirty_) {
833 texture_level0_complete_ = true;
834 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
835 const Texture::LevelInfo& level0 = face_infos_[ii].level_infos[0];
836 if (!TextureFaceComplete(first_level,
838 level0.target,
839 level0.internal_format,
840 level0.width,
841 level0.height,
842 level0.depth,
843 level0.format,
844 level0.type)) {
845 texture_level0_complete_ = false;
846 break;
849 texture_level0_dirty_ = false;
851 cube_complete_ &= texture_level0_complete_;
853 if (texture_complete_ && texture_mips_dirty_) {
854 texture_mips_complete_ = true;
855 for (size_t ii = 0;
856 ii < face_infos_.size() && texture_mips_complete_;
857 ++ii) {
858 const Texture::FaceInfo& face_info = face_infos_[ii];
859 const Texture::LevelInfo& level0 = face_info.level_infos[0];
860 for (GLsizei jj = 1; jj < levels_needed; ++jj) {
861 const Texture::LevelInfo& level_info = face_infos_[ii].level_infos[jj];
862 if (!TextureMipComplete(level0,
863 level_info.target,
865 level_info.internal_format,
866 level_info.width,
867 level_info.height,
868 level_info.depth,
869 level_info.format,
870 level_info.type)) {
871 texture_mips_complete_ = false;
872 break;
876 texture_mips_dirty_ = false;
878 texture_complete_ &= texture_mips_complete_;
881 bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) {
882 DCHECK(decoder);
883 if (cleared_) {
884 return true;
887 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
888 const Texture::FaceInfo& face_info = face_infos_[ii];
889 for (GLint jj = 0; jj < face_info.num_mip_levels; ++jj) {
890 const Texture::LevelInfo& info = face_info.level_infos[jj];
891 if (info.target != 0) {
892 if (!ClearLevel(decoder, info.target, jj)) {
893 return false;
898 UpdateSafeToRenderFrom(true);
899 return true;
902 bool Texture::IsLevelCleared(GLenum target, GLint level) const {
903 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
904 if (face_index >= face_infos_.size() ||
905 level >= static_cast<GLint>(face_infos_[face_index].level_infos.size())) {
906 return true;
909 const Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
911 return info.cleared;
914 void Texture::InitTextureMaxAnisotropyIfNeeded(GLenum target) {
915 if (texture_max_anisotropy_initialized_)
916 return;
917 texture_max_anisotropy_initialized_ = true;
918 GLfloat params[] = { 1.0f };
919 glTexParameterfv(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, params);
922 bool Texture::ClearLevel(
923 GLES2Decoder* decoder, GLenum target, GLint level) {
924 DCHECK(decoder);
925 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
926 if (face_index >= face_infos_.size() ||
927 level >= static_cast<GLint>(face_infos_[face_index].level_infos.size())) {
928 return true;
931 Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
933 DCHECK(target == info.target);
935 if (info.target == 0 ||
936 info.cleared ||
937 info.width == 0 ||
938 info.height == 0 ||
939 info.depth == 0) {
940 return true;
943 // NOTE: It seems kind of gross to call back into the decoder for this
944 // but only the decoder knows all the state (like unpack_alignment_) that's
945 // needed to be able to call GL correctly.
946 bool cleared = decoder->ClearLevel(
947 service_id_, target_, info.target, info.level, info.internal_format,
948 info.format, info.type, info.width, info.height, immutable_);
949 UpdateMipCleared(&info, cleared);
950 return info.cleared;
953 void Texture::SetLevelImage(
954 const FeatureInfo* feature_info,
955 GLenum target,
956 GLint level,
957 gfx::GLImage* image) {
958 DCHECK_GE(level, 0);
959 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
960 DCHECK_LT(static_cast<size_t>(face_index),
961 face_infos_.size());
962 DCHECK_LT(static_cast<size_t>(level),
963 face_infos_[face_index].level_infos.size());
964 Texture::LevelInfo& info =
965 face_infos_[face_index].level_infos[level];
966 DCHECK_EQ(info.target, target);
967 DCHECK_EQ(info.level, level);
968 info.image = image;
969 UpdateCanRenderCondition();
970 UpdateHasImages();
973 gfx::GLImage* Texture::GetLevelImage(GLint target, GLint level) const {
974 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES &&
975 target != GL_TEXTURE_RECTANGLE_ARB) {
976 return NULL;
979 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
980 if (level >= 0 && face_index < face_infos_.size() &&
981 static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
982 const LevelInfo& info = face_infos_[face_index].level_infos[level];
983 if (info.target != 0) {
984 return info.image.get();
987 return NULL;
990 void Texture::OnWillModifyPixels() {
991 gfx::GLImage* image = GetLevelImage(target(), 0);
992 if (image)
993 image->WillModifyTexImage();
996 void Texture::OnDidModifyPixels() {
997 gfx::GLImage* image = GetLevelImage(target(), 0);
998 if (image)
999 image->DidModifyTexImage();
1002 TextureRef::TextureRef(TextureManager* manager,
1003 GLuint client_id,
1004 Texture* texture)
1005 : manager_(manager),
1006 texture_(texture),
1007 client_id_(client_id),
1008 num_observers_(0) {
1009 DCHECK(manager_);
1010 DCHECK(texture_);
1011 texture_->AddTextureRef(this);
1012 manager_->StartTracking(this);
1015 scoped_refptr<TextureRef> TextureRef::Create(TextureManager* manager,
1016 GLuint client_id,
1017 GLuint service_id) {
1018 return new TextureRef(manager, client_id, new Texture(service_id));
1021 TextureRef::~TextureRef() {
1022 manager_->StopTracking(this);
1023 texture_->RemoveTextureRef(this, manager_->have_context_);
1024 manager_ = NULL;
1027 TextureManager::TextureManager(MemoryTracker* memory_tracker,
1028 FeatureInfo* feature_info,
1029 GLint max_texture_size,
1030 GLint max_cube_map_texture_size,
1031 GLint max_rectangle_texture_size,
1032 bool use_default_textures)
1033 : memory_tracker_managed_(
1034 new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)),
1035 memory_tracker_unmanaged_(
1036 new MemoryTypeTracker(memory_tracker, MemoryTracker::kUnmanaged)),
1037 feature_info_(feature_info),
1038 framebuffer_manager_(NULL),
1039 max_texture_size_(max_texture_size),
1040 max_cube_map_texture_size_(max_cube_map_texture_size),
1041 max_rectangle_texture_size_(max_rectangle_texture_size),
1042 max_levels_(ComputeMipMapCount(GL_TEXTURE_2D,
1043 max_texture_size,
1044 max_texture_size,
1045 max_texture_size)),
1046 max_cube_map_levels_(ComputeMipMapCount(GL_TEXTURE_CUBE_MAP,
1047 max_cube_map_texture_size,
1048 max_cube_map_texture_size,
1049 max_cube_map_texture_size)),
1050 use_default_textures_(use_default_textures),
1051 num_unrenderable_textures_(0),
1052 num_unsafe_textures_(0),
1053 num_uncleared_mips_(0),
1054 num_images_(0),
1055 texture_count_(0),
1056 have_context_(true) {
1057 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
1058 black_texture_ids_[ii] = 0;
1062 bool TextureManager::Initialize() {
1063 // TODO(gman): The default textures have to be real textures, not the 0
1064 // texture because we simulate non shared resources on top of shared
1065 // resources and all contexts that share resource share the same default
1066 // texture.
1067 default_textures_[kTexture2D] = CreateDefaultAndBlackTextures(
1068 GL_TEXTURE_2D, &black_texture_ids_[kTexture2D]);
1069 default_textures_[kCubeMap] = CreateDefaultAndBlackTextures(
1070 GL_TEXTURE_CUBE_MAP, &black_texture_ids_[kCubeMap]);
1072 if (feature_info_->feature_flags().oes_egl_image_external) {
1073 default_textures_[kExternalOES] = CreateDefaultAndBlackTextures(
1074 GL_TEXTURE_EXTERNAL_OES, &black_texture_ids_[kExternalOES]);
1077 if (feature_info_->feature_flags().arb_texture_rectangle) {
1078 default_textures_[kRectangleARB] = CreateDefaultAndBlackTextures(
1079 GL_TEXTURE_RECTANGLE_ARB, &black_texture_ids_[kRectangleARB]);
1082 return true;
1085 scoped_refptr<TextureRef>
1086 TextureManager::CreateDefaultAndBlackTextures(
1087 GLenum target,
1088 GLuint* black_texture) {
1089 static uint8 black[] = {0, 0, 0, 255};
1091 // Sampling a texture not associated with any EGLImage sibling will return
1092 // black values according to the spec.
1093 bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES);
1094 bool needs_faces = (target == GL_TEXTURE_CUBE_MAP);
1096 // Make default textures and texture for replacing non-renderable textures.
1097 GLuint ids[2];
1098 const int num_ids = use_default_textures_ ? 2 : 1;
1099 glGenTextures(num_ids, ids);
1100 for (int ii = 0; ii < num_ids; ++ii) {
1101 glBindTexture(target, ids[ii]);
1102 if (needs_initialization) {
1103 if (needs_faces) {
1104 for (int jj = 0; jj < GLES2Util::kNumFaces; ++jj) {
1105 glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj), 0, GL_RGBA, 1, 1, 0,
1106 GL_RGBA, GL_UNSIGNED_BYTE, black);
1108 } else {
1109 glTexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA,
1110 GL_UNSIGNED_BYTE, black);
1114 glBindTexture(target, 0);
1116 scoped_refptr<TextureRef> default_texture;
1117 if (use_default_textures_) {
1118 default_texture = TextureRef::Create(this, 0, ids[1]);
1119 SetTarget(default_texture.get(), target);
1120 if (needs_faces) {
1121 for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) {
1122 SetLevelInfo(default_texture.get(),
1123 GLES2Util::IndexToGLFaceTarget(ii),
1125 GL_RGBA,
1130 GL_RGBA,
1131 GL_UNSIGNED_BYTE,
1132 true);
1134 } else {
1135 if (needs_initialization) {
1136 SetLevelInfo(default_texture.get(),
1137 GL_TEXTURE_2D,
1139 GL_RGBA,
1144 GL_RGBA,
1145 GL_UNSIGNED_BYTE,
1146 true);
1147 } else {
1148 SetLevelInfo(default_texture.get(),
1149 GL_TEXTURE_EXTERNAL_OES,
1151 GL_RGBA,
1156 GL_RGBA,
1157 GL_UNSIGNED_BYTE,
1158 true);
1163 *black_texture = ids[0];
1164 return default_texture;
1167 bool TextureManager::ValidForTarget(
1168 GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth) {
1169 GLsizei max_size = MaxSizeForTarget(target) >> level;
1170 return level >= 0 &&
1171 width >= 0 &&
1172 height >= 0 &&
1173 depth >= 0 &&
1174 level < MaxLevelsForTarget(target) &&
1175 width <= max_size &&
1176 height <= max_size &&
1177 depth <= max_size &&
1178 (level == 0 || feature_info_->feature_flags().npot_ok ||
1179 (!GLES2Util::IsNPOT(width) &&
1180 !GLES2Util::IsNPOT(height) &&
1181 !GLES2Util::IsNPOT(depth))) &&
1182 (target != GL_TEXTURE_CUBE_MAP || (width == height && depth == 1)) &&
1183 (target != GL_TEXTURE_2D || (depth == 1));
1186 void TextureManager::SetTarget(TextureRef* ref, GLenum target) {
1187 DCHECK(ref);
1188 ref->texture()
1189 ->SetTarget(feature_info_.get(), target, MaxLevelsForTarget(target));
1192 void TextureManager::SetLevelCleared(TextureRef* ref,
1193 GLenum target,
1194 GLint level,
1195 bool cleared) {
1196 DCHECK(ref);
1197 ref->texture()->SetLevelCleared(target, level, cleared);
1200 bool TextureManager::ClearRenderableLevels(
1201 GLES2Decoder* decoder, TextureRef* ref) {
1202 DCHECK(ref);
1203 return ref->texture()->ClearRenderableLevels(decoder);
1206 bool TextureManager::ClearTextureLevel(
1207 GLES2Decoder* decoder, TextureRef* ref,
1208 GLenum target, GLint level) {
1209 DCHECK(ref);
1210 Texture* texture = ref->texture();
1211 if (texture->num_uncleared_mips() == 0) {
1212 return true;
1214 bool result = texture->ClearLevel(decoder, target, level);
1215 texture->UpdateCleared();
1216 return result;
1219 void TextureManager::SetLevelInfo(
1220 TextureRef* ref,
1221 GLenum target,
1222 GLint level,
1223 GLenum internal_format,
1224 GLsizei width,
1225 GLsizei height,
1226 GLsizei depth,
1227 GLint border,
1228 GLenum format,
1229 GLenum type,
1230 bool cleared) {
1231 DCHECK(ref);
1232 Texture* texture = ref->texture();
1234 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1235 texture->SetLevelInfo(feature_info_.get(),
1236 target,
1237 level,
1238 internal_format,
1239 width,
1240 height,
1241 depth,
1242 border,
1243 format,
1244 type,
1245 cleared);
1246 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1249 Texture* TextureManager::Produce(TextureRef* ref) {
1250 DCHECK(ref);
1251 return ref->texture();
1254 TextureRef* TextureManager::Consume(
1255 GLuint client_id,
1256 Texture* texture) {
1257 DCHECK(client_id);
1258 scoped_refptr<TextureRef> ref(new TextureRef(this, client_id, texture));
1259 bool result = textures_.insert(std::make_pair(client_id, ref)).second;
1260 DCHECK(result);
1261 return ref.get();
1264 void TextureManager::SetParameteri(
1265 const char* function_name, ErrorState* error_state,
1266 TextureRef* ref, GLenum pname, GLint param) {
1267 DCHECK(error_state);
1268 DCHECK(ref);
1269 Texture* texture = ref->texture();
1270 GLenum result = texture->SetParameteri(feature_info_.get(), pname, param);
1271 if (result != GL_NO_ERROR) {
1272 if (result == GL_INVALID_ENUM) {
1273 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1274 error_state, function_name, param, "param");
1275 } else {
1276 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMI(
1277 error_state, result, function_name, pname, param);
1279 } else {
1280 // Texture tracking pools exist only for the command decoder, so
1281 // do not pass them on to the native GL implementation.
1282 if (pname != GL_TEXTURE_POOL_CHROMIUM) {
1283 glTexParameteri(texture->target(), pname, param);
1288 void TextureManager::SetParameterf(
1289 const char* function_name, ErrorState* error_state,
1290 TextureRef* ref, GLenum pname, GLfloat param) {
1291 DCHECK(error_state);
1292 DCHECK(ref);
1293 Texture* texture = ref->texture();
1294 GLenum result = texture->SetParameterf(feature_info_.get(), pname, param);
1295 if (result != GL_NO_ERROR) {
1296 if (result == GL_INVALID_ENUM) {
1297 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1298 error_state, function_name, pname, "pname");
1299 } else {
1300 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMF(
1301 error_state, result, function_name, pname, param);
1303 } else {
1304 // Texture tracking pools exist only for the command decoder, so
1305 // do not pass them on to the native GL implementation.
1306 if (pname != GL_TEXTURE_POOL_CHROMIUM) {
1307 glTexParameterf(texture->target(), pname, param);
1312 bool TextureManager::MarkMipmapsGenerated(TextureRef* ref) {
1313 DCHECK(ref);
1314 Texture* texture = ref->texture();
1315 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1316 bool result = texture->MarkMipmapsGenerated(feature_info_.get());
1317 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1318 return result;
1321 TextureRef* TextureManager::CreateTexture(
1322 GLuint client_id, GLuint service_id) {
1323 DCHECK_NE(0u, service_id);
1324 scoped_refptr<TextureRef> ref(TextureRef::Create(
1325 this, client_id, service_id));
1326 std::pair<TextureMap::iterator, bool> result =
1327 textures_.insert(std::make_pair(client_id, ref));
1328 DCHECK(result.second);
1329 return ref.get();
1332 TextureRef* TextureManager::GetTexture(
1333 GLuint client_id) const {
1334 TextureMap::const_iterator it = textures_.find(client_id);
1335 return it != textures_.end() ? it->second.get() : NULL;
1338 void TextureManager::RemoveTexture(GLuint client_id) {
1339 TextureMap::iterator it = textures_.find(client_id);
1340 if (it != textures_.end()) {
1341 it->second->reset_client_id();
1342 textures_.erase(it);
1346 void TextureManager::StartTracking(TextureRef* ref) {
1347 Texture* texture = ref->texture();
1348 ++texture_count_;
1349 num_uncleared_mips_ += texture->num_uncleared_mips();
1350 if (!texture->SafeToRenderFrom())
1351 ++num_unsafe_textures_;
1352 if (!texture->CanRender(feature_info_.get()))
1353 ++num_unrenderable_textures_;
1354 if (texture->HasImages())
1355 ++num_images_;
1358 void TextureManager::StopTracking(TextureRef* ref) {
1359 if (ref->num_observers()) {
1360 for (unsigned int i = 0; i < destruction_observers_.size(); i++) {
1361 destruction_observers_[i]->OnTextureRefDestroying(ref);
1363 DCHECK_EQ(ref->num_observers(), 0);
1366 Texture* texture = ref->texture();
1368 --texture_count_;
1369 if (texture->HasImages()) {
1370 DCHECK_NE(0, num_images_);
1371 --num_images_;
1373 if (!texture->CanRender(feature_info_.get())) {
1374 DCHECK_NE(0, num_unrenderable_textures_);
1375 --num_unrenderable_textures_;
1377 if (!texture->SafeToRenderFrom()) {
1378 DCHECK_NE(0, num_unsafe_textures_);
1379 --num_unsafe_textures_;
1381 num_uncleared_mips_ -= texture->num_uncleared_mips();
1382 DCHECK_GE(num_uncleared_mips_, 0);
1385 MemoryTypeTracker* TextureManager::GetMemTracker(GLenum tracking_pool) {
1386 switch (tracking_pool) {
1387 case GL_TEXTURE_POOL_MANAGED_CHROMIUM:
1388 return memory_tracker_managed_.get();
1389 break;
1390 case GL_TEXTURE_POOL_UNMANAGED_CHROMIUM:
1391 return memory_tracker_unmanaged_.get();
1392 break;
1393 default:
1394 break;
1396 NOTREACHED();
1397 return NULL;
1400 Texture* TextureManager::GetTextureForServiceId(GLuint service_id) const {
1401 // This doesn't need to be fast. It's only used during slow queries.
1402 for (TextureMap::const_iterator it = textures_.begin();
1403 it != textures_.end(); ++it) {
1404 Texture* texture = it->second->texture();
1405 if (texture->service_id() == service_id)
1406 return texture;
1408 return NULL;
1411 GLsizei TextureManager::ComputeMipMapCount(GLenum target,
1412 GLsizei width,
1413 GLsizei height,
1414 GLsizei depth) {
1415 switch (target) {
1416 case GL_TEXTURE_EXTERNAL_OES:
1417 return 1;
1418 default:
1419 return 1 +
1420 base::bits::Log2Floor(std::max(std::max(width, height), depth));
1424 void TextureManager::SetLevelImage(
1425 TextureRef* ref,
1426 GLenum target,
1427 GLint level,
1428 gfx::GLImage* image) {
1429 DCHECK(ref);
1430 ref->texture()->SetLevelImage(feature_info_.get(), target, level, image);
1433 size_t TextureManager::GetSignatureSize() const {
1434 return sizeof(TextureTag) + sizeof(TextureSignature);
1437 void TextureManager::AddToSignature(
1438 TextureRef* ref,
1439 GLenum target,
1440 GLint level,
1441 std::string* signature) const {
1442 ref->texture()->AddToSignature(feature_info_.get(), target, level, signature);
1445 void TextureManager::UpdateSafeToRenderFrom(int delta) {
1446 num_unsafe_textures_ += delta;
1447 DCHECK_GE(num_unsafe_textures_, 0);
1450 void TextureManager::UpdateUnclearedMips(int delta) {
1451 num_uncleared_mips_ += delta;
1452 DCHECK_GE(num_uncleared_mips_, 0);
1455 void TextureManager::UpdateCanRenderCondition(
1456 Texture::CanRenderCondition old_condition,
1457 Texture::CanRenderCondition new_condition) {
1458 if (old_condition == Texture::CAN_RENDER_NEVER ||
1459 (old_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1460 !feature_info_->feature_flags().npot_ok)) {
1461 DCHECK_GT(num_unrenderable_textures_, 0);
1462 --num_unrenderable_textures_;
1464 if (new_condition == Texture::CAN_RENDER_NEVER ||
1465 (new_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1466 !feature_info_->feature_flags().npot_ok))
1467 ++num_unrenderable_textures_;
1470 void TextureManager::UpdateNumImages(int delta) {
1471 num_images_ += delta;
1472 DCHECK_GE(num_images_, 0);
1475 void TextureManager::IncFramebufferStateChangeCount() {
1476 if (framebuffer_manager_)
1477 framebuffer_manager_->IncFramebufferStateChangeCount();
1480 bool TextureManager::ValidateFormatAndTypeCombination(
1481 ErrorState* error_state, const char* function_name, GLenum format,
1482 GLenum type) {
1483 if (!feature_info_->GetTextureFormatValidator(format).IsValid(type)) {
1484 ERRORSTATE_SET_GL_ERROR(
1485 error_state, GL_INVALID_OPERATION, function_name,
1486 (std::string("invalid type ") +
1487 GLES2Util::GetStringEnum(type) + " for format " +
1488 GLES2Util::GetStringEnum(format)).c_str());
1489 return false;
1491 return true;
1494 bool TextureManager::ValidateTextureParameters(
1495 ErrorState* error_state, const char* function_name,
1496 GLenum format, GLenum type, GLenum internal_format, GLint level) {
1497 const Validators* validators = feature_info_->validators();
1498 if (!validators->texture_format.IsValid(format)) {
1499 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1500 error_state, function_name, format, "format");
1501 return false;
1503 if (!validators->pixel_type.IsValid(type)) {
1504 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1505 error_state, function_name, type, "type");
1506 return false;
1508 if (format != internal_format &&
1509 !((internal_format == GL_RGBA32F && format == GL_RGBA) ||
1510 (internal_format == GL_RGB32F && format == GL_RGB))) {
1511 ERRORSTATE_SET_GL_ERROR(
1512 error_state, GL_INVALID_OPERATION, function_name,
1513 "format != internalformat");
1514 return false;
1516 uint32 channels = GLES2Util::GetChannelsForFormat(format);
1517 if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) {
1518 ERRORSTATE_SET_GL_ERROR(
1519 error_state, GL_INVALID_OPERATION, function_name,
1520 (std::string("invalid format ") + GLES2Util::GetStringEnum(format) +
1521 " for level != 0").c_str());
1522 return false;
1524 return ValidateFormatAndTypeCombination(error_state, function_name,
1525 format, type);
1528 // Gets the texture id for a given target.
1529 TextureRef* TextureManager::GetTextureInfoForTarget(
1530 ContextState* state, GLenum target) {
1531 TextureUnit& unit = state->texture_units[state->active_texture_unit];
1532 TextureRef* texture = NULL;
1533 switch (target) {
1534 case GL_TEXTURE_2D:
1535 texture = unit.bound_texture_2d.get();
1536 break;
1537 case GL_TEXTURE_CUBE_MAP:
1538 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1539 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1540 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1541 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1542 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1543 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1544 texture = unit.bound_texture_cube_map.get();
1545 break;
1546 case GL_TEXTURE_EXTERNAL_OES:
1547 texture = unit.bound_texture_external_oes.get();
1548 break;
1549 case GL_TEXTURE_RECTANGLE_ARB:
1550 texture = unit.bound_texture_rectangle_arb.get();
1551 break;
1552 default:
1553 NOTREACHED();
1554 return NULL;
1556 return texture;
1559 TextureRef* TextureManager::GetTextureInfoForTargetUnlessDefault(
1560 ContextState* state, GLenum target) {
1561 TextureRef* texture = GetTextureInfoForTarget(state, target);
1562 if (!texture)
1563 return NULL;
1564 if (texture == GetDefaultTextureInfo(target))
1565 return NULL;
1566 return texture;
1569 bool TextureManager::ValidateTexImage2D(
1570 ContextState* state,
1571 const char* function_name,
1572 const DoTextImage2DArguments& args,
1573 TextureRef** texture_ref) {
1574 ErrorState* error_state = state->GetErrorState();
1575 const Validators* validators = feature_info_->validators();
1576 if (!validators->texture_target.IsValid(args.target)) {
1577 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1578 error_state, function_name, args.target, "target");
1579 return false;
1581 if (!validators->texture_internal_format.IsValid(args.internal_format)) {
1582 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1583 error_state, function_name, args.internal_format,
1584 "internalformat");
1585 return false;
1587 if (!ValidateTextureParameters(
1588 error_state, function_name, args.format, args.type,
1589 args.internal_format, args.level)) {
1590 return false;
1592 if (!ValidForTarget(args.target, args.level, args.width, args.height, 1) ||
1593 args.border != 0) {
1594 ERRORSTATE_SET_GL_ERROR(
1595 error_state, GL_INVALID_VALUE, function_name,
1596 "dimensions out of range");
1597 return false;
1599 if ((GLES2Util::GetChannelsForFormat(args.format) &
1600 (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && args.pixels) {
1601 ERRORSTATE_SET_GL_ERROR(
1602 error_state, GL_INVALID_OPERATION,
1603 function_name, "can not supply data for depth or stencil textures");
1604 return false;
1607 TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target);
1608 if (!local_texture_ref) {
1609 ERRORSTATE_SET_GL_ERROR(
1610 error_state, GL_INVALID_OPERATION, function_name,
1611 "unknown texture for target");
1612 return false;
1614 if (local_texture_ref->texture()->IsImmutable()) {
1615 ERRORSTATE_SET_GL_ERROR(
1616 error_state, GL_INVALID_OPERATION, function_name,
1617 "texture is immutable");
1618 return false;
1621 if (!memory_tracker_managed_->EnsureGPUMemoryAvailable(args.pixels_size)) {
1622 ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, function_name,
1623 "out of memory");
1624 return false;
1627 // Write the TextureReference since this is valid.
1628 *texture_ref = local_texture_ref;
1629 return true;
1632 void TextureManager::ValidateAndDoTexImage2D(
1633 DecoderTextureState* texture_state,
1634 ContextState* state,
1635 DecoderFramebufferState* framebuffer_state,
1636 const DoTextImage2DArguments& args) {
1637 TextureRef* texture_ref;
1638 if (!ValidateTexImage2D(state, "glTexImage2D", args, &texture_ref)) {
1639 return;
1642 DoTexImage2D(texture_state, state->GetErrorState(), framebuffer_state,
1643 texture_ref, args);
1646 GLenum TextureManager::AdjustTexFormat(GLenum format) const {
1647 // TODO: GLES 3 allows for internal format and format to differ. This logic
1648 // may need to change as a result.
1649 if (gfx::GetGLImplementation() == gfx::kGLImplementationDesktopGL) {
1650 if (format == GL_SRGB_EXT)
1651 return GL_RGB;
1652 if (format == GL_SRGB_ALPHA_EXT)
1653 return GL_RGBA;
1655 return format;
1658 void TextureManager::DoTexImage2D(
1659 DecoderTextureState* texture_state,
1660 ErrorState* error_state,
1661 DecoderFramebufferState* framebuffer_state,
1662 TextureRef* texture_ref,
1663 const DoTextImage2DArguments& args) {
1664 Texture* texture = texture_ref->texture();
1665 GLsizei tex_width = 0;
1666 GLsizei tex_height = 0;
1667 GLenum tex_type = 0;
1668 GLenum tex_format = 0;
1669 bool level_is_same =
1670 texture->GetLevelSize(args.target, args.level, &tex_width, &tex_height) &&
1671 texture->GetLevelType(args.target, args.level, &tex_type, &tex_format) &&
1672 args.width == tex_width && args.height == tex_height &&
1673 args.type == tex_type && args.format == tex_format;
1675 if (level_is_same && !args.pixels) {
1676 // Just set the level texture but mark the texture as uncleared.
1677 SetLevelInfo(
1678 texture_ref,
1679 args.target, args.level, args.internal_format, args.width, args.height,
1680 1, args.border, args.format, args.type, false);
1681 texture_state->tex_image_2d_failed = false;
1682 return;
1685 if (texture->IsAttachedToFramebuffer()) {
1686 framebuffer_state->clear_state_dirty = true;
1689 if (texture_state->texsubimage2d_faster_than_teximage2d &&
1690 level_is_same && args.pixels) {
1692 ScopedTextureUploadTimer timer(texture_state);
1693 glTexSubImage2D(args.target, args.level, 0, 0, args.width, args.height,
1694 AdjustTexFormat(args.format), args.type, args.pixels);
1696 SetLevelCleared(texture_ref, args.target, args.level, true);
1697 texture_state->tex_image_2d_failed = false;
1698 return;
1701 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glTexImage2D");
1703 ScopedTextureUploadTimer timer(texture_state);
1704 glTexImage2D(
1705 args.target, args.level, args.internal_format, args.width, args.height,
1706 args.border, AdjustTexFormat(args.format), args.type, args.pixels);
1708 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glTexImage2D");
1709 if (error == GL_NO_ERROR) {
1710 SetLevelInfo(
1711 texture_ref,
1712 args.target, args.level, args.internal_format, args.width, args.height,
1713 1, args.border, args.format, args.type, args.pixels != NULL);
1714 texture_state->tex_image_2d_failed = false;
1718 ScopedTextureUploadTimer::ScopedTextureUploadTimer(
1719 DecoderTextureState* texture_state)
1720 : texture_state_(texture_state),
1721 begin_time_(base::TimeTicks::Now()) {
1724 ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
1725 texture_state_->texture_upload_count++;
1726 texture_state_->total_texture_upload_time +=
1727 base::TimeTicks::Now() - begin_time_;
1730 } // namespace gles2
1731 } // namespace gpu