Handle account removal correctly on all platforms.
[chromium-blink-merge.git] / gpu / command_buffer / service / texture_manager.cc
blob9dc5cc9d924f19a2cd266043f24cb7cc38b4e178
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"
21 namespace gpu {
22 namespace gles2 {
24 TextureManager::DestructionObserver::DestructionObserver() {}
26 TextureManager::DestructionObserver::~DestructionObserver() {}
28 TextureManager::~TextureManager() {
29 for (unsigned int i = 0; i < destruction_observers_.size(); i++)
30 destruction_observers_[i]->OnTextureManagerDestroying(this);
32 DCHECK(textures_.empty());
34 // If this triggers, that means something is keeping a reference to
35 // a Texture belonging to this.
36 CHECK_EQ(texture_count_, 0u);
38 DCHECK_EQ(0, num_unrenderable_textures_);
39 DCHECK_EQ(0, num_unsafe_textures_);
40 DCHECK_EQ(0, num_uncleared_mips_);
41 DCHECK_EQ(0, num_images_);
44 void TextureManager::Destroy(bool have_context) {
45 have_context_ = have_context;
46 textures_.clear();
47 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
48 default_textures_[ii] = NULL;
51 if (have_context) {
52 glDeleteTextures(arraysize(black_texture_ids_), black_texture_ids_);
55 DCHECK_EQ(0u, memory_tracker_managed_->GetMemRepresented());
56 DCHECK_EQ(0u, memory_tracker_unmanaged_->GetMemRepresented());
59 Texture::Texture(GLuint service_id)
60 : mailbox_manager_(NULL),
61 memory_tracking_ref_(NULL),
62 service_id_(service_id),
63 cleared_(true),
64 num_uncleared_mips_(0),
65 target_(0),
66 min_filter_(GL_NEAREST_MIPMAP_LINEAR),
67 mag_filter_(GL_LINEAR),
68 wrap_s_(GL_REPEAT),
69 wrap_t_(GL_REPEAT),
70 usage_(GL_NONE),
71 pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM),
72 max_level_set_(-1),
73 texture_complete_(false),
74 cube_complete_(false),
75 npot_(false),
76 has_been_bound_(false),
77 framebuffer_attachment_count_(0),
78 immutable_(false),
79 has_images_(false),
80 estimated_size_(0),
81 can_render_condition_(CAN_RENDER_ALWAYS),
82 texture_max_anisotropy_initialized_(false) {
85 Texture::~Texture() {
86 if (mailbox_manager_)
87 mailbox_manager_->TextureDeleted(this);
90 void Texture::AddTextureRef(TextureRef* ref) {
91 DCHECK(refs_.find(ref) == refs_.end());
92 refs_.insert(ref);
93 if (!memory_tracking_ref_) {
94 memory_tracking_ref_ = ref;
95 GetMemTracker()->TrackMemAlloc(estimated_size());
99 void Texture::RemoveTextureRef(TextureRef* ref, bool have_context) {
100 if (memory_tracking_ref_ == ref) {
101 GetMemTracker()->TrackMemFree(estimated_size());
102 memory_tracking_ref_ = NULL;
104 size_t result = refs_.erase(ref);
105 DCHECK_EQ(result, 1u);
106 if (refs_.empty()) {
107 if (have_context) {
108 GLuint id = service_id();
109 glDeleteTextures(1, &id);
111 delete this;
112 } else if (memory_tracking_ref_ == NULL) {
113 // TODO(piman): tune ownership semantics for cross-context group shared
114 // textures.
115 memory_tracking_ref_ = *refs_.begin();
116 GetMemTracker()->TrackMemAlloc(estimated_size());
120 MemoryTypeTracker* Texture::GetMemTracker() {
121 DCHECK(memory_tracking_ref_);
122 return memory_tracking_ref_->manager()->GetMemTracker(pool_);
125 Texture::LevelInfo::LevelInfo()
126 : cleared(true),
127 target(0),
128 level(-1),
129 internal_format(0),
130 width(0),
131 height(0),
132 depth(0),
133 border(0),
134 format(0),
135 type(0),
136 estimated_size(0) {
139 Texture::LevelInfo::LevelInfo(const LevelInfo& rhs)
140 : cleared(rhs.cleared),
141 target(rhs.target),
142 level(rhs.level),
143 internal_format(rhs.internal_format),
144 width(rhs.width),
145 height(rhs.height),
146 depth(rhs.depth),
147 border(rhs.border),
148 format(rhs.format),
149 type(rhs.type),
150 image(rhs.image),
151 estimated_size(rhs.estimated_size) {
154 Texture::LevelInfo::~LevelInfo() {
157 Texture::CanRenderCondition Texture::GetCanRenderCondition() const {
158 if (target_ == 0)
159 return CAN_RENDER_ALWAYS;
161 if (target_ != GL_TEXTURE_EXTERNAL_OES) {
162 if (level_infos_.empty()) {
163 return CAN_RENDER_NEVER;
166 const Texture::LevelInfo& first_face = level_infos_[0][0];
167 if (first_face.width == 0 ||
168 first_face.height == 0 ||
169 first_face.depth == 0) {
170 return CAN_RENDER_NEVER;
174 bool needs_mips = NeedsMips();
175 if (needs_mips) {
176 if (!texture_complete())
177 return CAN_RENDER_NEVER;
178 if (target_ == GL_TEXTURE_CUBE_MAP && !cube_complete())
179 return CAN_RENDER_NEVER;
182 bool is_npot_compatible = !needs_mips &&
183 wrap_s_ == GL_CLAMP_TO_EDGE &&
184 wrap_t_ == GL_CLAMP_TO_EDGE;
186 if (!is_npot_compatible) {
187 if (target_ == GL_TEXTURE_RECTANGLE_ARB)
188 return CAN_RENDER_NEVER;
189 else if (npot())
190 return CAN_RENDER_ONLY_IF_NPOT;
193 return CAN_RENDER_ALWAYS;
196 bool Texture::CanRender(const FeatureInfo* feature_info) const {
197 switch (can_render_condition_) {
198 case CAN_RENDER_ALWAYS:
199 return true;
200 case CAN_RENDER_NEVER:
201 return false;
202 case CAN_RENDER_ONLY_IF_NPOT:
203 break;
205 return feature_info->feature_flags().npot_ok;
208 void Texture::AddToSignature(
209 const FeatureInfo* feature_info,
210 GLenum target,
211 GLint level,
212 std::string* signature) const {
213 DCHECK(feature_info);
214 DCHECK(signature);
215 DCHECK_GE(level, 0);
216 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
217 DCHECK_LT(static_cast<size_t>(face_index),
218 level_infos_.size());
219 DCHECK_LT(static_cast<size_t>(level),
220 level_infos_[face_index].size());
221 const Texture::LevelInfo& info =
222 level_infos_[face_index][level];
223 *signature += base::StringPrintf(
224 "|Texture|target=%04x|level=%d|internal_format=%04x"
225 "|width=%d|height=%d|depth=%d|border=%d|format=%04x|type=%04x"
226 "|image=%d|canrender=%d|canrenderto=%d|npot_=%d"
227 "|min_filter=%04x|mag_filter=%04x|wrap_s=%04x|wrap_t=%04x"
228 "|usage=%04x",
229 target, level, info.internal_format,
230 info.width, info.height, info.depth, info.border,
231 info.format, info.type, info.image.get() != NULL,
232 CanRender(feature_info), CanRenderTo(), npot_,
233 min_filter_, mag_filter_, wrap_s_, wrap_t_,
234 usage_);
237 void Texture::SetMailboxManager(MailboxManager* mailbox_manager) {
238 DCHECK(!mailbox_manager_ || mailbox_manager_ == mailbox_manager);
239 mailbox_manager_ = mailbox_manager;
242 bool Texture::MarkMipmapsGenerated(
243 const FeatureInfo* feature_info) {
244 if (!CanGenerateMipmaps(feature_info)) {
245 return false;
247 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
248 const Texture::LevelInfo& info1 = level_infos_[ii][0];
249 GLsizei width = info1.width;
250 GLsizei height = info1.height;
251 GLsizei depth = info1.depth;
252 GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
253 GLES2Util::IndexToGLFaceTarget(ii);
254 int num_mips =
255 TextureManager::ComputeMipMapCount(target_, width, height, depth);
256 for (int level = 1; level < num_mips; ++level) {
257 width = std::max(1, width >> 1);
258 height = std::max(1, height >> 1);
259 depth = std::max(1, depth >> 1);
260 SetLevelInfo(feature_info,
261 target,
262 level,
263 info1.internal_format,
264 width,
265 height,
266 depth,
267 info1.border,
268 info1.format,
269 info1.type,
270 true);
274 return true;
277 void Texture::SetTarget(
278 const FeatureInfo* feature_info, GLenum target, GLint max_levels) {
279 DCHECK_EQ(0u, target_); // you can only set this once.
280 target_ = target;
281 size_t num_faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
282 level_infos_.resize(num_faces);
283 for (size_t ii = 0; ii < num_faces; ++ii) {
284 level_infos_[ii].resize(max_levels);
287 if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) {
288 min_filter_ = GL_LINEAR;
289 wrap_s_ = wrap_t_ = GL_CLAMP_TO_EDGE;
292 if (target == GL_TEXTURE_EXTERNAL_OES) {
293 immutable_ = true;
295 Update(feature_info);
296 UpdateCanRenderCondition();
299 bool Texture::CanGenerateMipmaps(
300 const FeatureInfo* feature_info) const {
301 if ((npot() && !feature_info->feature_flags().npot_ok) ||
302 level_infos_.empty() ||
303 target_ == GL_TEXTURE_EXTERNAL_OES ||
304 target_ == GL_TEXTURE_RECTANGLE_ARB) {
305 return false;
308 // Can't generate mips for depth or stencil textures.
309 const Texture::LevelInfo& first = level_infos_[0][0];
310 uint32 channels = GLES2Util::GetChannelsForFormat(first.format);
311 if (channels & (GLES2Util::kDepth | GLES2Util::kStencil)) {
312 return false;
315 // TODO(gman): Check internal_format, format and type.
316 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
317 const LevelInfo& info = level_infos_[ii][0];
318 if ((info.target == 0) || (info.width != first.width) ||
319 (info.height != first.height) || (info.depth != 1) ||
320 (info.format != first.format) ||
321 (info.internal_format != first.internal_format) ||
322 (info.type != first.type) ||
323 feature_info->validators()->compressed_texture_format.IsValid(
324 info.internal_format) ||
325 info.image.get()) {
326 return false;
329 return true;
332 void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) {
333 DCHECK_GE(level, 0);
334 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
335 DCHECK_LT(static_cast<size_t>(face_index),
336 level_infos_.size());
337 DCHECK_LT(static_cast<size_t>(level),
338 level_infos_[face_index].size());
339 Texture::LevelInfo& info =
340 level_infos_[face_index][level];
341 UpdateMipCleared(&info, cleared);
342 UpdateCleared();
345 void Texture::UpdateCleared() {
346 if (level_infos_.empty()) {
347 return;
350 const Texture::LevelInfo& first_face = level_infos_[0][0];
351 int levels_needed = TextureManager::ComputeMipMapCount(
352 target_, first_face.width, first_face.height, first_face.depth);
353 bool cleared = true;
354 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
355 for (GLint jj = 0; jj < levels_needed; ++jj) {
356 const Texture::LevelInfo& info = level_infos_[ii][jj];
357 if (info.width > 0 && info.height > 0 && info.depth > 0 &&
358 !info.cleared) {
359 cleared = false;
360 break;
365 // If texture is uncleared and is attached to a framebuffer,
366 // that framebuffer must be marked possibly incomplete.
367 if (!cleared && IsAttachedToFramebuffer()) {
368 IncAllFramebufferStateChangeCount();
371 UpdateSafeToRenderFrom(cleared);
374 void Texture::UpdateSafeToRenderFrom(bool cleared) {
375 if (cleared_ == cleared)
376 return;
377 cleared_ = cleared;
378 int delta = cleared ? -1 : +1;
379 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
380 (*it)->manager()->UpdateSafeToRenderFrom(delta);
383 void Texture::UpdateMipCleared(LevelInfo* info, bool cleared) {
384 if (info->cleared == cleared)
385 return;
386 info->cleared = cleared;
387 int delta = cleared ? -1 : +1;
388 num_uncleared_mips_ += delta;
389 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
390 (*it)->manager()->UpdateUnclearedMips(delta);
393 void Texture::UpdateCanRenderCondition() {
394 CanRenderCondition can_render_condition = GetCanRenderCondition();
395 if (can_render_condition_ == can_render_condition)
396 return;
397 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
398 (*it)->manager()->UpdateCanRenderCondition(can_render_condition_,
399 can_render_condition);
400 can_render_condition_ = can_render_condition;
403 void Texture::UpdateHasImages() {
404 if (level_infos_.empty())
405 return;
407 bool has_images = false;
408 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
409 for (size_t jj = 0; jj < level_infos_[ii].size(); ++jj) {
410 const Texture::LevelInfo& info = level_infos_[ii][jj];
411 if (info.image.get() != NULL) {
412 has_images = true;
413 break;
418 if (has_images_ == has_images)
419 return;
420 has_images_ = has_images;
421 int delta = has_images ? +1 : -1;
422 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
423 (*it)->manager()->UpdateNumImages(delta);
426 void Texture::IncAllFramebufferStateChangeCount() {
427 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
428 (*it)->manager()->IncFramebufferStateChangeCount();
431 void Texture::SetLevelInfo(
432 const FeatureInfo* feature_info,
433 GLenum target,
434 GLint level,
435 GLenum internal_format,
436 GLsizei width,
437 GLsizei height,
438 GLsizei depth,
439 GLint border,
440 GLenum format,
441 GLenum type,
442 bool cleared) {
443 DCHECK_GE(level, 0);
444 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
445 DCHECK_LT(static_cast<size_t>(face_index),
446 level_infos_.size());
447 DCHECK_LT(static_cast<size_t>(level),
448 level_infos_[face_index].size());
449 DCHECK_GE(width, 0);
450 DCHECK_GE(height, 0);
451 DCHECK_GE(depth, 0);
452 Texture::LevelInfo& info =
453 level_infos_[face_index][level];
454 info.target = target;
455 info.level = level;
456 info.internal_format = internal_format;
457 info.width = width;
458 info.height = height;
459 info.depth = depth;
460 info.border = border;
461 info.format = format;
462 info.type = type;
463 info.image = 0;
465 estimated_size_ -= info.estimated_size;
466 GLES2Util::ComputeImageDataSizes(
467 width, height, format, type, 4, &info.estimated_size, NULL, NULL);
468 estimated_size_ += info.estimated_size;
470 UpdateMipCleared(&info, cleared);
471 max_level_set_ = std::max(max_level_set_, level);
472 Update(feature_info);
473 UpdateCleared();
474 UpdateCanRenderCondition();
475 UpdateHasImages();
476 if (IsAttachedToFramebuffer()) {
477 // TODO(gman): If textures tracked which framebuffers they were attached to
478 // we could just mark those framebuffers as not complete.
479 IncAllFramebufferStateChangeCount();
483 bool Texture::ValidForTexture(
484 GLint target,
485 GLint level,
486 GLint xoffset,
487 GLint yoffset,
488 GLsizei width,
489 GLsizei height,
490 GLenum type) const {
491 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
492 if (level >= 0 && face_index < level_infos_.size() &&
493 static_cast<size_t>(level) < level_infos_[face_index].size()) {
494 const LevelInfo& info = level_infos_[face_index][level];
495 int32 right;
496 int32 top;
497 return SafeAddInt32(xoffset, width, &right) &&
498 SafeAddInt32(yoffset, height, &top) &&
499 xoffset >= 0 &&
500 yoffset >= 0 &&
501 right <= info.width &&
502 top <= info.height &&
503 type == info.type;
505 return false;
508 bool Texture::GetLevelSize(
509 GLint target, GLint level, GLsizei* width, GLsizei* height) const {
510 DCHECK(width);
511 DCHECK(height);
512 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
513 if (level >= 0 && face_index < level_infos_.size() &&
514 static_cast<size_t>(level) < level_infos_[face_index].size()) {
515 const LevelInfo& info = level_infos_[face_index][level];
516 if (info.target != 0) {
517 *width = info.width;
518 *height = info.height;
519 return true;
522 return false;
525 bool Texture::GetLevelType(
526 GLint target, GLint level, GLenum* type, GLenum* internal_format) const {
527 DCHECK(type);
528 DCHECK(internal_format);
529 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
530 if (level >= 0 && face_index < level_infos_.size() &&
531 static_cast<size_t>(level) < level_infos_[face_index].size()) {
532 const LevelInfo& info = level_infos_[face_index][level];
533 if (info.target != 0) {
534 *type = info.type;
535 *internal_format = info.internal_format;
536 return true;
539 return false;
542 GLenum Texture::SetParameteri(
543 const FeatureInfo* feature_info, GLenum pname, GLint param) {
544 DCHECK(feature_info);
546 if (target_ == GL_TEXTURE_EXTERNAL_OES ||
547 target_ == GL_TEXTURE_RECTANGLE_ARB) {
548 if (pname == GL_TEXTURE_MIN_FILTER &&
549 (param != GL_NEAREST && param != GL_LINEAR))
550 return GL_INVALID_ENUM;
551 if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) &&
552 param != GL_CLAMP_TO_EDGE)
553 return GL_INVALID_ENUM;
556 switch (pname) {
557 case GL_TEXTURE_MIN_FILTER:
558 if (!feature_info->validators()->texture_min_filter_mode.IsValid(param)) {
559 return GL_INVALID_ENUM;
561 min_filter_ = param;
562 break;
563 case GL_TEXTURE_MAG_FILTER:
564 if (!feature_info->validators()->texture_mag_filter_mode.IsValid(param)) {
565 return GL_INVALID_ENUM;
567 mag_filter_ = param;
568 break;
569 case GL_TEXTURE_POOL_CHROMIUM:
570 if (!feature_info->validators()->texture_pool.IsValid(param)) {
571 return GL_INVALID_ENUM;
573 GetMemTracker()->TrackMemFree(estimated_size());
574 pool_ = param;
575 GetMemTracker()->TrackMemAlloc(estimated_size());
576 break;
577 case GL_TEXTURE_WRAP_S:
578 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
579 return GL_INVALID_ENUM;
581 wrap_s_ = param;
582 break;
583 case GL_TEXTURE_WRAP_T:
584 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
585 return GL_INVALID_ENUM;
587 wrap_t_ = param;
588 break;
589 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
590 if (param < 1) {
591 return GL_INVALID_VALUE;
593 break;
594 case GL_TEXTURE_USAGE_ANGLE:
595 if (!feature_info->validators()->texture_usage.IsValid(param)) {
596 return GL_INVALID_ENUM;
598 usage_ = param;
599 break;
600 default:
601 NOTREACHED();
602 return GL_INVALID_ENUM;
604 Update(feature_info);
605 UpdateCleared();
606 UpdateCanRenderCondition();
607 return GL_NO_ERROR;
610 GLenum Texture::SetParameterf(
611 const FeatureInfo* feature_info, GLenum pname, GLfloat param) {
612 switch (pname) {
613 case GL_TEXTURE_MIN_FILTER:
614 case GL_TEXTURE_MAG_FILTER:
615 case GL_TEXTURE_POOL_CHROMIUM:
616 case GL_TEXTURE_WRAP_S:
617 case GL_TEXTURE_WRAP_T:
618 case GL_TEXTURE_USAGE_ANGLE:
620 GLint iparam = static_cast<GLint>(param);
621 return SetParameteri(feature_info, pname, iparam);
623 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
624 if (param < 1.f) {
625 return GL_INVALID_VALUE;
627 break;
628 default:
629 NOTREACHED();
630 return GL_INVALID_ENUM;
632 return GL_NO_ERROR;
635 void Texture::Update(const FeatureInfo* feature_info) {
636 // Update npot status.
637 // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others
638 npot_ = target_ == GL_TEXTURE_EXTERNAL_OES;
640 if (level_infos_.empty()) {
641 texture_complete_ = false;
642 cube_complete_ = false;
643 return;
646 // checks that the first mip of any face is npot.
647 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
648 const Texture::LevelInfo& info = level_infos_[ii][0];
649 if (GLES2Util::IsNPOT(info.width) ||
650 GLES2Util::IsNPOT(info.height) ||
651 GLES2Util::IsNPOT(info.depth)) {
652 npot_ = true;
653 break;
657 // Update texture_complete and cube_complete status.
658 const Texture::LevelInfo& first_face = level_infos_[0][0];
659 int levels_needed = TextureManager::ComputeMipMapCount(
660 target_, first_face.width, first_face.height, first_face.depth);
661 texture_complete_ =
662 max_level_set_ >= (levels_needed - 1) && max_level_set_ >= 0;
663 cube_complete_ = (level_infos_.size() == 6) &&
664 (first_face.width == first_face.height);
666 if (first_face.width == 0 || first_face.height == 0) {
667 texture_complete_ = false;
669 if (first_face.type == GL_FLOAT &&
670 !feature_info->feature_flags().enable_texture_float_linear &&
671 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
672 mag_filter_ != GL_NEAREST)) {
673 texture_complete_ = false;
674 } else if (first_face.type == GL_HALF_FLOAT_OES &&
675 !feature_info->feature_flags().enable_texture_half_float_linear &&
676 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
677 mag_filter_ != GL_NEAREST)) {
678 texture_complete_ = false;
680 for (size_t ii = 0;
681 ii < level_infos_.size() && (cube_complete_ || texture_complete_);
682 ++ii) {
683 const Texture::LevelInfo& level0 = level_infos_[ii][0];
684 if (level0.target == 0 ||
685 level0.width != first_face.width ||
686 level0.height != first_face.height ||
687 level0.depth != 1 ||
688 level0.internal_format != first_face.internal_format ||
689 level0.format != first_face.format ||
690 level0.type != first_face.type) {
691 cube_complete_ = false;
693 // Get level0 dimensions
694 GLsizei width = level0.width;
695 GLsizei height = level0.height;
696 GLsizei depth = level0.depth;
697 for (GLint jj = 1; jj < levels_needed; ++jj) {
698 // compute required size for mip.
699 width = std::max(1, width >> 1);
700 height = std::max(1, height >> 1);
701 depth = std::max(1, depth >> 1);
702 const Texture::LevelInfo& info = level_infos_[ii][jj];
703 if (info.target == 0 ||
704 info.width != width ||
705 info.height != height ||
706 info.depth != depth ||
707 info.internal_format != level0.internal_format ||
708 info.format != level0.format ||
709 info.type != level0.type) {
710 texture_complete_ = false;
711 break;
717 bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) {
718 DCHECK(decoder);
719 if (cleared_) {
720 return true;
723 const Texture::LevelInfo& first_face = level_infos_[0][0];
724 int levels_needed = TextureManager::ComputeMipMapCount(
725 target_, first_face.width, first_face.height, first_face.depth);
727 for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
728 for (GLint jj = 0; jj < levels_needed; ++jj) {
729 Texture::LevelInfo& info = level_infos_[ii][jj];
730 if (info.target != 0) {
731 if (!ClearLevel(decoder, info.target, jj)) {
732 return false;
737 UpdateSafeToRenderFrom(true);
738 return true;
741 bool Texture::IsLevelCleared(GLenum target, GLint level) const {
742 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
743 if (face_index >= level_infos_.size() ||
744 level >= static_cast<GLint>(level_infos_[face_index].size())) {
745 return true;
748 const Texture::LevelInfo& info = level_infos_[face_index][level];
750 return info.cleared;
753 void Texture::InitTextureMaxAnisotropyIfNeeded(GLenum target) {
754 if (texture_max_anisotropy_initialized_)
755 return;
756 texture_max_anisotropy_initialized_ = true;
757 GLfloat params[] = { 1.0f };
758 glTexParameterfv(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, params);
761 bool Texture::ClearLevel(
762 GLES2Decoder* decoder, GLenum target, GLint level) {
763 DCHECK(decoder);
764 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
765 if (face_index >= level_infos_.size() ||
766 level >= static_cast<GLint>(level_infos_[face_index].size())) {
767 return true;
770 Texture::LevelInfo& info = level_infos_[face_index][level];
772 DCHECK(target == info.target);
774 if (info.target == 0 ||
775 info.cleared ||
776 info.width == 0 ||
777 info.height == 0 ||
778 info.depth == 0) {
779 return true;
782 // NOTE: It seems kind of gross to call back into the decoder for this
783 // but only the decoder knows all the state (like unpack_alignment_) that's
784 // needed to be able to call GL correctly.
785 bool cleared = decoder->ClearLevel(
786 service_id_, target_, info.target, info.level, info.internal_format,
787 info.format, info.type, info.width, info.height, immutable_);
788 UpdateMipCleared(&info, cleared);
789 return info.cleared;
792 void Texture::SetLevelImage(
793 const FeatureInfo* feature_info,
794 GLenum target,
795 GLint level,
796 gfx::GLImage* image) {
797 DCHECK_GE(level, 0);
798 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
799 DCHECK_LT(static_cast<size_t>(face_index),
800 level_infos_.size());
801 DCHECK_LT(static_cast<size_t>(level),
802 level_infos_[face_index].size());
803 Texture::LevelInfo& info =
804 level_infos_[face_index][level];
805 DCHECK_EQ(info.target, target);
806 DCHECK_EQ(info.level, level);
807 info.image = image;
808 UpdateCanRenderCondition();
809 UpdateHasImages();
812 gfx::GLImage* Texture::GetLevelImage(GLint target, GLint level) const {
813 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES &&
814 target != GL_TEXTURE_RECTANGLE_ARB) {
815 return NULL;
818 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
819 if (level >= 0 && face_index < level_infos_.size() &&
820 static_cast<size_t>(level) < level_infos_[face_index].size()) {
821 const LevelInfo& info = level_infos_[face_index][level];
822 if (info.target != 0) {
823 return info.image.get();
826 return NULL;
829 void Texture::OnWillModifyPixels() {
830 gfx::GLImage* image = GetLevelImage(target(), 0);
831 if (image)
832 image->WillModifyTexImage();
835 void Texture::OnDidModifyPixels() {
836 gfx::GLImage* image = GetLevelImage(target(), 0);
837 if (image)
838 image->DidModifyTexImage();
841 TextureRef::TextureRef(TextureManager* manager,
842 GLuint client_id,
843 Texture* texture)
844 : manager_(manager),
845 texture_(texture),
846 client_id_(client_id),
847 num_observers_(0) {
848 DCHECK(manager_);
849 DCHECK(texture_);
850 texture_->AddTextureRef(this);
851 manager_->StartTracking(this);
854 scoped_refptr<TextureRef> TextureRef::Create(TextureManager* manager,
855 GLuint client_id,
856 GLuint service_id) {
857 return new TextureRef(manager, client_id, new Texture(service_id));
860 TextureRef::~TextureRef() {
861 manager_->StopTracking(this);
862 texture_->RemoveTextureRef(this, manager_->have_context_);
863 manager_ = NULL;
866 TextureManager::TextureManager(MemoryTracker* memory_tracker,
867 FeatureInfo* feature_info,
868 GLint max_texture_size,
869 GLint max_cube_map_texture_size,
870 bool use_default_textures)
871 : memory_tracker_managed_(
872 new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)),
873 memory_tracker_unmanaged_(
874 new MemoryTypeTracker(memory_tracker, MemoryTracker::kUnmanaged)),
875 feature_info_(feature_info),
876 framebuffer_manager_(NULL),
877 max_texture_size_(max_texture_size),
878 max_cube_map_texture_size_(max_cube_map_texture_size),
879 max_levels_(ComputeMipMapCount(GL_TEXTURE_2D,
880 max_texture_size,
881 max_texture_size,
882 max_texture_size)),
883 max_cube_map_levels_(ComputeMipMapCount(GL_TEXTURE_CUBE_MAP,
884 max_cube_map_texture_size,
885 max_cube_map_texture_size,
886 max_cube_map_texture_size)),
887 use_default_textures_(use_default_textures),
888 num_unrenderable_textures_(0),
889 num_unsafe_textures_(0),
890 num_uncleared_mips_(0),
891 num_images_(0),
892 texture_count_(0),
893 have_context_(true) {
894 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
895 black_texture_ids_[ii] = 0;
899 bool TextureManager::Initialize() {
900 // TODO(gman): The default textures have to be real textures, not the 0
901 // texture because we simulate non shared resources on top of shared
902 // resources and all contexts that share resource share the same default
903 // texture.
904 default_textures_[kTexture2D] = CreateDefaultAndBlackTextures(
905 GL_TEXTURE_2D, &black_texture_ids_[kTexture2D]);
906 default_textures_[kCubeMap] = CreateDefaultAndBlackTextures(
907 GL_TEXTURE_CUBE_MAP, &black_texture_ids_[kCubeMap]);
909 if (feature_info_->feature_flags().oes_egl_image_external) {
910 default_textures_[kExternalOES] = CreateDefaultAndBlackTextures(
911 GL_TEXTURE_EXTERNAL_OES, &black_texture_ids_[kExternalOES]);
914 if (feature_info_->feature_flags().arb_texture_rectangle) {
915 default_textures_[kRectangleARB] = CreateDefaultAndBlackTextures(
916 GL_TEXTURE_RECTANGLE_ARB, &black_texture_ids_[kRectangleARB]);
919 return true;
922 scoped_refptr<TextureRef>
923 TextureManager::CreateDefaultAndBlackTextures(
924 GLenum target,
925 GLuint* black_texture) {
926 static uint8 black[] = {0, 0, 0, 255};
928 // Sampling a texture not associated with any EGLImage sibling will return
929 // black values according to the spec.
930 bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES);
931 bool needs_faces = (target == GL_TEXTURE_CUBE_MAP);
933 // Make default textures and texture for replacing non-renderable textures.
934 GLuint ids[2];
935 const int num_ids = use_default_textures_ ? 2 : 1;
936 glGenTextures(num_ids, ids);
937 for (int ii = 0; ii < num_ids; ++ii) {
938 glBindTexture(target, ids[ii]);
939 if (needs_initialization) {
940 if (needs_faces) {
941 for (int jj = 0; jj < GLES2Util::kNumFaces; ++jj) {
942 glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj), 0, GL_RGBA, 1, 1, 0,
943 GL_RGBA, GL_UNSIGNED_BYTE, black);
945 } else {
946 glTexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA,
947 GL_UNSIGNED_BYTE, black);
951 glBindTexture(target, 0);
953 scoped_refptr<TextureRef> default_texture;
954 if (use_default_textures_) {
955 default_texture = TextureRef::Create(this, 0, ids[1]);
956 SetTarget(default_texture.get(), target);
957 if (needs_faces) {
958 for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) {
959 SetLevelInfo(default_texture.get(),
960 GLES2Util::IndexToGLFaceTarget(ii),
962 GL_RGBA,
967 GL_RGBA,
968 GL_UNSIGNED_BYTE,
969 true);
971 } else {
972 if (needs_initialization) {
973 SetLevelInfo(default_texture.get(),
974 GL_TEXTURE_2D,
976 GL_RGBA,
981 GL_RGBA,
982 GL_UNSIGNED_BYTE,
983 true);
984 } else {
985 SetLevelInfo(default_texture.get(),
986 GL_TEXTURE_EXTERNAL_OES,
988 GL_RGBA,
993 GL_RGBA,
994 GL_UNSIGNED_BYTE,
995 true);
1000 *black_texture = ids[0];
1001 return default_texture;
1004 bool TextureManager::ValidForTarget(
1005 GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth) {
1006 GLsizei max_size = MaxSizeForTarget(target) >> level;
1007 return level >= 0 &&
1008 width >= 0 &&
1009 height >= 0 &&
1010 depth >= 0 &&
1011 level < MaxLevelsForTarget(target) &&
1012 width <= max_size &&
1013 height <= max_size &&
1014 depth <= max_size &&
1015 (level == 0 || feature_info_->feature_flags().npot_ok ||
1016 (!GLES2Util::IsNPOT(width) &&
1017 !GLES2Util::IsNPOT(height) &&
1018 !GLES2Util::IsNPOT(depth))) &&
1019 (target != GL_TEXTURE_CUBE_MAP || (width == height && depth == 1)) &&
1020 (target != GL_TEXTURE_2D || (depth == 1));
1023 void TextureManager::SetTarget(TextureRef* ref, GLenum target) {
1024 DCHECK(ref);
1025 ref->texture()
1026 ->SetTarget(feature_info_.get(), target, MaxLevelsForTarget(target));
1029 void TextureManager::SetLevelCleared(TextureRef* ref,
1030 GLenum target,
1031 GLint level,
1032 bool cleared) {
1033 DCHECK(ref);
1034 ref->texture()->SetLevelCleared(target, level, cleared);
1037 bool TextureManager::ClearRenderableLevels(
1038 GLES2Decoder* decoder, TextureRef* ref) {
1039 DCHECK(ref);
1040 return ref->texture()->ClearRenderableLevels(decoder);
1043 bool TextureManager::ClearTextureLevel(
1044 GLES2Decoder* decoder, TextureRef* ref,
1045 GLenum target, GLint level) {
1046 DCHECK(ref);
1047 Texture* texture = ref->texture();
1048 if (texture->num_uncleared_mips() == 0) {
1049 return true;
1051 bool result = texture->ClearLevel(decoder, target, level);
1052 texture->UpdateCleared();
1053 return result;
1056 void TextureManager::SetLevelInfo(
1057 TextureRef* ref,
1058 GLenum target,
1059 GLint level,
1060 GLenum internal_format,
1061 GLsizei width,
1062 GLsizei height,
1063 GLsizei depth,
1064 GLint border,
1065 GLenum format,
1066 GLenum type,
1067 bool cleared) {
1068 DCHECK(ref);
1069 Texture* texture = ref->texture();
1071 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1072 texture->SetLevelInfo(feature_info_.get(),
1073 target,
1074 level,
1075 internal_format,
1076 width,
1077 height,
1078 depth,
1079 border,
1080 format,
1081 type,
1082 cleared);
1083 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1086 Texture* TextureManager::Produce(TextureRef* ref) {
1087 DCHECK(ref);
1088 return ref->texture();
1091 TextureRef* TextureManager::Consume(
1092 GLuint client_id,
1093 Texture* texture) {
1094 DCHECK(client_id);
1095 scoped_refptr<TextureRef> ref(new TextureRef(this, client_id, texture));
1096 bool result = textures_.insert(std::make_pair(client_id, ref)).second;
1097 DCHECK(result);
1098 return ref.get();
1101 void TextureManager::SetParameteri(
1102 const char* function_name, ErrorState* error_state,
1103 TextureRef* ref, GLenum pname, GLint param) {
1104 DCHECK(error_state);
1105 DCHECK(ref);
1106 Texture* texture = ref->texture();
1107 GLenum result = texture->SetParameteri(feature_info_.get(), pname, param);
1108 if (result != GL_NO_ERROR) {
1109 if (result == GL_INVALID_ENUM) {
1110 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1111 error_state, function_name, param, "param");
1112 } else {
1113 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMI(
1114 error_state, result, function_name, pname, param);
1116 } else {
1117 // Texture tracking pools exist only for the command decoder, so
1118 // do not pass them on to the native GL implementation.
1119 if (pname != GL_TEXTURE_POOL_CHROMIUM) {
1120 glTexParameteri(texture->target(), pname, param);
1125 void TextureManager::SetParameterf(
1126 const char* function_name, ErrorState* error_state,
1127 TextureRef* ref, GLenum pname, GLfloat param) {
1128 DCHECK(error_state);
1129 DCHECK(ref);
1130 Texture* texture = ref->texture();
1131 GLenum result = texture->SetParameterf(feature_info_.get(), pname, param);
1132 if (result != GL_NO_ERROR) {
1133 if (result == GL_INVALID_ENUM) {
1134 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1135 error_state, function_name, param, "param");
1136 } else {
1137 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMF(
1138 error_state, result, function_name, pname, param);
1140 } else {
1141 // Texture tracking pools exist only for the command decoder, so
1142 // do not pass them on to the native GL implementation.
1143 if (pname != GL_TEXTURE_POOL_CHROMIUM) {
1144 glTexParameterf(texture->target(), pname, param);
1149 bool TextureManager::MarkMipmapsGenerated(TextureRef* ref) {
1150 DCHECK(ref);
1151 Texture* texture = ref->texture();
1152 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1153 bool result = texture->MarkMipmapsGenerated(feature_info_.get());
1154 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1155 return result;
1158 TextureRef* TextureManager::CreateTexture(
1159 GLuint client_id, GLuint service_id) {
1160 DCHECK_NE(0u, service_id);
1161 scoped_refptr<TextureRef> ref(TextureRef::Create(
1162 this, client_id, service_id));
1163 std::pair<TextureMap::iterator, bool> result =
1164 textures_.insert(std::make_pair(client_id, ref));
1165 DCHECK(result.second);
1166 return ref.get();
1169 TextureRef* TextureManager::GetTexture(
1170 GLuint client_id) const {
1171 TextureMap::const_iterator it = textures_.find(client_id);
1172 return it != textures_.end() ? it->second.get() : NULL;
1175 void TextureManager::RemoveTexture(GLuint client_id) {
1176 TextureMap::iterator it = textures_.find(client_id);
1177 if (it != textures_.end()) {
1178 it->second->reset_client_id();
1179 textures_.erase(it);
1183 void TextureManager::StartTracking(TextureRef* ref) {
1184 Texture* texture = ref->texture();
1185 ++texture_count_;
1186 num_uncleared_mips_ += texture->num_uncleared_mips();
1187 if (!texture->SafeToRenderFrom())
1188 ++num_unsafe_textures_;
1189 if (!texture->CanRender(feature_info_.get()))
1190 ++num_unrenderable_textures_;
1191 if (texture->HasImages())
1192 ++num_images_;
1195 void TextureManager::StopTracking(TextureRef* ref) {
1196 if (ref->num_observers()) {
1197 for (unsigned int i = 0; i < destruction_observers_.size(); i++) {
1198 destruction_observers_[i]->OnTextureRefDestroying(ref);
1200 DCHECK_EQ(ref->num_observers(), 0);
1203 Texture* texture = ref->texture();
1205 --texture_count_;
1206 if (texture->HasImages()) {
1207 DCHECK_NE(0, num_images_);
1208 --num_images_;
1210 if (!texture->CanRender(feature_info_.get())) {
1211 DCHECK_NE(0, num_unrenderable_textures_);
1212 --num_unrenderable_textures_;
1214 if (!texture->SafeToRenderFrom()) {
1215 DCHECK_NE(0, num_unsafe_textures_);
1216 --num_unsafe_textures_;
1218 num_uncleared_mips_ -= texture->num_uncleared_mips();
1219 DCHECK_GE(num_uncleared_mips_, 0);
1222 MemoryTypeTracker* TextureManager::GetMemTracker(GLenum tracking_pool) {
1223 switch (tracking_pool) {
1224 case GL_TEXTURE_POOL_MANAGED_CHROMIUM:
1225 return memory_tracker_managed_.get();
1226 break;
1227 case GL_TEXTURE_POOL_UNMANAGED_CHROMIUM:
1228 return memory_tracker_unmanaged_.get();
1229 break;
1230 default:
1231 break;
1233 NOTREACHED();
1234 return NULL;
1237 Texture* TextureManager::GetTextureForServiceId(GLuint service_id) const {
1238 // This doesn't need to be fast. It's only used during slow queries.
1239 for (TextureMap::const_iterator it = textures_.begin();
1240 it != textures_.end(); ++it) {
1241 Texture* texture = it->second->texture();
1242 if (texture->service_id() == service_id)
1243 return texture;
1245 return NULL;
1248 GLsizei TextureManager::ComputeMipMapCount(GLenum target,
1249 GLsizei width,
1250 GLsizei height,
1251 GLsizei depth) {
1252 switch (target) {
1253 case GL_TEXTURE_EXTERNAL_OES:
1254 return 1;
1255 default:
1256 return 1 +
1257 base::bits::Log2Floor(std::max(std::max(width, height), depth));
1261 void TextureManager::SetLevelImage(
1262 TextureRef* ref,
1263 GLenum target,
1264 GLint level,
1265 gfx::GLImage* image) {
1266 DCHECK(ref);
1267 ref->texture()->SetLevelImage(feature_info_.get(), target, level, image);
1270 void TextureManager::AddToSignature(
1271 TextureRef* ref,
1272 GLenum target,
1273 GLint level,
1274 std::string* signature) const {
1275 ref->texture()->AddToSignature(feature_info_.get(), target, level, signature);
1278 void TextureManager::UpdateSafeToRenderFrom(int delta) {
1279 num_unsafe_textures_ += delta;
1280 DCHECK_GE(num_unsafe_textures_, 0);
1283 void TextureManager::UpdateUnclearedMips(int delta) {
1284 num_uncleared_mips_ += delta;
1285 DCHECK_GE(num_uncleared_mips_, 0);
1288 void TextureManager::UpdateCanRenderCondition(
1289 Texture::CanRenderCondition old_condition,
1290 Texture::CanRenderCondition new_condition) {
1291 if (old_condition == Texture::CAN_RENDER_NEVER ||
1292 (old_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1293 !feature_info_->feature_flags().npot_ok)) {
1294 DCHECK_GT(num_unrenderable_textures_, 0);
1295 --num_unrenderable_textures_;
1297 if (new_condition == Texture::CAN_RENDER_NEVER ||
1298 (new_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1299 !feature_info_->feature_flags().npot_ok))
1300 ++num_unrenderable_textures_;
1303 void TextureManager::UpdateNumImages(int delta) {
1304 num_images_ += delta;
1305 DCHECK_GE(num_images_, 0);
1308 void TextureManager::IncFramebufferStateChangeCount() {
1309 if (framebuffer_manager_)
1310 framebuffer_manager_->IncFramebufferStateChangeCount();
1313 bool TextureManager::ValidateFormatAndTypeCombination(
1314 ErrorState* error_state, const char* function_name, GLenum format,
1315 GLenum type) {
1316 if (!feature_info_->GetTextureFormatValidator(format).IsValid(type)) {
1317 ERRORSTATE_SET_GL_ERROR(
1318 error_state, GL_INVALID_OPERATION, function_name,
1319 (std::string("invalid type ") +
1320 GLES2Util::GetStringEnum(type) + " for format " +
1321 GLES2Util::GetStringEnum(format)).c_str());
1322 return false;
1324 return true;
1327 bool TextureManager::ValidateTextureParameters(
1328 ErrorState* error_state, const char* function_name,
1329 GLenum format, GLenum type, GLenum internal_format, GLint level) {
1330 const Validators* validators = feature_info_->validators();
1331 if (!validators->texture_format.IsValid(format)) {
1332 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1333 error_state, function_name, format, "format");
1334 return false;
1336 if (!validators->pixel_type.IsValid(type)) {
1337 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1338 error_state, function_name, type, "type");
1339 return false;
1341 if (format != internal_format &&
1342 !((internal_format == GL_RGBA32F && format == GL_RGBA) ||
1343 (internal_format == GL_RGB32F && format == GL_RGB))) {
1344 ERRORSTATE_SET_GL_ERROR(
1345 error_state, GL_INVALID_OPERATION, function_name,
1346 "format != internalformat");
1347 return false;
1349 uint32 channels = GLES2Util::GetChannelsForFormat(format);
1350 if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) {
1351 ERRORSTATE_SET_GL_ERROR(
1352 error_state, GL_INVALID_OPERATION, function_name,
1353 (std::string("invalid format ") + GLES2Util::GetStringEnum(format) +
1354 " for level != 0").c_str());
1355 return false;
1357 return ValidateFormatAndTypeCombination(error_state, function_name,
1358 format, type);
1361 // Gets the texture id for a given target.
1362 TextureRef* TextureManager::GetTextureInfoForTarget(
1363 ContextState* state, GLenum target) {
1364 TextureUnit& unit = state->texture_units[state->active_texture_unit];
1365 TextureRef* texture = NULL;
1366 switch (target) {
1367 case GL_TEXTURE_2D:
1368 texture = unit.bound_texture_2d.get();
1369 break;
1370 case GL_TEXTURE_CUBE_MAP:
1371 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1372 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1373 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1374 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1375 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1376 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1377 texture = unit.bound_texture_cube_map.get();
1378 break;
1379 case GL_TEXTURE_EXTERNAL_OES:
1380 texture = unit.bound_texture_external_oes.get();
1381 break;
1382 case GL_TEXTURE_RECTANGLE_ARB:
1383 texture = unit.bound_texture_rectangle_arb.get();
1384 break;
1385 default:
1386 NOTREACHED();
1387 return NULL;
1389 return texture;
1392 TextureRef* TextureManager::GetTextureInfoForTargetUnlessDefault(
1393 ContextState* state, GLenum target) {
1394 TextureRef* texture = GetTextureInfoForTarget(state, target);
1395 if (!texture)
1396 return NULL;
1397 if (texture == GetDefaultTextureInfo(target))
1398 return NULL;
1399 return texture;
1402 bool TextureManager::ValidateTexImage2D(
1403 ContextState* state,
1404 const char* function_name,
1405 const DoTextImage2DArguments& args,
1406 TextureRef** texture_ref) {
1407 ErrorState* error_state = state->GetErrorState();
1408 const Validators* validators = feature_info_->validators();
1409 if (!validators->texture_target.IsValid(args.target)) {
1410 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1411 error_state, function_name, args.target, "target");
1412 return false;
1414 if (!validators->texture_internal_format.IsValid(args.internal_format)) {
1415 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1416 error_state, function_name, args.internal_format,
1417 "internalformat");
1418 return false;
1420 if (!ValidateTextureParameters(
1421 error_state, function_name, args.format, args.type,
1422 args.internal_format, args.level)) {
1423 return false;
1425 if (!ValidForTarget(args.target, args.level, args.width, args.height, 1) ||
1426 args.border != 0) {
1427 ERRORSTATE_SET_GL_ERROR(
1428 error_state, GL_INVALID_VALUE, function_name,
1429 "dimensions out of range");
1430 return false;
1432 if ((GLES2Util::GetChannelsForFormat(args.format) &
1433 (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && args.pixels) {
1434 ERRORSTATE_SET_GL_ERROR(
1435 error_state, GL_INVALID_OPERATION,
1436 function_name, "can not supply data for depth or stencil textures");
1437 return false;
1440 TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target);
1441 if (!local_texture_ref) {
1442 ERRORSTATE_SET_GL_ERROR(
1443 error_state, GL_INVALID_OPERATION, function_name,
1444 "unknown texture for target");
1445 return false;
1447 if (local_texture_ref->texture()->IsImmutable()) {
1448 ERRORSTATE_SET_GL_ERROR(
1449 error_state, GL_INVALID_OPERATION, function_name,
1450 "texture is immutable");
1451 return false;
1454 if (!memory_tracker_managed_->EnsureGPUMemoryAvailable(args.pixels_size)) {
1455 ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, function_name,
1456 "out of memory");
1457 return false;
1460 // Write the TextureReference since this is valid.
1461 *texture_ref = local_texture_ref;
1462 return true;
1465 void TextureManager::ValidateAndDoTexImage2D(
1466 DecoderTextureState* texture_state,
1467 ContextState* state,
1468 DecoderFramebufferState* framebuffer_state,
1469 const DoTextImage2DArguments& args) {
1470 TextureRef* texture_ref;
1471 if (!ValidateTexImage2D(state, "glTexImage2D", args, &texture_ref)) {
1472 return;
1475 DoTexImage2D(texture_state, state->GetErrorState(), framebuffer_state,
1476 texture_ref, args);
1479 void TextureManager::DoTexImage2D(
1480 DecoderTextureState* texture_state,
1481 ErrorState* error_state,
1482 DecoderFramebufferState* framebuffer_state,
1483 TextureRef* texture_ref,
1484 const DoTextImage2DArguments& args) {
1485 Texture* texture = texture_ref->texture();
1486 GLsizei tex_width = 0;
1487 GLsizei tex_height = 0;
1488 GLenum tex_type = 0;
1489 GLenum tex_format = 0;
1490 bool level_is_same =
1491 texture->GetLevelSize(args.target, args.level, &tex_width, &tex_height) &&
1492 texture->GetLevelType(args.target, args.level, &tex_type, &tex_format) &&
1493 args.width == tex_width && args.height == tex_height &&
1494 args.type == tex_type && args.format == tex_format;
1496 if (level_is_same && !args.pixels) {
1497 // Just set the level texture but mark the texture as uncleared.
1498 SetLevelInfo(
1499 texture_ref,
1500 args.target, args.level, args.internal_format, args.width, args.height,
1501 1, args.border, args.format, args.type, false);
1502 texture_state->tex_image_2d_failed = false;
1503 return;
1506 if (texture->IsAttachedToFramebuffer()) {
1507 framebuffer_state->clear_state_dirty = true;
1510 if (texture_state->texsubimage2d_faster_than_teximage2d &&
1511 level_is_same && args.pixels) {
1513 ScopedTextureUploadTimer timer(texture_state);
1514 glTexSubImage2D(args.target, args.level, 0, 0, args.width, args.height,
1515 args.format, args.type, args.pixels);
1517 SetLevelCleared(texture_ref, args.target, args.level, true);
1518 texture_state->tex_image_2d_failed = false;
1519 return;
1522 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glTexImage2D");
1524 ScopedTextureUploadTimer timer(texture_state);
1525 glTexImage2D(
1526 args.target, args.level, args.internal_format, args.width, args.height,
1527 args.border, args.format, args.type, args.pixels);
1529 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glTexImage2D");
1530 if (error == GL_NO_ERROR) {
1531 SetLevelInfo(
1532 texture_ref,
1533 args.target, args.level, args.internal_format, args.width, args.height,
1534 1, args.border, args.format, args.type, args.pixels != NULL);
1535 texture_state->tex_image_2d_failed = false;
1539 ScopedTextureUploadTimer::ScopedTextureUploadTimer(
1540 DecoderTextureState* texture_state)
1541 : texture_state_(texture_state),
1542 begin_time_(base::TimeTicks::HighResNow()) {
1545 ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
1546 texture_state_->texture_upload_count++;
1547 texture_state_->total_texture_upload_time +=
1548 base::TimeTicks::HighResNow() - begin_time_;
1551 } // namespace gles2
1552 } // namespace gpu