Linux: Depend on liberation-fonts package for RPMs.
[chromium-blink-merge.git] / gpu / command_buffer / service / texture_manager.cc
blob1dab2b87469f80726d82c6f9c322a8a0bd085cdb
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 <set>
9 #include <utility>
11 #include "base/bits.h"
12 #include "base/lazy_instance.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/trace_event/memory_dump_manager.h"
16 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
17 #include "gpu/command_buffer/service/context_state.h"
18 #include "gpu/command_buffer/service/error_state.h"
19 #include "gpu/command_buffer/service/feature_info.h"
20 #include "gpu/command_buffer/service/framebuffer_manager.h"
21 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
22 #include "gpu/command_buffer/service/mailbox_manager.h"
23 #include "gpu/command_buffer/service/memory_tracking.h"
24 #include "ui/gl/gl_implementation.h"
25 #include "ui/gl/trace_util.h"
27 namespace gpu {
28 namespace gles2 {
30 namespace {
32 // This should contain everything to uniquely identify a Texture.
33 const char TextureTag[] = "|Texture|";
34 struct TextureSignature {
35 GLenum target_;
36 GLint level_;
37 GLenum min_filter_;
38 GLenum mag_filter_;
39 GLenum wrap_r_;
40 GLenum wrap_s_;
41 GLenum wrap_t_;
42 GLenum usage_;
43 GLenum internal_format_;
44 GLenum compare_func_;
45 GLenum compare_mode_;
46 GLsizei width_;
47 GLsizei height_;
48 GLsizei depth_;
49 GLfloat max_lod_;
50 GLfloat min_lod_;
51 GLint base_level_;
52 GLint border_;
53 GLint max_level_;
54 GLenum format_;
55 GLenum type_;
56 bool has_image_;
57 bool can_render_;
58 bool can_render_to_;
59 bool npot_;
61 // Since we will be hashing this signature structure, the padding must be
62 // zero initialized. Although the C++11 specifications specify that this is
63 // true, we will use a constructor with a memset to further enforce it instead
64 // of relying on compilers adhering to this deep dark corner specification.
65 TextureSignature(GLenum target,
66 GLint level,
67 GLenum min_filter,
68 GLenum mag_filter,
69 GLenum wrap_r,
70 GLenum wrap_s,
71 GLenum wrap_t,
72 GLenum usage,
73 GLenum internal_format,
74 GLenum compare_func,
75 GLenum compare_mode,
76 GLsizei width,
77 GLsizei height,
78 GLsizei depth,
79 GLfloat max_lod,
80 GLfloat min_lod,
81 GLint base_level,
82 GLint border,
83 GLint max_level,
84 GLenum format,
85 GLenum type,
86 bool has_image,
87 bool can_render,
88 bool can_render_to,
89 bool npot) {
90 memset(this, 0, sizeof(TextureSignature));
91 target_ = target;
92 level_ = level;
93 min_filter_ = min_filter;
94 mag_filter_ = mag_filter;
95 wrap_r_ = wrap_r;
96 wrap_s_ = wrap_s;
97 wrap_t_ = wrap_t;
98 usage_ = usage;
99 internal_format_ = internal_format;
100 compare_func_ = compare_func;
101 compare_mode_ = compare_mode;
102 width_ = width;
103 height_ = height;
104 depth_ = depth;
105 max_lod_ = max_lod;
106 min_lod_ = min_lod;
107 base_level_ = base_level;
108 border_ = border;
109 max_level_ = max_level;
110 format_ = format;
111 type_ = type;
112 has_image_ = has_image;
113 can_render_ = can_render;
114 can_render_to_ = can_render_to;
115 npot_ = npot;
119 class FormatTypeValidator {
120 public:
121 FormatTypeValidator() {
122 static const FormatType kSupportedFormatTypes[] = {
123 // ES2.
124 { GL_RGB, GL_RGB, GL_UNSIGNED_BYTE },
125 { GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 },
126 { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE },
127 { GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 },
128 { GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 },
129 { GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE },
130 { GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE },
131 { GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE },
132 // Exposed by GL_OES_texture_float and GL_OES_texture_half_float
133 { GL_RGB, GL_RGB, GL_FLOAT },
134 { GL_RGBA, GL_RGBA, GL_FLOAT },
135 { GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT },
136 { GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT },
137 { GL_ALPHA, GL_ALPHA, GL_FLOAT },
138 { GL_RGB, GL_RGB, GL_HALF_FLOAT_OES },
139 { GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES },
140 { GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES },
141 { GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES },
142 { GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES },
143 // Exposed by GL_ANGLE_depth_texture
144 { GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT },
145 { GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT },
146 { GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 },
147 // Exposed by GL_EXT_sRGB
148 { GL_SRGB, GL_SRGB, GL_UNSIGNED_BYTE },
149 { GL_SRGB_ALPHA, GL_SRGB_ALPHA, GL_UNSIGNED_BYTE },
150 // Exposed by GL_EXT_texture_format_BGRA8888
151 { GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE },
152 // Exposed by GL_EXT_texture_rg
153 { GL_RED, GL_RED, GL_UNSIGNED_BYTE },
154 { GL_RG, GL_RG, GL_UNSIGNED_BYTE },
155 { GL_RED, GL_RED, GL_FLOAT },
156 { GL_RG, GL_RG, GL_FLOAT },
157 { GL_RED, GL_RED, GL_HALF_FLOAT_OES },
158 { GL_RG, GL_RG, GL_HALF_FLOAT_OES },
160 // ES3.
161 { GL_R8, GL_RED, GL_UNSIGNED_BYTE },
162 { GL_R8_SNORM, GL_RED, GL_BYTE },
163 { GL_R16F, GL_RED, GL_HALF_FLOAT },
164 { GL_R16F, GL_RED, GL_FLOAT },
165 { GL_R32F, GL_RED, GL_FLOAT },
166 { GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE },
167 { GL_R8I, GL_RED_INTEGER, GL_BYTE },
168 { GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT },
169 { GL_R16I, GL_RED_INTEGER, GL_SHORT },
170 { GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT },
171 { GL_R32I, GL_RED_INTEGER, GL_INT },
172 { GL_RG8, GL_RG, GL_UNSIGNED_BYTE },
173 { GL_RG8_SNORM, GL_RG, GL_BYTE },
174 { GL_RG16F, GL_RG, GL_HALF_FLOAT },
175 { GL_RG16F, GL_RG, GL_FLOAT },
176 { GL_RG32F, GL_RG, GL_FLOAT },
177 { GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE },
178 { GL_RG8I, GL_RG_INTEGER, GL_BYTE },
179 { GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT },
180 { GL_RG16I, GL_RG_INTEGER, GL_SHORT },
181 { GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT },
182 { GL_RG32I, GL_RG_INTEGER, GL_INT },
183 { GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE },
184 { GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE },
185 { GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE, },
186 { GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 },
187 { GL_RGB8_SNORM, GL_RGB, GL_BYTE },
188 { GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV },
189 { GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT },
190 { GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT },
191 { GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV },
192 { GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT },
193 { GL_RGB9_E5, GL_RGB, GL_FLOAT },
194 { GL_RGB16F, GL_RGB, GL_HALF_FLOAT },
195 { GL_RGB16F, GL_RGB, GL_FLOAT },
196 { GL_RGB32F, GL_RGB, GL_FLOAT },
197 { GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE },
198 { GL_RGB8I, GL_RGB_INTEGER, GL_BYTE },
199 { GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT },
200 { GL_RGB16I, GL_RGB_INTEGER, GL_SHORT },
201 { GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT },
202 { GL_RGB32I, GL_RGB_INTEGER, GL_INT },
203 { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE },
204 { GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE },
205 { GL_RGBA8_SNORM, GL_RGBA, GL_BYTE },
206 { GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE },
207 { GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 },
208 { GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV },
209 { GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE },
210 { GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 },
211 { GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV },
212 { GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT },
213 { GL_RGBA16F, GL_RGBA, GL_FLOAT },
214 { GL_RGBA32F, GL_RGBA, GL_FLOAT },
215 { GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE },
216 { GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE },
217 { GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV },
218 { GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT },
219 { GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT },
220 { GL_RGBA32I, GL_RGBA_INTEGER, GL_INT },
221 { GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT },
222 { GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT },
223 { GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT },
224 { GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT },
225 { GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT },
226 { GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 },
227 { GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL,
228 GL_FLOAT_32_UNSIGNED_INT_24_8_REV },
231 for (size_t ii = 0; ii < arraysize(kSupportedFormatTypes); ++ii) {
232 supported_combinations_.insert(kSupportedFormatTypes[ii]);
236 // This may be accessed from multiple threads.
237 bool IsValid(GLenum internal_format, GLenum format, GLenum type) const {
238 FormatType query = { internal_format, format, type };
239 return supported_combinations_.find(query) != supported_combinations_.end();
242 private:
243 // TODO(zmo): once std::tuple is allowed, switch over to that.
244 struct FormatType {
245 GLenum internal_format;
246 GLenum format;
247 GLenum type;
250 struct FormatTypeCompare {
251 bool operator() (const FormatType& lhs, const FormatType& rhs) const {
252 return (lhs.internal_format < rhs.internal_format ||
253 ((lhs.internal_format == rhs.internal_format) &&
254 (lhs.format < rhs.format)) ||
255 ((lhs.internal_format == rhs.internal_format) &&
256 (lhs.format == rhs.format) &&
257 (lhs.type < rhs.type)));
261 // This class needs to be thread safe, so once supported_combinations_
262 // are initialized in the constructor, it should never be modified later.
263 std::set<FormatType, FormatTypeCompare> supported_combinations_;
266 base::LazyInstance<const FormatTypeValidator>::Leaky g_format_type_validator =
267 LAZY_INSTANCE_INITIALIZER;
269 } // namespace anonymous
271 TextureManager::DestructionObserver::DestructionObserver() {}
273 TextureManager::DestructionObserver::~DestructionObserver() {}
275 TextureManager::~TextureManager() {
276 for (unsigned int i = 0; i < destruction_observers_.size(); i++)
277 destruction_observers_[i]->OnTextureManagerDestroying(this);
279 DCHECK(textures_.empty());
281 // If this triggers, that means something is keeping a reference to
282 // a Texture belonging to this.
283 CHECK_EQ(texture_count_, 0u);
285 DCHECK_EQ(0, num_unrenderable_textures_);
286 DCHECK_EQ(0, num_unsafe_textures_);
287 DCHECK_EQ(0, num_uncleared_mips_);
288 DCHECK_EQ(0, num_images_);
290 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
291 this);
294 void TextureManager::Destroy(bool have_context) {
295 have_context_ = have_context;
296 textures_.clear();
297 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
298 default_textures_[ii] = NULL;
301 if (have_context) {
302 glDeleteTextures(arraysize(black_texture_ids_), black_texture_ids_);
305 DCHECK_EQ(0u, memory_tracker_managed_->GetMemRepresented());
306 DCHECK_EQ(0u, memory_tracker_unmanaged_->GetMemRepresented());
309 Texture::Texture(GLuint service_id)
310 : mailbox_manager_(NULL),
311 memory_tracking_ref_(NULL),
312 service_id_(service_id),
313 cleared_(true),
314 num_uncleared_mips_(0),
315 num_npot_faces_(0),
316 target_(0),
317 min_filter_(GL_NEAREST_MIPMAP_LINEAR),
318 mag_filter_(GL_LINEAR),
319 wrap_r_(GL_REPEAT),
320 wrap_s_(GL_REPEAT),
321 wrap_t_(GL_REPEAT),
322 usage_(GL_NONE),
323 pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM),
324 compare_func_(GL_LEQUAL),
325 compare_mode_(GL_NONE),
326 max_lod_(1000.0f),
327 min_lod_(-1000.0f),
328 base_level_(0),
329 max_level_(1000),
330 max_level_set_(-1),
331 texture_complete_(false),
332 texture_mips_dirty_(false),
333 texture_mips_complete_(false),
334 cube_complete_(false),
335 texture_level0_dirty_(false),
336 texture_level0_complete_(false),
337 npot_(false),
338 has_been_bound_(false),
339 framebuffer_attachment_count_(0),
340 immutable_(false),
341 has_images_(false),
342 estimated_size_(0),
343 can_render_condition_(CAN_RENDER_ALWAYS),
344 texture_max_anisotropy_initialized_(false) {
347 Texture::~Texture() {
348 if (mailbox_manager_)
349 mailbox_manager_->TextureDeleted(this);
352 void Texture::AddTextureRef(TextureRef* ref) {
353 DCHECK(refs_.find(ref) == refs_.end());
354 refs_.insert(ref);
355 if (!memory_tracking_ref_) {
356 memory_tracking_ref_ = ref;
357 GetMemTracker()->TrackMemAlloc(estimated_size());
361 void Texture::RemoveTextureRef(TextureRef* ref, bool have_context) {
362 if (memory_tracking_ref_ == ref) {
363 GetMemTracker()->TrackMemFree(estimated_size());
364 memory_tracking_ref_ = NULL;
366 size_t result = refs_.erase(ref);
367 DCHECK_EQ(result, 1u);
368 if (refs_.empty()) {
369 if (have_context) {
370 GLuint id = service_id();
371 glDeleteTextures(1, &id);
373 delete this;
374 } else if (memory_tracking_ref_ == NULL) {
375 // TODO(piman): tune ownership semantics for cross-context group shared
376 // textures.
377 memory_tracking_ref_ = *refs_.begin();
378 GetMemTracker()->TrackMemAlloc(estimated_size());
382 MemoryTypeTracker* Texture::GetMemTracker() {
383 DCHECK(memory_tracking_ref_);
384 return memory_tracking_ref_->manager()->GetMemTracker(pool_);
387 Texture::LevelInfo::LevelInfo()
388 : target(0),
389 level(-1),
390 internal_format(0),
391 width(0),
392 height(0),
393 depth(0),
394 border(0),
395 format(0),
396 type(0),
397 estimated_size(0) {
400 Texture::LevelInfo::LevelInfo(const LevelInfo& rhs)
401 : cleared_rect(rhs.cleared_rect),
402 target(rhs.target),
403 level(rhs.level),
404 internal_format(rhs.internal_format),
405 width(rhs.width),
406 height(rhs.height),
407 depth(rhs.depth),
408 border(rhs.border),
409 format(rhs.format),
410 type(rhs.type),
411 image(rhs.image),
412 estimated_size(rhs.estimated_size) {
415 Texture::LevelInfo::~LevelInfo() {
418 Texture::FaceInfo::FaceInfo()
419 : num_mip_levels(0) {
422 Texture::FaceInfo::~FaceInfo() {
425 Texture::CanRenderCondition Texture::GetCanRenderCondition() const {
426 if (target_ == 0)
427 return CAN_RENDER_ALWAYS;
429 if (target_ != GL_TEXTURE_EXTERNAL_OES) {
430 if (face_infos_.empty()) {
431 return CAN_RENDER_NEVER;
434 const Texture::LevelInfo& first_face = face_infos_[0].level_infos[0];
435 if (first_face.width == 0 ||
436 first_face.height == 0 ||
437 first_face.depth == 0) {
438 return CAN_RENDER_NEVER;
442 bool needs_mips = NeedsMips();
443 if (needs_mips) {
444 if (!texture_complete())
445 return CAN_RENDER_NEVER;
448 if (target_ == GL_TEXTURE_CUBE_MAP && !cube_complete())
449 return CAN_RENDER_NEVER;
451 bool is_npot_compatible = !needs_mips &&
452 wrap_s_ == GL_CLAMP_TO_EDGE &&
453 wrap_t_ == GL_CLAMP_TO_EDGE;
455 if (!is_npot_compatible) {
456 if (target_ == GL_TEXTURE_RECTANGLE_ARB)
457 return CAN_RENDER_NEVER;
458 else if (npot())
459 return CAN_RENDER_ONLY_IF_NPOT;
462 return CAN_RENDER_ALWAYS;
465 bool Texture::CanRender(const FeatureInfo* feature_info) const {
466 switch (can_render_condition_) {
467 case CAN_RENDER_ALWAYS:
468 return true;
469 case CAN_RENDER_NEVER:
470 return false;
471 case CAN_RENDER_ONLY_IF_NPOT:
472 break;
474 return feature_info->feature_flags().npot_ok;
477 void Texture::AddToSignature(
478 const FeatureInfo* feature_info,
479 GLenum target,
480 GLint level,
481 std::string* signature) const {
482 DCHECK(feature_info);
483 DCHECK(signature);
484 DCHECK_GE(level, 0);
485 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
486 DCHECK_LT(static_cast<size_t>(face_index),
487 face_infos_.size());
488 DCHECK_LT(static_cast<size_t>(level),
489 face_infos_[face_index].level_infos.size());
491 const Texture::LevelInfo& info =
492 face_infos_[face_index].level_infos[level];
494 TextureSignature signature_data(target,
495 level,
496 min_filter_,
497 mag_filter_,
498 wrap_r_,
499 wrap_s_,
500 wrap_t_,
501 usage_,
502 info.internal_format,
503 compare_func_,
504 compare_mode_,
505 info.width,
506 info.height,
507 info.depth,
508 max_lod_,
509 min_lod_,
510 base_level_,
511 info.border,
512 max_level_,
513 info.format,
514 info.type,
515 info.image.get() != NULL,
516 CanRender(feature_info),
517 CanRenderTo(),
518 npot_);
520 signature->append(TextureTag, sizeof(TextureTag));
521 signature->append(reinterpret_cast<const char*>(&signature_data),
522 sizeof(signature_data));
525 void Texture::SetMailboxManager(MailboxManager* mailbox_manager) {
526 DCHECK(!mailbox_manager_ || mailbox_manager_ == mailbox_manager);
527 mailbox_manager_ = mailbox_manager;
530 bool Texture::MarkMipmapsGenerated(
531 const FeatureInfo* feature_info) {
532 if (!CanGenerateMipmaps(feature_info)) {
533 return false;
535 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
536 const Texture::FaceInfo& face_info = face_infos_[ii];
537 const Texture::LevelInfo& level0_info = face_info.level_infos[0];
538 GLsizei width = level0_info.width;
539 GLsizei height = level0_info.height;
540 GLsizei depth = level0_info.depth;
541 GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
542 GLES2Util::IndexToGLFaceTarget(ii);
544 const GLsizei num_mips = face_info.num_mip_levels;
545 for (GLsizei level = 1; level < num_mips; ++level) {
546 width = std::max(1, width >> 1);
547 height = std::max(1, height >> 1);
548 depth = std::max(1, depth >> 1);
549 SetLevelInfo(feature_info, target, level, level0_info.internal_format,
550 width, height, depth, level0_info.border, level0_info.format,
551 level0_info.type, gfx::Rect(width, height));
555 return true;
558 void Texture::SetTarget(
559 const FeatureInfo* feature_info, GLenum target, GLint max_levels) {
560 DCHECK_EQ(0u, target_); // you can only set this once.
561 target_ = target;
562 size_t num_faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
563 face_infos_.resize(num_faces);
564 for (size_t ii = 0; ii < num_faces; ++ii) {
565 face_infos_[ii].level_infos.resize(max_levels);
568 if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) {
569 min_filter_ = GL_LINEAR;
570 wrap_s_ = wrap_t_ = GL_CLAMP_TO_EDGE;
573 if (target == GL_TEXTURE_EXTERNAL_OES) {
574 immutable_ = true;
576 Update(feature_info);
577 UpdateCanRenderCondition();
580 bool Texture::CanGenerateMipmaps(
581 const FeatureInfo* feature_info) const {
582 if ((npot() && !feature_info->feature_flags().npot_ok) ||
583 face_infos_.empty() ||
584 target_ == GL_TEXTURE_EXTERNAL_OES ||
585 target_ == GL_TEXTURE_RECTANGLE_ARB) {
586 return false;
589 if (static_cast<size_t>(base_level_) >= face_infos_[0].level_infos.size()) {
590 return false;
593 // Can't generate mips for depth or stencil textures.
594 const Texture::LevelInfo& base = face_infos_[0].level_infos[base_level_];
595 uint32 channels = GLES2Util::GetChannelsForFormat(base.format);
596 if (channels & (GLES2Util::kDepth | GLES2Util::kStencil)) {
597 return false;
600 // TODO(gman): Check internal_format, format and type.
601 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
602 const LevelInfo& info = face_infos_[ii].level_infos[base_level_];
603 if ((info.target == 0) || (info.width != base.width) ||
604 (info.height != base.height) || (info.depth != base.depth) ||
605 (info.format != base.format) ||
606 (info.internal_format != base.internal_format) ||
607 (info.type != base.type) ||
608 feature_info->validators()->compressed_texture_format.IsValid(
609 info.internal_format) ||
610 info.image.get()) {
611 return false;
614 return true;
617 bool Texture::TextureIsNPOT(GLsizei width,
618 GLsizei height,
619 GLsizei depth) {
620 return (GLES2Util::IsNPOT(width) ||
621 GLES2Util::IsNPOT(height) ||
622 GLES2Util::IsNPOT(depth));
625 bool Texture::TextureFaceComplete(const Texture::LevelInfo& first_face,
626 size_t face_index,
627 GLenum target,
628 GLenum internal_format,
629 GLsizei width,
630 GLsizei height,
631 GLsizei depth,
632 GLenum format,
633 GLenum type) {
634 bool complete = (target != 0 && depth == 1);
635 if (face_index != 0) {
636 complete &= (width == first_face.width &&
637 height == first_face.height &&
638 internal_format == first_face.internal_format &&
639 format == first_face.format &&
640 type == first_face.type);
642 return complete;
645 bool Texture::TextureMipComplete(const Texture::LevelInfo& level0_face,
646 GLenum target,
647 GLint level,
648 GLenum internal_format,
649 GLsizei width,
650 GLsizei height,
651 GLsizei depth,
652 GLenum format,
653 GLenum type) {
654 bool complete = (target != 0);
655 if (level != 0) {
656 const GLsizei mip_width = std::max(1, level0_face.width >> level);
657 const GLsizei mip_height = std::max(1, level0_face.height >> level);
658 const GLsizei mip_depth = std::max(1, level0_face.depth >> level);
660 complete &= (width == mip_width &&
661 height == mip_height &&
662 depth == mip_depth &&
663 internal_format == level0_face.internal_format &&
664 format == level0_face.format &&
665 type == level0_face.type);
667 return complete;
670 void Texture::SetLevelClearedRect(GLenum target,
671 GLint level,
672 const gfx::Rect& cleared_rect) {
673 DCHECK_GE(level, 0);
674 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
675 DCHECK_LT(static_cast<size_t>(face_index),
676 face_infos_.size());
677 DCHECK_LT(static_cast<size_t>(level),
678 face_infos_[face_index].level_infos.size());
679 Texture::LevelInfo& info =
680 face_infos_[face_index].level_infos[level];
681 UpdateMipCleared(&info, info.width, info.height, cleared_rect);
682 UpdateCleared();
685 void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) {
686 DCHECK_GE(level, 0);
687 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
688 DCHECK_LT(static_cast<size_t>(face_index), face_infos_.size());
689 DCHECK_LT(static_cast<size_t>(level),
690 face_infos_[face_index].level_infos.size());
691 Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
692 UpdateMipCleared(&info, info.width, info.height,
693 cleared ? gfx::Rect(info.width, info.height) : gfx::Rect());
694 UpdateCleared();
697 void Texture::UpdateCleared() {
698 if (face_infos_.empty()) {
699 return;
702 const bool cleared = (num_uncleared_mips_ == 0);
704 // If texture is uncleared and is attached to a framebuffer,
705 // that framebuffer must be marked possibly incomplete.
706 if (!cleared && IsAttachedToFramebuffer()) {
707 IncAllFramebufferStateChangeCount();
710 UpdateSafeToRenderFrom(cleared);
713 void Texture::UpdateSafeToRenderFrom(bool cleared) {
714 if (cleared_ == cleared)
715 return;
716 cleared_ = cleared;
717 int delta = cleared ? -1 : +1;
718 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
719 (*it)->manager()->UpdateSafeToRenderFrom(delta);
722 void Texture::UpdateMipCleared(LevelInfo* info,
723 GLsizei width,
724 GLsizei height,
725 const gfx::Rect& cleared_rect) {
726 bool was_cleared = info->cleared_rect == gfx::Rect(info->width, info->height);
727 info->width = width;
728 info->height = height;
729 info->cleared_rect = cleared_rect;
730 bool cleared = info->cleared_rect == gfx::Rect(info->width, info->height);
731 if (cleared == was_cleared)
732 return;
733 int delta = cleared ? -1 : +1;
734 num_uncleared_mips_ += delta;
735 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
736 (*it)->manager()->UpdateUnclearedMips(delta);
739 void Texture::UpdateCanRenderCondition() {
740 CanRenderCondition can_render_condition = GetCanRenderCondition();
741 if (can_render_condition_ == can_render_condition)
742 return;
743 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
744 (*it)->manager()->UpdateCanRenderCondition(can_render_condition_,
745 can_render_condition);
746 can_render_condition_ = can_render_condition;
749 void Texture::UpdateHasImages() {
750 if (face_infos_.empty())
751 return;
753 bool has_images = false;
754 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
755 for (size_t jj = 0; jj < face_infos_[ii].level_infos.size(); ++jj) {
756 const Texture::LevelInfo& info = face_infos_[ii].level_infos[jj];
757 if (info.image.get() != NULL) {
758 has_images = true;
759 break;
764 if (has_images_ == has_images)
765 return;
766 has_images_ = has_images;
767 int delta = has_images ? +1 : -1;
768 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
769 (*it)->manager()->UpdateNumImages(delta);
772 void Texture::IncAllFramebufferStateChangeCount() {
773 for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
774 (*it)->manager()->IncFramebufferStateChangeCount();
777 void Texture::SetLevelInfo(const FeatureInfo* feature_info,
778 GLenum target,
779 GLint level,
780 GLenum internal_format,
781 GLsizei width,
782 GLsizei height,
783 GLsizei depth,
784 GLint border,
785 GLenum format,
786 GLenum type,
787 const gfx::Rect& cleared_rect) {
788 DCHECK_GE(level, 0);
789 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
790 DCHECK_LT(static_cast<size_t>(face_index),
791 face_infos_.size());
792 DCHECK_LT(static_cast<size_t>(level),
793 face_infos_[face_index].level_infos.size());
794 DCHECK_GE(width, 0);
795 DCHECK_GE(height, 0);
796 DCHECK_GE(depth, 0);
797 Texture::LevelInfo& info =
798 face_infos_[face_index].level_infos[level];
800 // Update counters only if any attributes have changed. Counters are
801 // comparisons between the old and new values so it must be done before any
802 // assignment has been done to the LevelInfo.
803 if (info.target != target ||
804 info.internal_format != internal_format ||
805 info.width != width ||
806 info.height != height ||
807 info.depth != depth ||
808 info.format != format ||
809 info.type != type) {
810 if (level == 0) {
811 // Calculate the mip level count.
812 face_infos_[face_index].num_mip_levels =
813 TextureManager::ComputeMipMapCount(target_, width, height, depth);
815 // Update NPOT face count for the first level.
816 bool prev_npot = TextureIsNPOT(info.width, info.height, info.depth);
817 bool now_npot = TextureIsNPOT(width, height, depth);
818 if (prev_npot != now_npot)
819 num_npot_faces_ += now_npot ? 1 : -1;
821 // Signify that level 0 has been changed, so they need to be reverified.
822 texture_level0_dirty_ = true;
825 // Signify that at least one of the mips has changed.
826 texture_mips_dirty_ = true;
829 info.target = target;
830 info.level = level;
831 info.internal_format = internal_format;
832 info.depth = depth;
833 info.border = border;
834 info.format = format;
835 info.type = type;
836 info.image = 0;
838 UpdateMipCleared(&info, width, height, cleared_rect);
840 estimated_size_ -= info.estimated_size;
841 GLES2Util::ComputeImageDataSizes(
842 width, height, 1, format, type, 4, &info.estimated_size, NULL, NULL);
843 estimated_size_ += info.estimated_size;
845 max_level_set_ = std::max(max_level_set_, level);
846 Update(feature_info);
847 UpdateCleared();
848 UpdateCanRenderCondition();
849 UpdateHasImages();
850 if (IsAttachedToFramebuffer()) {
851 // TODO(gman): If textures tracked which framebuffers they were attached to
852 // we could just mark those framebuffers as not complete.
853 IncAllFramebufferStateChangeCount();
857 bool Texture::ValidForTexture(
858 GLint target,
859 GLint level,
860 GLint xoffset,
861 GLint yoffset,
862 GLint zoffset,
863 GLsizei width,
864 GLsizei height,
865 GLsizei depth) const {
866 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
867 if (level >= 0 && face_index < face_infos_.size() &&
868 static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
869 const LevelInfo& info = face_infos_[face_index].level_infos[level];
870 int32 max_x;
871 int32 max_y;
872 int32 max_z;
873 return SafeAddInt32(xoffset, width, &max_x) &&
874 SafeAddInt32(yoffset, height, &max_y) &&
875 SafeAddInt32(zoffset, depth, &max_z) &&
876 xoffset >= 0 &&
877 yoffset >= 0 &&
878 zoffset >= 0 &&
879 max_x <= info.width &&
880 max_y <= info.height &&
881 max_z <= info.depth;
883 return false;
886 bool Texture::GetLevelSize(
887 GLint target, GLint level,
888 GLsizei* width, GLsizei* height, GLsizei* depth) const {
889 DCHECK(width);
890 DCHECK(height);
891 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
892 if (level >= 0 && face_index < face_infos_.size() &&
893 static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
894 const LevelInfo& info = face_infos_[face_index].level_infos[level];
895 if (info.target != 0) {
896 *width = info.width;
897 *height = info.height;
898 if (depth)
899 *depth = info.depth;
900 return true;
903 return false;
906 bool Texture::GetLevelType(
907 GLint target, GLint level, GLenum* type, GLenum* internal_format) const {
908 DCHECK(type);
909 DCHECK(internal_format);
910 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
911 if (level >= 0 && face_index < face_infos_.size() &&
912 static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
913 const LevelInfo& info = face_infos_[face_index].level_infos[level];
914 if (info.target != 0) {
915 *type = info.type;
916 *internal_format = info.internal_format;
917 return true;
920 return false;
923 GLenum Texture::SetParameteri(
924 const FeatureInfo* feature_info, GLenum pname, GLint param) {
925 DCHECK(feature_info);
927 if (target_ == GL_TEXTURE_EXTERNAL_OES ||
928 target_ == GL_TEXTURE_RECTANGLE_ARB) {
929 if (pname == GL_TEXTURE_MIN_FILTER &&
930 (param != GL_NEAREST && param != GL_LINEAR))
931 return GL_INVALID_ENUM;
932 if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) &&
933 param != GL_CLAMP_TO_EDGE)
934 return GL_INVALID_ENUM;
937 switch (pname) {
938 case GL_TEXTURE_MIN_LOD:
939 case GL_TEXTURE_MAX_LOD:
941 GLfloat fparam = static_cast<GLfloat>(param);
942 return SetParameterf(feature_info, pname, fparam);
944 case GL_TEXTURE_MIN_FILTER:
945 if (!feature_info->validators()->texture_min_filter_mode.IsValid(param)) {
946 return GL_INVALID_ENUM;
948 min_filter_ = param;
949 break;
950 case GL_TEXTURE_MAG_FILTER:
951 if (!feature_info->validators()->texture_mag_filter_mode.IsValid(param)) {
952 return GL_INVALID_ENUM;
954 mag_filter_ = param;
955 break;
956 case GL_TEXTURE_POOL_CHROMIUM:
957 if (!feature_info->validators()->texture_pool.IsValid(param)) {
958 return GL_INVALID_ENUM;
960 GetMemTracker()->TrackMemFree(estimated_size());
961 pool_ = param;
962 GetMemTracker()->TrackMemAlloc(estimated_size());
963 break;
964 case GL_TEXTURE_WRAP_R:
965 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
966 return GL_INVALID_ENUM;
968 wrap_r_ = param;
969 break;
970 case GL_TEXTURE_WRAP_S:
971 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
972 return GL_INVALID_ENUM;
974 wrap_s_ = param;
975 break;
976 case GL_TEXTURE_WRAP_T:
977 if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
978 return GL_INVALID_ENUM;
980 wrap_t_ = param;
981 break;
982 case GL_TEXTURE_COMPARE_FUNC:
983 if (!feature_info->validators()->texture_compare_func.IsValid(param)) {
984 return GL_INVALID_ENUM;
986 compare_func_ = param;
987 break;
988 case GL_TEXTURE_COMPARE_MODE:
989 if (!feature_info->validators()->texture_compare_mode.IsValid(param)) {
990 return GL_INVALID_ENUM;
992 compare_mode_ = param;
993 break;
994 case GL_TEXTURE_BASE_LEVEL:
995 if (param < 0) {
996 return GL_INVALID_VALUE;
998 base_level_ = param;
999 break;
1000 case GL_TEXTURE_MAX_LEVEL:
1001 if (param < 0) {
1002 return GL_INVALID_VALUE;
1004 max_level_ = param;
1005 break;
1006 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
1007 if (param < 1) {
1008 return GL_INVALID_VALUE;
1010 break;
1011 case GL_TEXTURE_USAGE_ANGLE:
1012 if (!feature_info->validators()->texture_usage.IsValid(param)) {
1013 return GL_INVALID_ENUM;
1015 usage_ = param;
1016 break;
1017 default:
1018 NOTREACHED();
1019 return GL_INVALID_ENUM;
1021 Update(feature_info);
1022 UpdateCleared();
1023 UpdateCanRenderCondition();
1024 return GL_NO_ERROR;
1027 GLenum Texture::SetParameterf(
1028 const FeatureInfo* feature_info, GLenum pname, GLfloat param) {
1029 switch (pname) {
1030 case GL_TEXTURE_MIN_FILTER:
1031 case GL_TEXTURE_MAG_FILTER:
1032 case GL_TEXTURE_POOL_CHROMIUM:
1033 case GL_TEXTURE_WRAP_R:
1034 case GL_TEXTURE_WRAP_S:
1035 case GL_TEXTURE_WRAP_T:
1036 case GL_TEXTURE_COMPARE_FUNC:
1037 case GL_TEXTURE_COMPARE_MODE:
1038 case GL_TEXTURE_BASE_LEVEL:
1039 case GL_TEXTURE_MAX_LEVEL:
1040 case GL_TEXTURE_USAGE_ANGLE:
1042 GLint iparam = static_cast<GLint>(param);
1043 return SetParameteri(feature_info, pname, iparam);
1045 case GL_TEXTURE_MIN_LOD:
1046 min_lod_ = param;
1047 break;
1048 case GL_TEXTURE_MAX_LOD:
1049 max_lod_ = param;
1050 break;
1051 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
1052 if (param < 1.f) {
1053 return GL_INVALID_VALUE;
1055 break;
1056 default:
1057 NOTREACHED();
1058 return GL_INVALID_ENUM;
1060 return GL_NO_ERROR;
1063 void Texture::Update(const FeatureInfo* feature_info) {
1064 // Update npot status.
1065 // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others
1066 npot_ = (target_ == GL_TEXTURE_EXTERNAL_OES) || (num_npot_faces_ > 0);
1068 if (face_infos_.empty()) {
1069 texture_complete_ = false;
1070 cube_complete_ = false;
1071 return;
1074 // Update texture_complete and cube_complete status.
1075 const Texture::FaceInfo& first_face = face_infos_[0];
1076 const Texture::LevelInfo& first_level = first_face.level_infos[0];
1077 const GLsizei levels_needed = first_face.num_mip_levels;
1079 texture_complete_ =
1080 max_level_set_ >= (levels_needed - 1) && max_level_set_ >= 0;
1081 cube_complete_ = (face_infos_.size() == 6) &&
1082 (first_level.width == first_level.height);
1084 if (first_level.width == 0 || first_level.height == 0) {
1085 texture_complete_ = false;
1086 } else if (first_level.type == GL_FLOAT &&
1087 !feature_info->feature_flags().enable_texture_float_linear &&
1088 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
1089 mag_filter_ != GL_NEAREST)) {
1090 texture_complete_ = false;
1091 } else if (first_level.type == GL_HALF_FLOAT_OES &&
1092 !feature_info->feature_flags().enable_texture_half_float_linear &&
1093 (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
1094 mag_filter_ != GL_NEAREST)) {
1095 texture_complete_ = false;
1098 if (cube_complete_ && texture_level0_dirty_) {
1099 texture_level0_complete_ = true;
1100 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
1101 const Texture::LevelInfo& level0 = face_infos_[ii].level_infos[0];
1102 if (!TextureFaceComplete(first_level,
1104 level0.target,
1105 level0.internal_format,
1106 level0.width,
1107 level0.height,
1108 level0.depth,
1109 level0.format,
1110 level0.type)) {
1111 texture_level0_complete_ = false;
1112 break;
1115 texture_level0_dirty_ = false;
1117 cube_complete_ &= texture_level0_complete_;
1119 if (texture_complete_ && texture_mips_dirty_) {
1120 texture_mips_complete_ = true;
1121 for (size_t ii = 0;
1122 ii < face_infos_.size() && texture_mips_complete_;
1123 ++ii) {
1124 const Texture::FaceInfo& face_info = face_infos_[ii];
1125 const Texture::LevelInfo& level0 = face_info.level_infos[0];
1126 for (GLsizei jj = 1; jj < levels_needed; ++jj) {
1127 const Texture::LevelInfo& level_info = face_infos_[ii].level_infos[jj];
1128 if (!TextureMipComplete(level0,
1129 level_info.target,
1131 level_info.internal_format,
1132 level_info.width,
1133 level_info.height,
1134 level_info.depth,
1135 level_info.format,
1136 level_info.type)) {
1137 texture_mips_complete_ = false;
1138 break;
1142 texture_mips_dirty_ = false;
1144 texture_complete_ &= texture_mips_complete_;
1147 bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) {
1148 DCHECK(decoder);
1149 if (cleared_) {
1150 return true;
1153 for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
1154 const Texture::FaceInfo& face_info = face_infos_[ii];
1155 for (GLint jj = 0; jj < face_info.num_mip_levels; ++jj) {
1156 const Texture::LevelInfo& info = face_info.level_infos[jj];
1157 if (info.target != 0) {
1158 if (!ClearLevel(decoder, info.target, jj)) {
1159 return false;
1164 UpdateSafeToRenderFrom(true);
1165 return true;
1168 gfx::Rect Texture::GetLevelClearedRect(GLenum target, GLint level) const {
1169 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
1170 if (face_index >= face_infos_.size() ||
1171 level >= static_cast<GLint>(face_infos_[face_index].level_infos.size())) {
1172 return gfx::Rect();
1175 const Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
1177 return info.cleared_rect;
1180 bool Texture::IsLevelCleared(GLenum target, GLint level) const {
1181 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
1182 if (face_index >= face_infos_.size() ||
1183 level >= static_cast<GLint>(face_infos_[face_index].level_infos.size())) {
1184 return true;
1187 const Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
1189 return info.cleared_rect == gfx::Rect(info.width, info.height);
1192 void Texture::InitTextureMaxAnisotropyIfNeeded(GLenum target) {
1193 if (texture_max_anisotropy_initialized_)
1194 return;
1195 texture_max_anisotropy_initialized_ = true;
1196 GLfloat params[] = { 1.0f };
1197 glTexParameterfv(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, params);
1200 bool Texture::ClearLevel(
1201 GLES2Decoder* decoder, GLenum target, GLint level) {
1202 DCHECK(decoder);
1203 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
1204 if (face_index >= face_infos_.size() ||
1205 level >= static_cast<GLint>(face_infos_[face_index].level_infos.size())) {
1206 return true;
1209 Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
1211 DCHECK(target == info.target);
1213 if (info.target == 0 ||
1214 info.cleared_rect == gfx::Rect(info.width, info.height) ||
1215 info.width == 0 || info.height == 0 || info.depth == 0) {
1216 return true;
1219 // Clear all remaining sub regions.
1220 const int x[] = {
1221 0, info.cleared_rect.x(), info.cleared_rect.right(), info.width};
1222 const int y[] = {
1223 0, info.cleared_rect.y(), info.cleared_rect.bottom(), info.height};
1225 for (size_t j = 0; j < 3; ++j) {
1226 for (size_t i = 0; i < 3; ++i) {
1227 // Center of nine patch is already cleared.
1228 if (j == 1 && i == 1)
1229 continue;
1231 gfx::Rect rect(x[i], y[j], x[i + 1] - x[i], y[j + 1] - y[j]);
1232 if (rect.IsEmpty())
1233 continue;
1235 // NOTE: It seems kind of gross to call back into the decoder for this
1236 // but only the decoder knows all the state (like unpack_alignment_)
1237 // that's needed to be able to call GL correctly.
1238 bool cleared = decoder->ClearLevel(this, info.target, info.level,
1239 info.format, info.type, rect.x(),
1240 rect.y(), rect.width(), rect.height());
1241 if (!cleared)
1242 return false;
1246 UpdateMipCleared(&info, info.width, info.height,
1247 gfx::Rect(info.width, info.height));
1248 return true;
1251 void Texture::SetLevelImage(
1252 const FeatureInfo* feature_info,
1253 GLenum target,
1254 GLint level,
1255 gfx::GLImage* image) {
1256 DCHECK_GE(level, 0);
1257 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
1258 DCHECK_LT(static_cast<size_t>(face_index),
1259 face_infos_.size());
1260 DCHECK_LT(static_cast<size_t>(level),
1261 face_infos_[face_index].level_infos.size());
1262 Texture::LevelInfo& info =
1263 face_infos_[face_index].level_infos[level];
1264 DCHECK_EQ(info.target, target);
1265 DCHECK_EQ(info.level, level);
1266 info.image = image;
1267 UpdateCanRenderCondition();
1268 UpdateHasImages();
1270 // TODO(ericrk): Images may have complex sizing not accounted for by
1271 // |estimated_size_|, we should add logic here to update |estimated_size_|
1272 // based on the new GLImage. crbug.com/526298
1275 gfx::GLImage* Texture::GetLevelImage(GLint target, GLint level) const {
1276 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES &&
1277 target != GL_TEXTURE_RECTANGLE_ARB) {
1278 return NULL;
1281 size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
1282 if (level >= 0 && face_index < face_infos_.size() &&
1283 static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
1284 const LevelInfo& info = face_infos_[face_index].level_infos[level];
1285 if (info.target != 0) {
1286 return info.image.get();
1289 return NULL;
1292 void Texture::OnWillModifyPixels() {
1293 gfx::GLImage* image = GetLevelImage(target(), 0);
1294 if (image)
1295 image->WillModifyTexImage();
1298 void Texture::OnDidModifyPixels() {
1299 gfx::GLImage* image = GetLevelImage(target(), 0);
1300 if (image)
1301 image->DidModifyTexImage();
1304 void Texture::DumpLevelMemory(base::trace_event::ProcessMemoryDump* pmd,
1305 uint64_t client_tracing_id,
1306 const std::string& dump_name) const {
1307 for (uint32_t face_index = 0; face_index < face_infos_.size(); ++face_index) {
1308 const auto& level_infos = face_infos_[face_index].level_infos;
1309 for (uint32_t level_index = 0; level_index < level_infos.size();
1310 ++level_index) {
1311 // Skip levels with no size. Textures will have empty levels for all
1312 // potential mip levels which are not in use.
1313 if (!level_infos[level_index].estimated_size)
1314 continue;
1316 if (level_infos[level_index].image) {
1317 // If a level is backed by a GLImage, ask the GLImage to dump itself.
1318 level_infos[level_index].image->OnMemoryDump(
1319 pmd, client_tracing_id,
1320 base::StringPrintf("%s/face_%d/level_%d", dump_name.c_str(),
1321 face_index, level_index));
1322 } else {
1323 // If a level is not backed by a GLImage, create a simple dump.
1324 base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
1325 base::StringPrintf("%s/face_%d/level_%d", dump_name.c_str(),
1326 face_index, level_index));
1327 dump->AddScalar(
1328 base::trace_event::MemoryAllocatorDump::kNameSize,
1329 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
1330 static_cast<uint64_t>(level_infos[level_index].estimated_size));
1336 TextureRef::TextureRef(TextureManager* manager,
1337 GLuint client_id,
1338 Texture* texture)
1339 : manager_(manager),
1340 texture_(texture),
1341 client_id_(client_id),
1342 num_observers_(0) {
1343 DCHECK(manager_);
1344 DCHECK(texture_);
1345 texture_->AddTextureRef(this);
1346 manager_->StartTracking(this);
1349 scoped_refptr<TextureRef> TextureRef::Create(TextureManager* manager,
1350 GLuint client_id,
1351 GLuint service_id) {
1352 return new TextureRef(manager, client_id, new Texture(service_id));
1355 TextureRef::~TextureRef() {
1356 manager_->StopTracking(this);
1357 texture_->RemoveTextureRef(this, manager_->have_context_);
1358 manager_ = NULL;
1361 TextureManager::TextureManager(MemoryTracker* memory_tracker,
1362 FeatureInfo* feature_info,
1363 GLint max_texture_size,
1364 GLint max_cube_map_texture_size,
1365 GLint max_rectangle_texture_size,
1366 GLint max_3d_texture_size,
1367 bool use_default_textures)
1368 : memory_tracker_managed_(
1369 new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)),
1370 memory_tracker_unmanaged_(
1371 new MemoryTypeTracker(memory_tracker, MemoryTracker::kUnmanaged)),
1372 memory_tracker_(memory_tracker),
1373 feature_info_(feature_info),
1374 framebuffer_manager_(NULL),
1375 max_texture_size_(max_texture_size),
1376 max_cube_map_texture_size_(max_cube_map_texture_size),
1377 max_rectangle_texture_size_(max_rectangle_texture_size),
1378 max_3d_texture_size_(max_3d_texture_size),
1379 max_levels_(ComputeMipMapCount(GL_TEXTURE_2D,
1380 max_texture_size,
1381 max_texture_size,
1382 max_texture_size)),
1383 max_cube_map_levels_(ComputeMipMapCount(GL_TEXTURE_CUBE_MAP,
1384 max_cube_map_texture_size,
1385 max_cube_map_texture_size,
1386 max_cube_map_texture_size)),
1387 max_3d_levels_(ComputeMipMapCount(GL_TEXTURE_3D,
1388 // Same as GL_TEXTURE_2D_ARRAY
1389 max_3d_texture_size,
1390 max_3d_texture_size,
1391 max_3d_texture_size)),
1392 use_default_textures_(use_default_textures),
1393 num_unrenderable_textures_(0),
1394 num_unsafe_textures_(0),
1395 num_uncleared_mips_(0),
1396 num_images_(0),
1397 texture_count_(0),
1398 have_context_(true) {
1399 for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
1400 black_texture_ids_[ii] = 0;
1404 bool TextureManager::Initialize() {
1405 // TODO(gman): The default textures have to be real textures, not the 0
1406 // texture because we simulate non shared resources on top of shared
1407 // resources and all contexts that share resource share the same default
1408 // texture.
1409 default_textures_[kTexture2D] = CreateDefaultAndBlackTextures(
1410 GL_TEXTURE_2D, &black_texture_ids_[kTexture2D]);
1411 default_textures_[kCubeMap] = CreateDefaultAndBlackTextures(
1412 GL_TEXTURE_CUBE_MAP, &black_texture_ids_[kCubeMap]);
1414 if (feature_info_->IsES3Enabled()) {
1415 default_textures_[kTexture3D] = CreateDefaultAndBlackTextures(
1416 GL_TEXTURE_3D, &black_texture_ids_[kTexture3D]);
1417 default_textures_[kTexture2DArray] = CreateDefaultAndBlackTextures(
1418 GL_TEXTURE_2D_ARRAY, &black_texture_ids_[kTexture2DArray]);
1421 if (feature_info_->feature_flags().oes_egl_image_external) {
1422 default_textures_[kExternalOES] = CreateDefaultAndBlackTextures(
1423 GL_TEXTURE_EXTERNAL_OES, &black_texture_ids_[kExternalOES]);
1426 if (feature_info_->feature_flags().arb_texture_rectangle) {
1427 default_textures_[kRectangleARB] = CreateDefaultAndBlackTextures(
1428 GL_TEXTURE_RECTANGLE_ARB, &black_texture_ids_[kRectangleARB]);
1431 // When created from InProcessCommandBuffer, we won't have a |memory_tracker_|
1432 // so don't register a dump provider.
1433 if (memory_tracker_) {
1434 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
1435 this, base::ThreadTaskRunnerHandle::Get());
1438 return true;
1441 scoped_refptr<TextureRef>
1442 TextureManager::CreateDefaultAndBlackTextures(
1443 GLenum target,
1444 GLuint* black_texture) {
1445 static uint8 black[] = {0, 0, 0, 255};
1447 // Sampling a texture not associated with any EGLImage sibling will return
1448 // black values according to the spec.
1449 bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES);
1450 bool needs_faces = (target == GL_TEXTURE_CUBE_MAP);
1451 bool is_3d_or_2d_array_target = (target == GL_TEXTURE_3D ||
1452 target == GL_TEXTURE_2D_ARRAY);
1454 // Make default textures and texture for replacing non-renderable textures.
1455 GLuint ids[2];
1456 const int num_ids = use_default_textures_ ? 2 : 1;
1457 glGenTextures(num_ids, ids);
1458 for (int ii = 0; ii < num_ids; ++ii) {
1459 glBindTexture(target, ids[ii]);
1460 if (needs_initialization) {
1461 if (needs_faces) {
1462 for (int jj = 0; jj < GLES2Util::kNumFaces; ++jj) {
1463 glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj), 0, GL_RGBA, 1, 1, 0,
1464 GL_RGBA, GL_UNSIGNED_BYTE, black);
1466 } else {
1467 if (is_3d_or_2d_array_target) {
1468 glTexImage3D(target, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA,
1469 GL_UNSIGNED_BYTE, black);
1470 } else {
1471 glTexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA,
1472 GL_UNSIGNED_BYTE, black);
1477 glBindTexture(target, 0);
1479 scoped_refptr<TextureRef> default_texture;
1480 if (use_default_textures_) {
1481 default_texture = TextureRef::Create(this, 0, ids[1]);
1482 SetTarget(default_texture.get(), target);
1483 if (needs_faces) {
1484 for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) {
1485 SetLevelInfo(default_texture.get(), GLES2Util::IndexToGLFaceTarget(ii),
1486 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1487 gfx::Rect(1, 1));
1489 } else {
1490 if (needs_initialization) {
1491 SetLevelInfo(default_texture.get(), GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1,
1492 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
1493 } else {
1494 SetLevelInfo(default_texture.get(), GL_TEXTURE_EXTERNAL_OES, 0, GL_RGBA,
1495 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
1500 *black_texture = ids[0];
1501 return default_texture;
1504 bool TextureManager::ValidForTarget(
1505 GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth) {
1506 GLsizei max_size = MaxSizeForTarget(target) >> level;
1507 return level >= 0 &&
1508 width >= 0 &&
1509 height >= 0 &&
1510 depth >= 0 &&
1511 level < MaxLevelsForTarget(target) &&
1512 width <= max_size &&
1513 height <= max_size &&
1514 depth <= max_size &&
1515 (level == 0 || feature_info_->feature_flags().npot_ok ||
1516 (!GLES2Util::IsNPOT(width) &&
1517 !GLES2Util::IsNPOT(height) &&
1518 !GLES2Util::IsNPOT(depth))) &&
1519 (target != GL_TEXTURE_CUBE_MAP || (width == height && depth == 1)) &&
1520 (target != GL_TEXTURE_2D || (depth == 1));
1523 void TextureManager::SetTarget(TextureRef* ref, GLenum target) {
1524 DCHECK(ref);
1525 ref->texture()
1526 ->SetTarget(feature_info_.get(), target, MaxLevelsForTarget(target));
1529 void TextureManager::SetLevelClearedRect(TextureRef* ref,
1530 GLenum target,
1531 GLint level,
1532 const gfx::Rect& cleared_rect) {
1533 DCHECK(ref);
1534 ref->texture()->SetLevelClearedRect(target, level, cleared_rect);
1537 void TextureManager::SetLevelCleared(TextureRef* ref,
1538 GLenum target,
1539 GLint level,
1540 bool cleared) {
1541 DCHECK(ref);
1542 ref->texture()->SetLevelCleared(target, level, cleared);
1545 bool TextureManager::ClearRenderableLevels(
1546 GLES2Decoder* decoder, TextureRef* ref) {
1547 DCHECK(ref);
1548 return ref->texture()->ClearRenderableLevels(decoder);
1551 bool TextureManager::ClearTextureLevel(
1552 GLES2Decoder* decoder, TextureRef* ref,
1553 GLenum target, GLint level) {
1554 DCHECK(ref);
1555 Texture* texture = ref->texture();
1556 if (texture->num_uncleared_mips() == 0) {
1557 return true;
1559 bool result = texture->ClearLevel(decoder, target, level);
1560 texture->UpdateCleared();
1561 return result;
1564 void TextureManager::SetLevelInfo(TextureRef* ref,
1565 GLenum target,
1566 GLint level,
1567 GLenum internal_format,
1568 GLsizei width,
1569 GLsizei height,
1570 GLsizei depth,
1571 GLint border,
1572 GLenum format,
1573 GLenum type,
1574 const gfx::Rect& cleared_rect) {
1575 DCHECK(gfx::Rect(width, height).Contains(cleared_rect));
1576 DCHECK(ref);
1577 Texture* texture = ref->texture();
1579 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1580 texture->SetLevelInfo(feature_info_.get(), target, level, internal_format,
1581 width, height, depth, border, format, type,
1582 cleared_rect);
1583 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1586 Texture* TextureManager::Produce(TextureRef* ref) {
1587 DCHECK(ref);
1588 return ref->texture();
1591 TextureRef* TextureManager::Consume(
1592 GLuint client_id,
1593 Texture* texture) {
1594 DCHECK(client_id);
1595 scoped_refptr<TextureRef> ref(new TextureRef(this, client_id, texture));
1596 bool result = textures_.insert(std::make_pair(client_id, ref)).second;
1597 DCHECK(result);
1598 return ref.get();
1601 void TextureManager::SetParameteri(
1602 const char* function_name, ErrorState* error_state,
1603 TextureRef* ref, GLenum pname, GLint param) {
1604 DCHECK(error_state);
1605 DCHECK(ref);
1606 Texture* texture = ref->texture();
1607 GLenum result = texture->SetParameteri(feature_info_.get(), pname, param);
1608 if (result != GL_NO_ERROR) {
1609 if (result == GL_INVALID_ENUM) {
1610 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1611 error_state, function_name, param, "param");
1612 } else {
1613 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMI(
1614 error_state, result, function_name, pname, param);
1616 } else {
1617 // Texture tracking pools exist only for the command decoder, so
1618 // do not pass them on to the native GL implementation.
1619 if (pname != GL_TEXTURE_POOL_CHROMIUM) {
1620 glTexParameteri(texture->target(), pname, param);
1625 void TextureManager::SetParameterf(
1626 const char* function_name, ErrorState* error_state,
1627 TextureRef* ref, GLenum pname, GLfloat param) {
1628 DCHECK(error_state);
1629 DCHECK(ref);
1630 Texture* texture = ref->texture();
1631 GLenum result = texture->SetParameterf(feature_info_.get(), pname, param);
1632 if (result != GL_NO_ERROR) {
1633 if (result == GL_INVALID_ENUM) {
1634 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1635 error_state, function_name, pname, "pname");
1636 } else {
1637 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMF(
1638 error_state, result, function_name, pname, param);
1640 } else {
1641 // Texture tracking pools exist only for the command decoder, so
1642 // do not pass them on to the native GL implementation.
1643 if (pname != GL_TEXTURE_POOL_CHROMIUM) {
1644 glTexParameterf(texture->target(), pname, param);
1649 bool TextureManager::MarkMipmapsGenerated(TextureRef* ref) {
1650 DCHECK(ref);
1651 Texture* texture = ref->texture();
1652 texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
1653 bool result = texture->MarkMipmapsGenerated(feature_info_.get());
1654 texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
1655 return result;
1658 TextureRef* TextureManager::CreateTexture(
1659 GLuint client_id, GLuint service_id) {
1660 DCHECK_NE(0u, service_id);
1661 scoped_refptr<TextureRef> ref(TextureRef::Create(
1662 this, client_id, service_id));
1663 std::pair<TextureMap::iterator, bool> result =
1664 textures_.insert(std::make_pair(client_id, ref));
1665 DCHECK(result.second);
1666 return ref.get();
1669 TextureRef* TextureManager::GetTexture(
1670 GLuint client_id) const {
1671 TextureMap::const_iterator it = textures_.find(client_id);
1672 return it != textures_.end() ? it->second.get() : NULL;
1675 void TextureManager::RemoveTexture(GLuint client_id) {
1676 TextureMap::iterator it = textures_.find(client_id);
1677 if (it != textures_.end()) {
1678 it->second->reset_client_id();
1679 textures_.erase(it);
1683 void TextureManager::StartTracking(TextureRef* ref) {
1684 Texture* texture = ref->texture();
1685 ++texture_count_;
1686 num_uncleared_mips_ += texture->num_uncleared_mips();
1687 if (!texture->SafeToRenderFrom())
1688 ++num_unsafe_textures_;
1689 if (!texture->CanRender(feature_info_.get()))
1690 ++num_unrenderable_textures_;
1691 if (texture->HasImages())
1692 ++num_images_;
1695 void TextureManager::StopTracking(TextureRef* ref) {
1696 if (ref->num_observers()) {
1697 for (unsigned int i = 0; i < destruction_observers_.size(); i++) {
1698 destruction_observers_[i]->OnTextureRefDestroying(ref);
1700 DCHECK_EQ(ref->num_observers(), 0);
1703 Texture* texture = ref->texture();
1705 --texture_count_;
1706 if (texture->HasImages()) {
1707 DCHECK_NE(0, num_images_);
1708 --num_images_;
1710 if (!texture->CanRender(feature_info_.get())) {
1711 DCHECK_NE(0, num_unrenderable_textures_);
1712 --num_unrenderable_textures_;
1714 if (!texture->SafeToRenderFrom()) {
1715 DCHECK_NE(0, num_unsafe_textures_);
1716 --num_unsafe_textures_;
1718 num_uncleared_mips_ -= texture->num_uncleared_mips();
1719 DCHECK_GE(num_uncleared_mips_, 0);
1722 MemoryTypeTracker* TextureManager::GetMemTracker(GLenum tracking_pool) {
1723 switch (tracking_pool) {
1724 case GL_TEXTURE_POOL_MANAGED_CHROMIUM:
1725 return memory_tracker_managed_.get();
1726 break;
1727 case GL_TEXTURE_POOL_UNMANAGED_CHROMIUM:
1728 return memory_tracker_unmanaged_.get();
1729 break;
1730 default:
1731 break;
1733 NOTREACHED();
1734 return NULL;
1737 Texture* TextureManager::GetTextureForServiceId(GLuint service_id) const {
1738 // This doesn't need to be fast. It's only used during slow queries.
1739 for (TextureMap::const_iterator it = textures_.begin();
1740 it != textures_.end(); ++it) {
1741 Texture* texture = it->second->texture();
1742 if (texture->service_id() == service_id)
1743 return texture;
1745 return NULL;
1748 GLsizei TextureManager::ComputeMipMapCount(GLenum target,
1749 GLsizei width,
1750 GLsizei height,
1751 GLsizei depth) {
1752 switch (target) {
1753 case GL_TEXTURE_EXTERNAL_OES:
1754 return 1;
1755 default:
1756 return 1 +
1757 base::bits::Log2Floor(std::max(std::max(width, height), depth));
1761 void TextureManager::SetLevelImage(
1762 TextureRef* ref,
1763 GLenum target,
1764 GLint level,
1765 gfx::GLImage* image) {
1766 DCHECK(ref);
1767 ref->texture()->SetLevelImage(feature_info_.get(), target, level, image);
1770 size_t TextureManager::GetSignatureSize() const {
1771 return sizeof(TextureTag) + sizeof(TextureSignature);
1774 void TextureManager::AddToSignature(
1775 TextureRef* ref,
1776 GLenum target,
1777 GLint level,
1778 std::string* signature) const {
1779 ref->texture()->AddToSignature(feature_info_.get(), target, level, signature);
1782 void TextureManager::UpdateSafeToRenderFrom(int delta) {
1783 num_unsafe_textures_ += delta;
1784 DCHECK_GE(num_unsafe_textures_, 0);
1787 void TextureManager::UpdateUnclearedMips(int delta) {
1788 num_uncleared_mips_ += delta;
1789 DCHECK_GE(num_uncleared_mips_, 0);
1792 void TextureManager::UpdateCanRenderCondition(
1793 Texture::CanRenderCondition old_condition,
1794 Texture::CanRenderCondition new_condition) {
1795 if (old_condition == Texture::CAN_RENDER_NEVER ||
1796 (old_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1797 !feature_info_->feature_flags().npot_ok)) {
1798 DCHECK_GT(num_unrenderable_textures_, 0);
1799 --num_unrenderable_textures_;
1801 if (new_condition == Texture::CAN_RENDER_NEVER ||
1802 (new_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
1803 !feature_info_->feature_flags().npot_ok))
1804 ++num_unrenderable_textures_;
1807 void TextureManager::UpdateNumImages(int delta) {
1808 num_images_ += delta;
1809 DCHECK_GE(num_images_, 0);
1812 void TextureManager::IncFramebufferStateChangeCount() {
1813 if (framebuffer_manager_)
1814 framebuffer_manager_->IncFramebufferStateChangeCount();
1817 bool TextureManager::ValidateFormatAndTypeCombination(
1818 ErrorState* error_state, const char* function_name, GLenum format,
1819 GLenum type) {
1820 // TODO(zmo): now this is only called by GLES2DecoderImpl::DoCopyTexImage2D
1821 // and is incorrect for ES3. Fix this.
1822 if (!g_format_type_validator.Get().IsValid(format, format, type)) {
1823 ERRORSTATE_SET_GL_ERROR(
1824 error_state, GL_INVALID_OPERATION, function_name,
1825 (std::string("invalid type ") +
1826 GLES2Util::GetStringEnum(type) + " for format " +
1827 GLES2Util::GetStringEnum(format)).c_str());
1828 return false;
1830 return true;
1833 bool TextureManager::ValidateTextureParameters(
1834 ErrorState* error_state, const char* function_name,
1835 GLenum format, GLenum type, GLenum internal_format, GLint level) {
1836 const Validators* validators = feature_info_->validators();
1837 if (!validators->texture_format.IsValid(format)) {
1838 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1839 error_state, function_name, format, "format");
1840 return false;
1842 if (!validators->pixel_type.IsValid(type)) {
1843 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1844 error_state, function_name, type, "type");
1845 return false;
1847 if (!g_format_type_validator.Get().IsValid(internal_format, format, type)) {
1848 ERRORSTATE_SET_GL_ERROR(
1849 error_state, GL_INVALID_OPERATION, function_name,
1850 "invalid internalformat/format/type combination");
1851 return false;
1853 // For TexSubImage calls, internal_format isn't part of the parameters,
1854 // so its validation needs to be after the internal_format/format/type
1855 // combination validation. Otherwise, an unexpected INVALID_ENUM could be
1856 // generated instead of INVALID_OPERATION.
1857 if (!validators->texture_internal_format.IsValid(internal_format)) {
1858 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1859 error_state, function_name, internal_format, "internal_format");
1860 return false;
1862 if (!feature_info_->IsES3Enabled()) {
1863 uint32 channels = GLES2Util::GetChannelsForFormat(format);
1864 if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) {
1865 ERRORSTATE_SET_GL_ERROR(
1866 error_state, GL_INVALID_OPERATION, function_name,
1867 (std::string("invalid format ") + GLES2Util::GetStringEnum(format) +
1868 " for level != 0").c_str());
1869 return false;
1872 return true;
1875 // Gets the texture id for a given target.
1876 TextureRef* TextureManager::GetTextureInfoForTarget(
1877 ContextState* state, GLenum target) {
1878 TextureUnit& unit = state->texture_units[state->active_texture_unit];
1879 TextureRef* texture = NULL;
1880 switch (target) {
1881 case GL_TEXTURE_2D:
1882 texture = unit.bound_texture_2d.get();
1883 break;
1884 case GL_TEXTURE_CUBE_MAP:
1885 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1886 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1887 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1888 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1889 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1890 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1891 texture = unit.bound_texture_cube_map.get();
1892 break;
1893 case GL_TEXTURE_EXTERNAL_OES:
1894 texture = unit.bound_texture_external_oes.get();
1895 break;
1896 case GL_TEXTURE_RECTANGLE_ARB:
1897 texture = unit.bound_texture_rectangle_arb.get();
1898 break;
1899 case GL_TEXTURE_3D:
1900 texture = unit.bound_texture_3d.get();
1901 break;
1902 case GL_TEXTURE_2D_ARRAY:
1903 texture = unit.bound_texture_2d_array.get();
1904 break;
1905 default:
1906 NOTREACHED();
1907 return NULL;
1909 return texture;
1912 TextureRef* TextureManager::GetTextureInfoForTargetUnlessDefault(
1913 ContextState* state, GLenum target) {
1914 TextureRef* texture = GetTextureInfoForTarget(state, target);
1915 if (!texture)
1916 return NULL;
1917 if (texture == GetDefaultTextureInfo(target))
1918 return NULL;
1919 return texture;
1922 bool TextureManager::ValidateTexImage(
1923 ContextState* state,
1924 const char* function_name,
1925 const DoTexImageArguments& args,
1926 TextureRef** texture_ref) {
1927 ErrorState* error_state = state->GetErrorState();
1928 const Validators* validators = feature_info_->validators();
1929 if (((args.command_type == DoTexImageArguments::kTexImage2D) &&
1930 !validators->texture_target.IsValid(args.target)) ||
1931 ((args.command_type == DoTexImageArguments::kTexImage3D) &&
1932 !validators->texture_3_d_target.IsValid(args.target))) {
1933 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1934 error_state, function_name, args.target, "target");
1935 return false;
1937 if (!ValidateTextureParameters(
1938 error_state, function_name, args.format, args.type,
1939 args.internal_format, args.level)) {
1940 return false;
1942 if (!ValidForTarget(args.target, args.level,
1943 args.width, args.height, args.depth) ||
1944 args.border != 0) {
1945 ERRORSTATE_SET_GL_ERROR(
1946 error_state, GL_INVALID_VALUE, function_name,
1947 "dimensions out of range");
1948 return false;
1950 if ((GLES2Util::GetChannelsForFormat(args.format) &
1951 (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && args.pixels
1952 && !feature_info_->IsES3Enabled()) {
1953 ERRORSTATE_SET_GL_ERROR(
1954 error_state, GL_INVALID_OPERATION,
1955 function_name, "can not supply data for depth or stencil textures");
1956 return false;
1959 TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target);
1960 if (!local_texture_ref) {
1961 ERRORSTATE_SET_GL_ERROR(
1962 error_state, GL_INVALID_OPERATION, function_name,
1963 "unknown texture for target");
1964 return false;
1966 if (local_texture_ref->texture()->IsImmutable()) {
1967 ERRORSTATE_SET_GL_ERROR(
1968 error_state, GL_INVALID_OPERATION, function_name,
1969 "texture is immutable");
1970 return false;
1973 if (!memory_tracker_managed_->EnsureGPUMemoryAvailable(args.pixels_size)) {
1974 ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, function_name,
1975 "out of memory");
1976 return false;
1979 // Write the TextureReference since this is valid.
1980 *texture_ref = local_texture_ref;
1981 return true;
1984 void TextureManager::ValidateAndDoTexImage(
1985 DecoderTextureState* texture_state,
1986 ContextState* state,
1987 DecoderFramebufferState* framebuffer_state,
1988 const char* function_name,
1989 const DoTexImageArguments& args) {
1990 TextureRef* texture_ref;
1991 if (!ValidateTexImage(state, function_name, args, &texture_ref)) {
1992 return;
1995 // ValidateTexImage is passed already.
1996 Texture* texture = texture_ref->texture();
1997 bool need_cube_map_workaround =
1998 texture->target() == GL_TEXTURE_CUBE_MAP &&
1999 (texture_state->force_cube_complete ||
2000 (texture_state->force_cube_map_positive_x_allocation &&
2001 args.target != GL_TEXTURE_CUBE_MAP_POSITIVE_X));
2002 if (need_cube_map_workaround) {
2003 std::vector<GLenum> undefined_faces;
2004 if (texture_state->force_cube_complete) {
2005 int width = 0;
2006 int height = 0;
2007 for (unsigned i = 0; i < 6; i++) {
2008 bool defined =
2009 texture->GetLevelSize(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
2010 args.level, &width, &height, nullptr);
2011 if (!defined || GL_TEXTURE_CUBE_MAP_POSITIVE_X + i == args.target)
2012 undefined_faces.push_back(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i);
2014 } else if (texture_state->force_cube_map_positive_x_allocation &&
2015 args.target != GL_TEXTURE_CUBE_MAP_POSITIVE_X) {
2016 int width = 0;
2017 int height = 0;
2018 if (!texture->GetLevelSize(GL_TEXTURE_CUBE_MAP_POSITIVE_X, args.level,
2019 &width, &height, nullptr)) {
2020 undefined_faces.push_back(GL_TEXTURE_CUBE_MAP_POSITIVE_X);
2022 undefined_faces.push_back(args.target);
2025 DCHECK(undefined_faces.size());
2026 if (!memory_tracker_managed_->EnsureGPUMemoryAvailable(
2027 undefined_faces.size() * args.pixels_size)) {
2028 ERRORSTATE_SET_GL_ERROR(state->GetErrorState(), GL_OUT_OF_MEMORY,
2029 function_name, "out of memory");
2030 return;
2032 DoTexImageArguments new_args = args;
2033 scoped_ptr<char[]> zero(new char[args.pixels_size]);
2034 memset(zero.get(), 0, args.pixels_size);
2035 for (GLenum face : undefined_faces) {
2036 new_args.target = face;
2037 if (face == args.target) {
2038 new_args.pixels = args.pixels;
2039 } else {
2040 new_args.pixels = zero.get();
2042 DoTexImage(texture_state, state->GetErrorState(), framebuffer_state,
2043 function_name, texture_ref, new_args);
2045 return;
2048 DoTexImage(texture_state, state->GetErrorState(), framebuffer_state,
2049 function_name, texture_ref, args);
2052 GLenum TextureManager::AdjustTexFormat(GLenum format) const {
2053 // TODO(bajones): GLES 3 allows for internal format and format to differ.
2054 // This logic may need to change as a result.
2055 if (gfx::GetGLImplementation() == gfx::kGLImplementationDesktopGL) {
2056 if (format == GL_SRGB_EXT)
2057 return GL_RGB;
2058 if (format == GL_SRGB_ALPHA_EXT)
2059 return GL_RGBA;
2061 return format;
2064 void TextureManager::DoTexImage(
2065 DecoderTextureState* texture_state,
2066 ErrorState* error_state,
2067 DecoderFramebufferState* framebuffer_state,
2068 const char* function_name,
2069 TextureRef* texture_ref,
2070 const DoTexImageArguments& args) {
2071 Texture* texture = texture_ref->texture();
2072 GLsizei tex_width = 0;
2073 GLsizei tex_height = 0;
2074 GLsizei tex_depth = 0;
2075 GLenum tex_type = 0;
2076 GLenum tex_format = 0;
2077 bool level_is_same =
2078 texture->GetLevelSize(
2079 args.target, args.level, &tex_width, &tex_height, &tex_depth) &&
2080 texture->GetLevelType(args.target, args.level, &tex_type, &tex_format) &&
2081 args.width == tex_width && args.height == tex_height &&
2082 args.depth == tex_depth && args.type == tex_type &&
2083 args.format == tex_format;
2085 if (level_is_same && !args.pixels) {
2086 // Just set the level texture but mark the texture as uncleared.
2087 SetLevelInfo(texture_ref, args.target, args.level, args.internal_format,
2088 args.width, args.height, args.depth, args.border, args.format,
2089 args.type, gfx::Rect());
2090 texture_state->tex_image_failed = false;
2091 return;
2094 if (texture->IsAttachedToFramebuffer()) {
2095 framebuffer_state->clear_state_dirty = true;
2098 if (texture_state->texsubimage_faster_than_teximage &&
2099 level_is_same && args.pixels) {
2101 ScopedTextureUploadTimer timer(texture_state);
2102 if (args.command_type == DoTexImageArguments::kTexImage3D) {
2103 glTexSubImage3D(args.target, args.level, 0, 0, 0,
2104 args.width, args.height, args.depth,
2105 args.format, args.type, args.pixels);
2106 } else {
2107 glTexSubImage2D(args.target, args.level, 0, 0, args.width, args.height,
2108 AdjustTexFormat(args.format), args.type, args.pixels);
2111 SetLevelCleared(texture_ref, args.target, args.level, true);
2112 texture_state->tex_image_failed = false;
2113 return;
2116 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, function_name);
2118 ScopedTextureUploadTimer timer(texture_state);
2119 if (args.command_type == DoTexImageArguments::kTexImage3D) {
2120 glTexImage3D(args.target, args.level, args.internal_format, args.width,
2121 args.height, args.depth, args.border, args.format,
2122 args.type, args.pixels);
2123 } else {
2124 glTexImage2D(args.target, args.level, args.internal_format, args.width,
2125 args.height, args.border, AdjustTexFormat(args.format),
2126 args.type, args.pixels);
2129 GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, function_name);
2130 if (error == GL_NO_ERROR) {
2131 SetLevelInfo(
2132 texture_ref, args.target, args.level, args.internal_format, args.width,
2133 args.height, args.depth, args.border, args.format, args.type,
2134 args.pixels != NULL ? gfx::Rect(args.width, args.height) : gfx::Rect());
2135 texture_state->tex_image_failed = false;
2139 ScopedTextureUploadTimer::ScopedTextureUploadTimer(
2140 DecoderTextureState* texture_state)
2141 : texture_state_(texture_state),
2142 begin_time_(base::TimeTicks::Now()) {
2145 ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
2146 texture_state_->texture_upload_count++;
2147 texture_state_->total_texture_upload_time +=
2148 base::TimeTicks::Now() - begin_time_;
2151 bool TextureManager::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
2152 base::trace_event::ProcessMemoryDump* pmd) {
2153 for (const auto& resource : textures_) {
2154 // Only dump memory info for textures actually owned by this TextureManager.
2155 DumpTextureRef(pmd, resource.second.get());
2158 // Also dump TextureManager internal textures, if allocated.
2159 for (int i = 0; i < kNumDefaultTextures; i++) {
2160 if (default_textures_[i]) {
2161 DumpTextureRef(pmd, default_textures_[i].get());
2165 return true;
2168 void TextureManager::DumpTextureRef(base::trace_event::ProcessMemoryDump* pmd,
2169 TextureRef* ref) {
2170 uint32_t size = ref->texture()->estimated_size();
2172 // Ignore unallocated texture IDs.
2173 if (size == 0)
2174 return;
2176 std::string dump_name =
2177 base::StringPrintf("gpu/gl/textures/client_%d/texture_%d",
2178 memory_tracker_->ClientId(), ref->client_id());
2180 base::trace_event::MemoryAllocatorDump* dump =
2181 pmd->CreateAllocatorDump(dump_name);
2182 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
2183 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
2184 static_cast<uint64_t>(size));
2186 // Add the |client_guid| which expresses shared ownership with the client
2187 // process.
2188 auto client_guid = gfx::GetGLTextureClientGUIDForTracing(
2189 memory_tracker_->ShareGroupTracingGUID(), ref->client_id());
2190 pmd->CreateSharedGlobalAllocatorDump(client_guid);
2191 pmd->AddOwnershipEdge(dump->guid(), client_guid);
2193 // Add a |service_guid| which expresses shared ownership between the various
2194 // |client_guid|s.
2195 // TODO(ericrk): May need to ensure uniqueness using GLShareGroup and
2196 // potentially cross-share-group sharing via EGLImages. crbug.com/512534
2197 auto service_guid = gfx::GetGLTextureServiceGUIDForTracing(
2198 memory_tracker_->ShareGroupTracingGUID(), ref->texture()->service_id());
2199 pmd->CreateSharedGlobalAllocatorDump(service_guid);
2201 int importance = 0; // Default importance.
2202 // The link to the memory tracking |client_id| is given a higher importance
2203 // than other refs.
2204 if (ref == ref->texture()->memory_tracking_ref_)
2205 importance = 2;
2207 pmd->AddOwnershipEdge(client_guid, service_guid, importance);
2209 // Dump all sub-levels held by the texture. They will appear below the main
2210 // gl/textures/client_X/texture_Y dump.
2211 ref->texture()->DumpLevelMemory(pmd, memory_tracker_->ClientTracingId(),
2212 dump_name);
2215 } // namespace gles2
2216 } // namespace gpu