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"
11 #include "base/bits.h"
12 #include "base/lazy_instance.h"
13 #include "base/strings/stringprintf.h"
14 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
15 #include "gpu/command_buffer/service/context_state.h"
16 #include "gpu/command_buffer/service/error_state.h"
17 #include "gpu/command_buffer/service/feature_info.h"
18 #include "gpu/command_buffer/service/framebuffer_manager.h"
19 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
20 #include "gpu/command_buffer/service/mailbox_manager.h"
21 #include "gpu/command_buffer/service/memory_tracking.h"
22 #include "ui/gl/gl_implementation.h"
29 // This should contain everything to uniquely identify a Texture.
30 const char TextureTag
[] = "|Texture|";
31 struct TextureSignature
{
40 GLenum internal_format_
;
58 // Since we will be hashing this signature structure, the padding must be
59 // zero initialized. Although the C++11 specifications specify that this is
60 // true, we will use a constructor with a memset to further enforce it instead
61 // of relying on compilers adhering to this deep dark corner specification.
62 TextureSignature(GLenum target
,
70 GLenum internal_format
,
87 memset(this, 0, sizeof(TextureSignature
));
90 min_filter_
= min_filter
;
91 mag_filter_
= mag_filter
;
96 internal_format_
= internal_format
;
97 compare_func_
= compare_func
;
98 compare_mode_
= compare_mode
;
104 base_level_
= base_level
;
106 max_level_
= max_level
;
109 has_image_
= has_image
;
110 can_render_
= can_render
;
111 can_render_to_
= can_render_to
;
116 class FormatTypeValidator
{
118 FormatTypeValidator() {
119 static const FormatType kSupportedFormatTypes
[] = {
121 { GL_RGB
, GL_RGB
, GL_UNSIGNED_BYTE
},
122 { GL_RGB
, GL_RGB
, GL_UNSIGNED_SHORT_5_6_5
},
123 { GL_RGBA
, GL_RGBA
, GL_UNSIGNED_BYTE
},
124 { GL_RGBA
, GL_RGBA
, GL_UNSIGNED_SHORT_4_4_4_4
},
125 { GL_RGBA
, GL_RGBA
, GL_UNSIGNED_SHORT_5_5_5_1
},
126 { GL_LUMINANCE_ALPHA
, GL_LUMINANCE_ALPHA
, GL_UNSIGNED_BYTE
},
127 { GL_LUMINANCE
, GL_LUMINANCE
, GL_UNSIGNED_BYTE
},
128 { GL_ALPHA
, GL_ALPHA
, GL_UNSIGNED_BYTE
},
129 // Exposed by GL_OES_texture_float and GL_OES_texture_half_float
130 { GL_RGB
, GL_RGB
, GL_FLOAT
},
131 { GL_RGBA
, GL_RGBA
, GL_FLOAT
},
132 { GL_LUMINANCE_ALPHA
, GL_LUMINANCE_ALPHA
, GL_FLOAT
},
133 { GL_LUMINANCE
, GL_LUMINANCE
, GL_FLOAT
},
134 { GL_ALPHA
, GL_ALPHA
, GL_FLOAT
},
135 { GL_RGB
, GL_RGB
, GL_HALF_FLOAT_OES
},
136 { GL_RGBA
, GL_RGBA
, GL_HALF_FLOAT_OES
},
137 { GL_LUMINANCE_ALPHA
, GL_LUMINANCE_ALPHA
, GL_HALF_FLOAT_OES
},
138 { GL_LUMINANCE
, GL_LUMINANCE
, GL_HALF_FLOAT_OES
},
139 { GL_ALPHA
, GL_ALPHA
, GL_HALF_FLOAT_OES
},
140 // Exposed by GL_ANGLE_depth_texture
141 { GL_DEPTH_COMPONENT
, GL_DEPTH_COMPONENT
, GL_UNSIGNED_SHORT
},
142 { GL_DEPTH_COMPONENT
, GL_DEPTH_COMPONENT
, GL_UNSIGNED_INT
},
143 { GL_DEPTH_STENCIL
, GL_DEPTH_STENCIL
, GL_UNSIGNED_INT_24_8
},
144 // Exposed by GL_EXT_sRGB
145 { GL_SRGB
, GL_SRGB
, GL_UNSIGNED_BYTE
},
146 { GL_SRGB_ALPHA
, GL_SRGB_ALPHA
, GL_UNSIGNED_BYTE
},
147 // Exposed by GL_EXT_texture_format_BGRA8888
148 { GL_BGRA_EXT
, GL_BGRA_EXT
, GL_UNSIGNED_BYTE
},
149 // Exposed by GL_EXT_texture_rg
150 { GL_RED
, GL_RED
, GL_UNSIGNED_BYTE
},
151 { GL_RG
, GL_RG
, GL_UNSIGNED_BYTE
},
152 { GL_RED
, GL_RED
, GL_FLOAT
},
153 { GL_RG
, GL_RG
, GL_FLOAT
},
154 { GL_RED
, GL_RED
, GL_HALF_FLOAT_OES
},
155 { GL_RG
, GL_RG
, GL_HALF_FLOAT_OES
},
158 { GL_R8
, GL_RED
, GL_UNSIGNED_BYTE
},
159 { GL_R8_SNORM
, GL_RED
, GL_BYTE
},
160 { GL_R16F
, GL_RED
, GL_HALF_FLOAT
},
161 { GL_R16F
, GL_RED
, GL_FLOAT
},
162 { GL_R32F
, GL_RED
, GL_FLOAT
},
163 { GL_R8UI
, GL_RED_INTEGER
, GL_UNSIGNED_BYTE
},
164 { GL_R8I
, GL_RED_INTEGER
, GL_BYTE
},
165 { GL_R16UI
, GL_RED_INTEGER
, GL_UNSIGNED_SHORT
},
166 { GL_R16I
, GL_RED_INTEGER
, GL_SHORT
},
167 { GL_R32UI
, GL_RED_INTEGER
, GL_UNSIGNED_INT
},
168 { GL_R32I
, GL_RED_INTEGER
, GL_INT
},
169 { GL_RG8
, GL_RG
, GL_UNSIGNED_BYTE
},
170 { GL_RG8_SNORM
, GL_RG
, GL_BYTE
},
171 { GL_RG16F
, GL_RG
, GL_HALF_FLOAT
},
172 { GL_RG16F
, GL_RG
, GL_FLOAT
},
173 { GL_RG32F
, GL_RG
, GL_FLOAT
},
174 { GL_RG8UI
, GL_RG_INTEGER
, GL_UNSIGNED_BYTE
},
175 { GL_RG8I
, GL_RG_INTEGER
, GL_BYTE
},
176 { GL_RG16UI
, GL_RG_INTEGER
, GL_UNSIGNED_SHORT
},
177 { GL_RG16I
, GL_RG_INTEGER
, GL_SHORT
},
178 { GL_RG32UI
, GL_RG_INTEGER
, GL_UNSIGNED_INT
},
179 { GL_RG32I
, GL_RG_INTEGER
, GL_INT
},
180 { GL_RGB8
, GL_RGB
, GL_UNSIGNED_BYTE
},
181 { GL_SRGB8
, GL_RGB
, GL_UNSIGNED_BYTE
},
182 { GL_RGB565
, GL_RGB
, GL_UNSIGNED_BYTE
, },
183 { GL_RGB565
, GL_RGB
, GL_UNSIGNED_SHORT_5_6_5
},
184 { GL_RGB8_SNORM
, GL_RGB
, GL_BYTE
},
185 { GL_R11F_G11F_B10F
, GL_RGB
, GL_UNSIGNED_INT_10F_11F_11F_REV
},
186 { GL_R11F_G11F_B10F
, GL_RGB
, GL_HALF_FLOAT
},
187 { GL_R11F_G11F_B10F
, GL_RGB
, GL_FLOAT
},
188 { GL_RGB9_E5
, GL_RGB
, GL_UNSIGNED_INT_5_9_9_9_REV
},
189 { GL_RGB9_E5
, GL_RGB
, GL_HALF_FLOAT
},
190 { GL_RGB9_E5
, GL_RGB
, GL_FLOAT
},
191 { GL_RGB16F
, GL_RGB
, GL_HALF_FLOAT
},
192 { GL_RGB16F
, GL_RGB
, GL_FLOAT
},
193 { GL_RGB32F
, GL_RGB
, GL_FLOAT
},
194 { GL_RGB8UI
, GL_RGB_INTEGER
, GL_UNSIGNED_BYTE
},
195 { GL_RGB8I
, GL_RGB_INTEGER
, GL_BYTE
},
196 { GL_RGB16UI
, GL_RGB_INTEGER
, GL_UNSIGNED_SHORT
},
197 { GL_RGB16I
, GL_RGB_INTEGER
, GL_SHORT
},
198 { GL_RGB32UI
, GL_RGB_INTEGER
, GL_UNSIGNED_INT
},
199 { GL_RGB32I
, GL_RGB_INTEGER
, GL_INT
},
200 { GL_RGBA8
, GL_RGBA
, GL_UNSIGNED_BYTE
},
201 { GL_SRGB8_ALPHA8
, GL_RGBA
, GL_UNSIGNED_BYTE
},
202 { GL_RGBA8_SNORM
, GL_RGBA
, GL_BYTE
},
203 { GL_RGB5_A1
, GL_RGBA
, GL_UNSIGNED_BYTE
},
204 { GL_RGB5_A1
, GL_RGBA
, GL_UNSIGNED_SHORT_5_5_5_1
},
205 { GL_RGB5_A1
, GL_RGBA
, GL_UNSIGNED_INT_2_10_10_10_REV
},
206 { GL_RGBA4
, GL_RGBA
, GL_UNSIGNED_BYTE
},
207 { GL_RGBA4
, GL_RGBA
, GL_UNSIGNED_SHORT_4_4_4_4
},
208 { GL_RGB10_A2
, GL_RGBA
, GL_UNSIGNED_INT_2_10_10_10_REV
},
209 { GL_RGBA16F
, GL_RGBA
, GL_HALF_FLOAT
},
210 { GL_RGBA16F
, GL_RGBA
, GL_FLOAT
},
211 { GL_RGBA32F
, GL_RGBA
, GL_FLOAT
},
212 { GL_RGBA8UI
, GL_RGBA_INTEGER
, GL_UNSIGNED_BYTE
},
213 { GL_RGBA8I
, GL_RGBA_INTEGER
, GL_BYTE
},
214 { GL_RGB10_A2UI
, GL_RGBA_INTEGER
, GL_UNSIGNED_INT_2_10_10_10_REV
},
215 { GL_RGBA16UI
, GL_RGBA_INTEGER
, GL_UNSIGNED_SHORT
},
216 { GL_RGBA16I
, GL_RGBA_INTEGER
, GL_SHORT
},
217 { GL_RGBA32I
, GL_RGBA_INTEGER
, GL_INT
},
218 { GL_RGBA32UI
, GL_RGBA_INTEGER
, GL_UNSIGNED_INT
},
219 { GL_DEPTH_COMPONENT16
, GL_DEPTH_COMPONENT
, GL_UNSIGNED_SHORT
},
220 { GL_DEPTH_COMPONENT16
, GL_DEPTH_COMPONENT
, GL_UNSIGNED_INT
},
221 { GL_DEPTH_COMPONENT24
, GL_DEPTH_COMPONENT
, GL_UNSIGNED_INT
},
222 { GL_DEPTH_COMPONENT32F
, GL_DEPTH_COMPONENT
, GL_FLOAT
},
223 { GL_DEPTH24_STENCIL8
, GL_DEPTH_STENCIL
, GL_UNSIGNED_INT_24_8
},
224 { GL_DEPTH32F_STENCIL8
, GL_DEPTH_STENCIL
,
225 GL_FLOAT_32_UNSIGNED_INT_24_8_REV
},
228 for (size_t ii
= 0; ii
< arraysize(kSupportedFormatTypes
); ++ii
) {
229 supported_combinations_
.insert(kSupportedFormatTypes
[ii
]);
233 // This may be accessed from multiple threads.
234 bool IsValid(GLenum internal_format
, GLenum format
, GLenum type
) const {
235 FormatType query
= { internal_format
, format
, type
};
236 return supported_combinations_
.find(query
) != supported_combinations_
.end();
240 // TODO(zmo): once std::tuple is allowed, switch over to that.
242 GLenum internal_format
;
247 struct FormatTypeCompare
{
248 bool operator() (const FormatType
& lhs
, const FormatType
& rhs
) const {
249 return (lhs
.internal_format
< rhs
.internal_format
||
250 ((lhs
.internal_format
== rhs
.internal_format
) &&
251 (lhs
.format
< rhs
.format
)) ||
252 ((lhs
.internal_format
== rhs
.internal_format
) &&
253 (lhs
.format
== rhs
.format
) &&
254 (lhs
.type
< rhs
.type
)));
258 // This class needs to be thread safe, so once supported_combinations_
259 // are initialized in the constructor, it should never be modified later.
260 std::set
<FormatType
, FormatTypeCompare
> supported_combinations_
;
263 base::LazyInstance
<const FormatTypeValidator
>::Leaky g_format_type_validator
=
264 LAZY_INSTANCE_INITIALIZER
;
266 } // namespace anonymous
268 TextureManager::DestructionObserver::DestructionObserver() {}
270 TextureManager::DestructionObserver::~DestructionObserver() {}
272 TextureManager::~TextureManager() {
273 for (unsigned int i
= 0; i
< destruction_observers_
.size(); i
++)
274 destruction_observers_
[i
]->OnTextureManagerDestroying(this);
276 DCHECK(textures_
.empty());
278 // If this triggers, that means something is keeping a reference to
279 // a Texture belonging to this.
280 CHECK_EQ(texture_count_
, 0u);
282 DCHECK_EQ(0, num_unrenderable_textures_
);
283 DCHECK_EQ(0, num_unsafe_textures_
);
284 DCHECK_EQ(0, num_uncleared_mips_
);
285 DCHECK_EQ(0, num_images_
);
288 void TextureManager::Destroy(bool have_context
) {
289 have_context_
= have_context
;
291 for (int ii
= 0; ii
< kNumDefaultTextures
; ++ii
) {
292 default_textures_
[ii
] = NULL
;
296 glDeleteTextures(arraysize(black_texture_ids_
), black_texture_ids_
);
299 DCHECK_EQ(0u, memory_tracker_managed_
->GetMemRepresented());
300 DCHECK_EQ(0u, memory_tracker_unmanaged_
->GetMemRepresented());
303 Texture::Texture(GLuint service_id
)
304 : mailbox_manager_(NULL
),
305 memory_tracking_ref_(NULL
),
306 service_id_(service_id
),
308 num_uncleared_mips_(0),
311 min_filter_(GL_NEAREST_MIPMAP_LINEAR
),
312 mag_filter_(GL_LINEAR
),
317 pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM
),
318 compare_func_(GL_LEQUAL
),
319 compare_mode_(GL_NONE
),
325 texture_complete_(false),
326 texture_mips_dirty_(false),
327 texture_mips_complete_(false),
328 cube_complete_(false),
329 texture_level0_dirty_(false),
330 texture_level0_complete_(false),
332 has_been_bound_(false),
333 framebuffer_attachment_count_(0),
337 can_render_condition_(CAN_RENDER_ALWAYS
),
338 texture_max_anisotropy_initialized_(false) {
341 Texture::~Texture() {
342 if (mailbox_manager_
)
343 mailbox_manager_
->TextureDeleted(this);
346 void Texture::AddTextureRef(TextureRef
* ref
) {
347 DCHECK(refs_
.find(ref
) == refs_
.end());
349 if (!memory_tracking_ref_
) {
350 memory_tracking_ref_
= ref
;
351 GetMemTracker()->TrackMemAlloc(estimated_size());
355 void Texture::RemoveTextureRef(TextureRef
* ref
, bool have_context
) {
356 if (memory_tracking_ref_
== ref
) {
357 GetMemTracker()->TrackMemFree(estimated_size());
358 memory_tracking_ref_
= NULL
;
360 size_t result
= refs_
.erase(ref
);
361 DCHECK_EQ(result
, 1u);
364 GLuint id
= service_id();
365 glDeleteTextures(1, &id
);
368 } else if (memory_tracking_ref_
== NULL
) {
369 // TODO(piman): tune ownership semantics for cross-context group shared
371 memory_tracking_ref_
= *refs_
.begin();
372 GetMemTracker()->TrackMemAlloc(estimated_size());
376 MemoryTypeTracker
* Texture::GetMemTracker() {
377 DCHECK(memory_tracking_ref_
);
378 return memory_tracking_ref_
->manager()->GetMemTracker(pool_
);
381 Texture::LevelInfo::LevelInfo()
394 Texture::LevelInfo::LevelInfo(const LevelInfo
& rhs
)
395 : cleared_rect(rhs
.cleared_rect
),
398 internal_format(rhs
.internal_format
),
406 estimated_size(rhs
.estimated_size
) {
409 Texture::LevelInfo::~LevelInfo() {
412 Texture::FaceInfo::FaceInfo()
413 : num_mip_levels(0) {
416 Texture::FaceInfo::~FaceInfo() {
419 Texture::CanRenderCondition
Texture::GetCanRenderCondition() const {
421 return CAN_RENDER_ALWAYS
;
423 if (target_
!= GL_TEXTURE_EXTERNAL_OES
) {
424 if (face_infos_
.empty()) {
425 return CAN_RENDER_NEVER
;
428 const Texture::LevelInfo
& first_face
= face_infos_
[0].level_infos
[0];
429 if (first_face
.width
== 0 ||
430 first_face
.height
== 0 ||
431 first_face
.depth
== 0) {
432 return CAN_RENDER_NEVER
;
436 bool needs_mips
= NeedsMips();
438 if (!texture_complete())
439 return CAN_RENDER_NEVER
;
440 if (target_
== GL_TEXTURE_CUBE_MAP
&& !cube_complete())
441 return CAN_RENDER_NEVER
;
444 bool is_npot_compatible
= !needs_mips
&&
445 wrap_s_
== GL_CLAMP_TO_EDGE
&&
446 wrap_t_
== GL_CLAMP_TO_EDGE
;
448 if (!is_npot_compatible
) {
449 if (target_
== GL_TEXTURE_RECTANGLE_ARB
)
450 return CAN_RENDER_NEVER
;
452 return CAN_RENDER_ONLY_IF_NPOT
;
455 return CAN_RENDER_ALWAYS
;
458 bool Texture::CanRender(const FeatureInfo
* feature_info
) const {
459 switch (can_render_condition_
) {
460 case CAN_RENDER_ALWAYS
:
462 case CAN_RENDER_NEVER
:
464 case CAN_RENDER_ONLY_IF_NPOT
:
467 return feature_info
->feature_flags().npot_ok
;
470 void Texture::AddToSignature(
471 const FeatureInfo
* feature_info
,
474 std::string
* signature
) const {
475 DCHECK(feature_info
);
478 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
479 DCHECK_LT(static_cast<size_t>(face_index
),
481 DCHECK_LT(static_cast<size_t>(level
),
482 face_infos_
[face_index
].level_infos
.size());
484 const Texture::LevelInfo
& info
=
485 face_infos_
[face_index
].level_infos
[level
];
487 TextureSignature
signature_data(target
,
495 info
.internal_format
,
508 info
.image
.get() != NULL
,
509 CanRender(feature_info
),
513 signature
->append(TextureTag
, sizeof(TextureTag
));
514 signature
->append(reinterpret_cast<const char*>(&signature_data
),
515 sizeof(signature_data
));
518 void Texture::SetMailboxManager(MailboxManager
* mailbox_manager
) {
519 DCHECK(!mailbox_manager_
|| mailbox_manager_
== mailbox_manager
);
520 mailbox_manager_
= mailbox_manager
;
523 bool Texture::MarkMipmapsGenerated(
524 const FeatureInfo
* feature_info
) {
525 if (!CanGenerateMipmaps(feature_info
)) {
528 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
529 const Texture::FaceInfo
& face_info
= face_infos_
[ii
];
530 const Texture::LevelInfo
& level0_info
= face_info
.level_infos
[0];
531 GLsizei width
= level0_info
.width
;
532 GLsizei height
= level0_info
.height
;
533 GLsizei depth
= level0_info
.depth
;
534 GLenum target
= target_
== GL_TEXTURE_2D
? GL_TEXTURE_2D
:
535 GLES2Util::IndexToGLFaceTarget(ii
);
537 const GLsizei num_mips
= face_info
.num_mip_levels
;
538 for (GLsizei level
= 1; level
< num_mips
; ++level
) {
539 width
= std::max(1, width
>> 1);
540 height
= std::max(1, height
>> 1);
541 depth
= std::max(1, depth
>> 1);
542 SetLevelInfo(feature_info
, target
, level
, level0_info
.internal_format
,
543 width
, height
, depth
, level0_info
.border
, level0_info
.format
,
544 level0_info
.type
, gfx::Rect(width
, height
));
551 void Texture::SetTarget(
552 const FeatureInfo
* feature_info
, GLenum target
, GLint max_levels
) {
553 DCHECK_EQ(0u, target_
); // you can only set this once.
555 size_t num_faces
= (target
== GL_TEXTURE_CUBE_MAP
) ? 6 : 1;
556 face_infos_
.resize(num_faces
);
557 for (size_t ii
= 0; ii
< num_faces
; ++ii
) {
558 face_infos_
[ii
].level_infos
.resize(max_levels
);
561 if (target
== GL_TEXTURE_EXTERNAL_OES
|| target
== GL_TEXTURE_RECTANGLE_ARB
) {
562 min_filter_
= GL_LINEAR
;
563 wrap_s_
= wrap_t_
= GL_CLAMP_TO_EDGE
;
566 if (target
== GL_TEXTURE_EXTERNAL_OES
) {
569 Update(feature_info
);
570 UpdateCanRenderCondition();
573 bool Texture::CanGenerateMipmaps(
574 const FeatureInfo
* feature_info
) const {
575 if ((npot() && !feature_info
->feature_flags().npot_ok
) ||
576 face_infos_
.empty() ||
577 target_
== GL_TEXTURE_EXTERNAL_OES
||
578 target_
== GL_TEXTURE_RECTANGLE_ARB
) {
582 // Can't generate mips for depth or stencil textures.
583 const Texture::LevelInfo
& first
= face_infos_
[0].level_infos
[0];
584 uint32 channels
= GLES2Util::GetChannelsForFormat(first
.format
);
585 if (channels
& (GLES2Util::kDepth
| GLES2Util::kStencil
)) {
589 // TODO(gman): Check internal_format, format and type.
590 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
591 const LevelInfo
& info
= face_infos_
[ii
].level_infos
[0];
592 if ((info
.target
== 0) || (info
.width
!= first
.width
) ||
593 (info
.height
!= first
.height
) || (info
.depth
!= 1) ||
594 (info
.format
!= first
.format
) ||
595 (info
.internal_format
!= first
.internal_format
) ||
596 (info
.type
!= first
.type
) ||
597 feature_info
->validators()->compressed_texture_format
.IsValid(
598 info
.internal_format
) ||
606 bool Texture::TextureIsNPOT(GLsizei width
,
609 return (GLES2Util::IsNPOT(width
) ||
610 GLES2Util::IsNPOT(height
) ||
611 GLES2Util::IsNPOT(depth
));
614 bool Texture::TextureFaceComplete(const Texture::LevelInfo
& first_face
,
617 GLenum internal_format
,
623 bool complete
= (target
!= 0 && depth
== 1);
624 if (face_index
!= 0) {
625 complete
&= (width
== first_face
.width
&&
626 height
== first_face
.height
&&
627 internal_format
== first_face
.internal_format
&&
628 format
== first_face
.format
&&
629 type
== first_face
.type
);
634 bool Texture::TextureMipComplete(const Texture::LevelInfo
& level0_face
,
637 GLenum internal_format
,
643 bool complete
= (target
!= 0);
645 const GLsizei mip_width
= std::max(1, level0_face
.width
>> level
);
646 const GLsizei mip_height
= std::max(1, level0_face
.height
>> level
);
647 const GLsizei mip_depth
= std::max(1, level0_face
.depth
>> level
);
649 complete
&= (width
== mip_width
&&
650 height
== mip_height
&&
651 depth
== mip_depth
&&
652 internal_format
== level0_face
.internal_format
&&
653 format
== level0_face
.format
&&
654 type
== level0_face
.type
);
659 void Texture::SetLevelClearedRect(GLenum target
,
661 const gfx::Rect
& cleared_rect
) {
663 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
664 DCHECK_LT(static_cast<size_t>(face_index
),
666 DCHECK_LT(static_cast<size_t>(level
),
667 face_infos_
[face_index
].level_infos
.size());
668 Texture::LevelInfo
& info
=
669 face_infos_
[face_index
].level_infos
[level
];
670 UpdateMipCleared(&info
, info
.width
, info
.height
, cleared_rect
);
674 void Texture::SetLevelCleared(GLenum target
, GLint level
, bool cleared
) {
676 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
677 DCHECK_LT(static_cast<size_t>(face_index
), face_infos_
.size());
678 DCHECK_LT(static_cast<size_t>(level
),
679 face_infos_
[face_index
].level_infos
.size());
680 Texture::LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
681 UpdateMipCleared(&info
, info
.width
, info
.height
,
682 cleared
? gfx::Rect(info
.width
, info
.height
) : gfx::Rect());
686 void Texture::UpdateCleared() {
687 if (face_infos_
.empty()) {
691 const bool cleared
= (num_uncleared_mips_
== 0);
693 // If texture is uncleared and is attached to a framebuffer,
694 // that framebuffer must be marked possibly incomplete.
695 if (!cleared
&& IsAttachedToFramebuffer()) {
696 IncAllFramebufferStateChangeCount();
699 UpdateSafeToRenderFrom(cleared
);
702 void Texture::UpdateSafeToRenderFrom(bool cleared
) {
703 if (cleared_
== cleared
)
706 int delta
= cleared
? -1 : +1;
707 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
708 (*it
)->manager()->UpdateSafeToRenderFrom(delta
);
711 void Texture::UpdateMipCleared(LevelInfo
* info
,
714 const gfx::Rect
& cleared_rect
) {
715 bool was_cleared
= info
->cleared_rect
== gfx::Rect(info
->width
, info
->height
);
717 info
->height
= height
;
718 info
->cleared_rect
= cleared_rect
;
719 bool cleared
= info
->cleared_rect
== gfx::Rect(info
->width
, info
->height
);
720 if (cleared
== was_cleared
)
722 int delta
= cleared
? -1 : +1;
723 num_uncleared_mips_
+= delta
;
724 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
725 (*it
)->manager()->UpdateUnclearedMips(delta
);
728 void Texture::UpdateCanRenderCondition() {
729 CanRenderCondition can_render_condition
= GetCanRenderCondition();
730 if (can_render_condition_
== can_render_condition
)
732 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
733 (*it
)->manager()->UpdateCanRenderCondition(can_render_condition_
,
734 can_render_condition
);
735 can_render_condition_
= can_render_condition
;
738 void Texture::UpdateHasImages() {
739 if (face_infos_
.empty())
742 bool has_images
= false;
743 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
744 for (size_t jj
= 0; jj
< face_infos_
[ii
].level_infos
.size(); ++jj
) {
745 const Texture::LevelInfo
& info
= face_infos_
[ii
].level_infos
[jj
];
746 if (info
.image
.get() != NULL
) {
753 if (has_images_
== has_images
)
755 has_images_
= has_images
;
756 int delta
= has_images
? +1 : -1;
757 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
758 (*it
)->manager()->UpdateNumImages(delta
);
761 void Texture::IncAllFramebufferStateChangeCount() {
762 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
763 (*it
)->manager()->IncFramebufferStateChangeCount();
766 void Texture::SetLevelInfo(const FeatureInfo
* feature_info
,
769 GLenum internal_format
,
776 const gfx::Rect
& cleared_rect
) {
778 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
779 DCHECK_LT(static_cast<size_t>(face_index
),
781 DCHECK_LT(static_cast<size_t>(level
),
782 face_infos_
[face_index
].level_infos
.size());
784 DCHECK_GE(height
, 0);
786 Texture::LevelInfo
& info
=
787 face_infos_
[face_index
].level_infos
[level
];
789 // Update counters only if any attributes have changed. Counters are
790 // comparisons between the old and new values so it must be done before any
791 // assignment has been done to the LevelInfo.
792 if (info
.target
!= target
||
793 info
.internal_format
!= internal_format
||
794 info
.width
!= width
||
795 info
.height
!= height
||
796 info
.depth
!= depth
||
797 info
.format
!= format
||
800 // Calculate the mip level count.
801 face_infos_
[face_index
].num_mip_levels
=
802 TextureManager::ComputeMipMapCount(target_
, width
, height
, depth
);
804 // Update NPOT face count for the first level.
805 bool prev_npot
= TextureIsNPOT(info
.width
, info
.height
, info
.depth
);
806 bool now_npot
= TextureIsNPOT(width
, height
, depth
);
807 if (prev_npot
!= now_npot
)
808 num_npot_faces_
+= now_npot
? 1 : -1;
810 // Signify that level 0 has been changed, so they need to be reverified.
811 texture_level0_dirty_
= true;
814 // Signify that at least one of the mips has changed.
815 texture_mips_dirty_
= true;
818 info
.target
= target
;
820 info
.internal_format
= internal_format
;
822 info
.border
= border
;
823 info
.format
= format
;
827 UpdateMipCleared(&info
, width
, height
, cleared_rect
);
829 estimated_size_
-= info
.estimated_size
;
830 GLES2Util::ComputeImageDataSizes(
831 width
, height
, 1, format
, type
, 4, &info
.estimated_size
, NULL
, NULL
);
832 estimated_size_
+= info
.estimated_size
;
834 max_level_set_
= std::max(max_level_set_
, level
);
835 Update(feature_info
);
837 UpdateCanRenderCondition();
839 if (IsAttachedToFramebuffer()) {
840 // TODO(gman): If textures tracked which framebuffers they were attached to
841 // we could just mark those framebuffers as not complete.
842 IncAllFramebufferStateChangeCount();
846 bool Texture::ValidForTexture(
856 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
857 if (level
>= 0 && face_index
< face_infos_
.size() &&
858 static_cast<size_t>(level
) < face_infos_
[face_index
].level_infos
.size()) {
859 const LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
863 return SafeAddInt32(xoffset
, width
, &max_x
) &&
864 SafeAddInt32(yoffset
, height
, &max_y
) &&
865 SafeAddInt32(zoffset
, depth
, &max_z
) &&
869 max_x
<= info
.width
&&
870 max_y
<= info
.height
&&
871 max_z
<= info
.depth
&&
877 bool Texture::GetLevelSize(
878 GLint target
, GLint level
,
879 GLsizei
* width
, GLsizei
* height
, GLsizei
* depth
) const {
882 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
883 if (level
>= 0 && face_index
< face_infos_
.size() &&
884 static_cast<size_t>(level
) < face_infos_
[face_index
].level_infos
.size()) {
885 const LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
886 if (info
.target
!= 0) {
888 *height
= info
.height
;
897 bool Texture::GetLevelType(
898 GLint target
, GLint level
, GLenum
* type
, GLenum
* internal_format
) const {
900 DCHECK(internal_format
);
901 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
902 if (level
>= 0 && face_index
< face_infos_
.size() &&
903 static_cast<size_t>(level
) < face_infos_
[face_index
].level_infos
.size()) {
904 const LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
905 if (info
.target
!= 0) {
907 *internal_format
= info
.internal_format
;
914 GLenum
Texture::SetParameteri(
915 const FeatureInfo
* feature_info
, GLenum pname
, GLint param
) {
916 DCHECK(feature_info
);
918 if (target_
== GL_TEXTURE_EXTERNAL_OES
||
919 target_
== GL_TEXTURE_RECTANGLE_ARB
) {
920 if (pname
== GL_TEXTURE_MIN_FILTER
&&
921 (param
!= GL_NEAREST
&& param
!= GL_LINEAR
))
922 return GL_INVALID_ENUM
;
923 if ((pname
== GL_TEXTURE_WRAP_S
|| pname
== GL_TEXTURE_WRAP_T
) &&
924 param
!= GL_CLAMP_TO_EDGE
)
925 return GL_INVALID_ENUM
;
929 case GL_TEXTURE_MIN_LOD
:
930 case GL_TEXTURE_MAX_LOD
:
932 GLfloat fparam
= static_cast<GLfloat
>(param
);
933 return SetParameterf(feature_info
, pname
, fparam
);
935 case GL_TEXTURE_MIN_FILTER
:
936 if (!feature_info
->validators()->texture_min_filter_mode
.IsValid(param
)) {
937 return GL_INVALID_ENUM
;
941 case GL_TEXTURE_MAG_FILTER
:
942 if (!feature_info
->validators()->texture_mag_filter_mode
.IsValid(param
)) {
943 return GL_INVALID_ENUM
;
947 case GL_TEXTURE_POOL_CHROMIUM
:
948 if (!feature_info
->validators()->texture_pool
.IsValid(param
)) {
949 return GL_INVALID_ENUM
;
951 GetMemTracker()->TrackMemFree(estimated_size());
953 GetMemTracker()->TrackMemAlloc(estimated_size());
955 case GL_TEXTURE_WRAP_R
:
956 if (!feature_info
->validators()->texture_wrap_mode
.IsValid(param
)) {
957 return GL_INVALID_ENUM
;
961 case GL_TEXTURE_WRAP_S
:
962 if (!feature_info
->validators()->texture_wrap_mode
.IsValid(param
)) {
963 return GL_INVALID_ENUM
;
967 case GL_TEXTURE_WRAP_T
:
968 if (!feature_info
->validators()->texture_wrap_mode
.IsValid(param
)) {
969 return GL_INVALID_ENUM
;
973 case GL_TEXTURE_COMPARE_FUNC
:
974 if (!feature_info
->validators()->texture_compare_func
.IsValid(param
)) {
975 return GL_INVALID_ENUM
;
977 compare_func_
= param
;
979 case GL_TEXTURE_COMPARE_MODE
:
980 if (!feature_info
->validators()->texture_compare_mode
.IsValid(param
)) {
981 return GL_INVALID_ENUM
;
983 compare_mode_
= param
;
985 case GL_TEXTURE_BASE_LEVEL
:
987 return GL_INVALID_VALUE
;
991 case GL_TEXTURE_MAX_LEVEL
:
993 return GL_INVALID_VALUE
;
997 case GL_TEXTURE_MAX_ANISOTROPY_EXT
:
999 return GL_INVALID_VALUE
;
1002 case GL_TEXTURE_USAGE_ANGLE
:
1003 if (!feature_info
->validators()->texture_usage
.IsValid(param
)) {
1004 return GL_INVALID_ENUM
;
1010 return GL_INVALID_ENUM
;
1012 Update(feature_info
);
1014 UpdateCanRenderCondition();
1018 GLenum
Texture::SetParameterf(
1019 const FeatureInfo
* feature_info
, GLenum pname
, GLfloat param
) {
1021 case GL_TEXTURE_MIN_FILTER
:
1022 case GL_TEXTURE_MAG_FILTER
:
1023 case GL_TEXTURE_POOL_CHROMIUM
:
1024 case GL_TEXTURE_WRAP_R
:
1025 case GL_TEXTURE_WRAP_S
:
1026 case GL_TEXTURE_WRAP_T
:
1027 case GL_TEXTURE_COMPARE_FUNC
:
1028 case GL_TEXTURE_COMPARE_MODE
:
1029 case GL_TEXTURE_BASE_LEVEL
:
1030 case GL_TEXTURE_MAX_LEVEL
:
1031 case GL_TEXTURE_USAGE_ANGLE
:
1033 GLint iparam
= static_cast<GLint
>(param
);
1034 return SetParameteri(feature_info
, pname
, iparam
);
1036 case GL_TEXTURE_MIN_LOD
:
1039 case GL_TEXTURE_MAX_LOD
:
1042 case GL_TEXTURE_MAX_ANISOTROPY_EXT
:
1044 return GL_INVALID_VALUE
;
1049 return GL_INVALID_ENUM
;
1054 void Texture::Update(const FeatureInfo
* feature_info
) {
1055 // Update npot status.
1056 // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others
1057 npot_
= (target_
== GL_TEXTURE_EXTERNAL_OES
) || (num_npot_faces_
> 0);
1059 if (face_infos_
.empty()) {
1060 texture_complete_
= false;
1061 cube_complete_
= false;
1065 // Update texture_complete and cube_complete status.
1066 const Texture::FaceInfo
& first_face
= face_infos_
[0];
1067 const Texture::LevelInfo
& first_level
= first_face
.level_infos
[0];
1068 const GLsizei levels_needed
= first_face
.num_mip_levels
;
1071 max_level_set_
>= (levels_needed
- 1) && max_level_set_
>= 0;
1072 cube_complete_
= (face_infos_
.size() == 6) &&
1073 (first_level
.width
== first_level
.height
);
1075 if (first_level
.width
== 0 || first_level
.height
== 0) {
1076 texture_complete_
= false;
1077 } else if (first_level
.type
== GL_FLOAT
&&
1078 !feature_info
->feature_flags().enable_texture_float_linear
&&
1079 (min_filter_
!= GL_NEAREST_MIPMAP_NEAREST
||
1080 mag_filter_
!= GL_NEAREST
)) {
1081 texture_complete_
= false;
1082 } else if (first_level
.type
== GL_HALF_FLOAT_OES
&&
1083 !feature_info
->feature_flags().enable_texture_half_float_linear
&&
1084 (min_filter_
!= GL_NEAREST_MIPMAP_NEAREST
||
1085 mag_filter_
!= GL_NEAREST
)) {
1086 texture_complete_
= false;
1089 if (cube_complete_
&& texture_level0_dirty_
) {
1090 texture_level0_complete_
= true;
1091 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
1092 const Texture::LevelInfo
& level0
= face_infos_
[ii
].level_infos
[0];
1093 if (!TextureFaceComplete(first_level
,
1096 level0
.internal_format
,
1102 texture_level0_complete_
= false;
1106 texture_level0_dirty_
= false;
1108 cube_complete_
&= texture_level0_complete_
;
1110 if (texture_complete_
&& texture_mips_dirty_
) {
1111 texture_mips_complete_
= true;
1113 ii
< face_infos_
.size() && texture_mips_complete_
;
1115 const Texture::FaceInfo
& face_info
= face_infos_
[ii
];
1116 const Texture::LevelInfo
& level0
= face_info
.level_infos
[0];
1117 for (GLsizei jj
= 1; jj
< levels_needed
; ++jj
) {
1118 const Texture::LevelInfo
& level_info
= face_infos_
[ii
].level_infos
[jj
];
1119 if (!TextureMipComplete(level0
,
1122 level_info
.internal_format
,
1128 texture_mips_complete_
= false;
1133 texture_mips_dirty_
= false;
1135 texture_complete_
&= texture_mips_complete_
;
1138 bool Texture::ClearRenderableLevels(GLES2Decoder
* decoder
) {
1144 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
1145 const Texture::FaceInfo
& face_info
= face_infos_
[ii
];
1146 for (GLint jj
= 0; jj
< face_info
.num_mip_levels
; ++jj
) {
1147 const Texture::LevelInfo
& info
= face_info
.level_infos
[jj
];
1148 if (info
.target
!= 0) {
1149 if (!ClearLevel(decoder
, info
.target
, jj
)) {
1155 UpdateSafeToRenderFrom(true);
1159 gfx::Rect
Texture::GetLevelClearedRect(GLenum target
, GLint level
) const {
1160 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
1161 if (face_index
>= face_infos_
.size() ||
1162 level
>= static_cast<GLint
>(face_infos_
[face_index
].level_infos
.size())) {
1166 const Texture::LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
1168 return info
.cleared_rect
;
1171 bool Texture::IsLevelCleared(GLenum target
, GLint level
) const {
1172 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
1173 if (face_index
>= face_infos_
.size() ||
1174 level
>= static_cast<GLint
>(face_infos_
[face_index
].level_infos
.size())) {
1178 const Texture::LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
1180 return info
.cleared_rect
== gfx::Rect(info
.width
, info
.height
);
1183 void Texture::InitTextureMaxAnisotropyIfNeeded(GLenum target
) {
1184 if (texture_max_anisotropy_initialized_
)
1186 texture_max_anisotropy_initialized_
= true;
1187 GLfloat params
[] = { 1.0f
};
1188 glTexParameterfv(target
, GL_TEXTURE_MAX_ANISOTROPY_EXT
, params
);
1191 bool Texture::ClearLevel(
1192 GLES2Decoder
* decoder
, GLenum target
, GLint level
) {
1194 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
1195 if (face_index
>= face_infos_
.size() ||
1196 level
>= static_cast<GLint
>(face_infos_
[face_index
].level_infos
.size())) {
1200 Texture::LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
1202 DCHECK(target
== info
.target
);
1204 if (info
.target
== 0 ||
1205 info
.cleared_rect
== gfx::Rect(info
.width
, info
.height
) ||
1206 info
.width
== 0 || info
.height
== 0 || info
.depth
== 0) {
1210 // Clear all remaining sub regions.
1212 0, info
.cleared_rect
.x(), info
.cleared_rect
.right(), info
.width
};
1214 0, info
.cleared_rect
.y(), info
.cleared_rect
.bottom(), info
.height
};
1216 for (size_t j
= 0; j
< 3; ++j
) {
1217 for (size_t i
= 0; i
< 3; ++i
) {
1218 // Center of nine patch is already cleared.
1219 if (j
== 1 && i
== 1)
1222 gfx::Rect
rect(x
[i
], y
[j
], x
[i
+ 1] - x
[i
], y
[j
+ 1] - y
[j
]);
1226 // NOTE: It seems kind of gross to call back into the decoder for this
1227 // but only the decoder knows all the state (like unpack_alignment_)
1228 // that's needed to be able to call GL correctly.
1229 bool cleared
= decoder
->ClearLevel(this, info
.target
, info
.level
,
1230 info
.format
, info
.type
, rect
.x(),
1231 rect
.y(), rect
.width(), rect
.height());
1237 UpdateMipCleared(&info
, info
.width
, info
.height
,
1238 gfx::Rect(info
.width
, info
.height
));
1242 void Texture::SetLevelImage(
1243 const FeatureInfo
* feature_info
,
1246 gfx::GLImage
* image
) {
1247 DCHECK_GE(level
, 0);
1248 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
1249 DCHECK_LT(static_cast<size_t>(face_index
),
1250 face_infos_
.size());
1251 DCHECK_LT(static_cast<size_t>(level
),
1252 face_infos_
[face_index
].level_infos
.size());
1253 Texture::LevelInfo
& info
=
1254 face_infos_
[face_index
].level_infos
[level
];
1255 DCHECK_EQ(info
.target
, target
);
1256 DCHECK_EQ(info
.level
, level
);
1258 UpdateCanRenderCondition();
1262 gfx::GLImage
* Texture::GetLevelImage(GLint target
, GLint level
) const {
1263 if (target
!= GL_TEXTURE_2D
&& target
!= GL_TEXTURE_EXTERNAL_OES
&&
1264 target
!= GL_TEXTURE_RECTANGLE_ARB
) {
1268 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
1269 if (level
>= 0 && face_index
< face_infos_
.size() &&
1270 static_cast<size_t>(level
) < face_infos_
[face_index
].level_infos
.size()) {
1271 const LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
1272 if (info
.target
!= 0) {
1273 return info
.image
.get();
1279 void Texture::OnWillModifyPixels() {
1280 gfx::GLImage
* image
= GetLevelImage(target(), 0);
1282 image
->WillModifyTexImage();
1285 void Texture::OnDidModifyPixels() {
1286 gfx::GLImage
* image
= GetLevelImage(target(), 0);
1288 image
->DidModifyTexImage();
1291 TextureRef::TextureRef(TextureManager
* manager
,
1294 : manager_(manager
),
1296 client_id_(client_id
),
1300 texture_
->AddTextureRef(this);
1301 manager_
->StartTracking(this);
1304 scoped_refptr
<TextureRef
> TextureRef::Create(TextureManager
* manager
,
1306 GLuint service_id
) {
1307 return new TextureRef(manager
, client_id
, new Texture(service_id
));
1310 TextureRef::~TextureRef() {
1311 manager_
->StopTracking(this);
1312 texture_
->RemoveTextureRef(this, manager_
->have_context_
);
1316 TextureManager::TextureManager(MemoryTracker
* memory_tracker
,
1317 FeatureInfo
* feature_info
,
1318 GLint max_texture_size
,
1319 GLint max_cube_map_texture_size
,
1320 GLint max_rectangle_texture_size
,
1321 GLint max_3d_texture_size
,
1322 bool use_default_textures
)
1323 : memory_tracker_managed_(
1324 new MemoryTypeTracker(memory_tracker
, MemoryTracker::kManaged
)),
1325 memory_tracker_unmanaged_(
1326 new MemoryTypeTracker(memory_tracker
, MemoryTracker::kUnmanaged
)),
1327 feature_info_(feature_info
),
1328 framebuffer_manager_(NULL
),
1329 max_texture_size_(max_texture_size
),
1330 max_cube_map_texture_size_(max_cube_map_texture_size
),
1331 max_rectangle_texture_size_(max_rectangle_texture_size
),
1332 max_3d_texture_size_(max_3d_texture_size
),
1333 max_levels_(ComputeMipMapCount(GL_TEXTURE_2D
,
1337 max_cube_map_levels_(ComputeMipMapCount(GL_TEXTURE_CUBE_MAP
,
1338 max_cube_map_texture_size
,
1339 max_cube_map_texture_size
,
1340 max_cube_map_texture_size
)),
1341 max_3d_levels_(ComputeMipMapCount(GL_TEXTURE_3D
,
1342 // Same as GL_TEXTURE_2D_ARRAY
1343 max_3d_texture_size
,
1344 max_3d_texture_size
,
1345 max_3d_texture_size
)),
1346 use_default_textures_(use_default_textures
),
1347 num_unrenderable_textures_(0),
1348 num_unsafe_textures_(0),
1349 num_uncleared_mips_(0),
1352 have_context_(true) {
1353 for (int ii
= 0; ii
< kNumDefaultTextures
; ++ii
) {
1354 black_texture_ids_
[ii
] = 0;
1358 bool TextureManager::Initialize() {
1359 // TODO(gman): The default textures have to be real textures, not the 0
1360 // texture because we simulate non shared resources on top of shared
1361 // resources and all contexts that share resource share the same default
1363 default_textures_
[kTexture2D
] = CreateDefaultAndBlackTextures(
1364 GL_TEXTURE_2D
, &black_texture_ids_
[kTexture2D
]);
1365 default_textures_
[kCubeMap
] = CreateDefaultAndBlackTextures(
1366 GL_TEXTURE_CUBE_MAP
, &black_texture_ids_
[kCubeMap
]);
1368 if (feature_info_
->feature_flags().oes_egl_image_external
) {
1369 default_textures_
[kExternalOES
] = CreateDefaultAndBlackTextures(
1370 GL_TEXTURE_EXTERNAL_OES
, &black_texture_ids_
[kExternalOES
]);
1373 if (feature_info_
->feature_flags().arb_texture_rectangle
) {
1374 default_textures_
[kRectangleARB
] = CreateDefaultAndBlackTextures(
1375 GL_TEXTURE_RECTANGLE_ARB
, &black_texture_ids_
[kRectangleARB
]);
1381 scoped_refptr
<TextureRef
>
1382 TextureManager::CreateDefaultAndBlackTextures(
1384 GLuint
* black_texture
) {
1385 static uint8 black
[] = {0, 0, 0, 255};
1387 // Sampling a texture not associated with any EGLImage sibling will return
1388 // black values according to the spec.
1389 bool needs_initialization
= (target
!= GL_TEXTURE_EXTERNAL_OES
);
1390 bool needs_faces
= (target
== GL_TEXTURE_CUBE_MAP
);
1392 // Make default textures and texture for replacing non-renderable textures.
1394 const int num_ids
= use_default_textures_
? 2 : 1;
1395 glGenTextures(num_ids
, ids
);
1396 for (int ii
= 0; ii
< num_ids
; ++ii
) {
1397 glBindTexture(target
, ids
[ii
]);
1398 if (needs_initialization
) {
1400 for (int jj
= 0; jj
< GLES2Util::kNumFaces
; ++jj
) {
1401 glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj
), 0, GL_RGBA
, 1, 1, 0,
1402 GL_RGBA
, GL_UNSIGNED_BYTE
, black
);
1405 glTexImage2D(target
, 0, GL_RGBA
, 1, 1, 0, GL_RGBA
,
1406 GL_UNSIGNED_BYTE
, black
);
1410 glBindTexture(target
, 0);
1412 scoped_refptr
<TextureRef
> default_texture
;
1413 if (use_default_textures_
) {
1414 default_texture
= TextureRef::Create(this, 0, ids
[1]);
1415 SetTarget(default_texture
.get(), target
);
1417 for (int ii
= 0; ii
< GLES2Util::kNumFaces
; ++ii
) {
1418 SetLevelInfo(default_texture
.get(), GLES2Util::IndexToGLFaceTarget(ii
),
1419 0, GL_RGBA
, 1, 1, 1, 0, GL_RGBA
, GL_UNSIGNED_BYTE
,
1423 if (needs_initialization
) {
1424 SetLevelInfo(default_texture
.get(), GL_TEXTURE_2D
, 0, GL_RGBA
, 1, 1, 1,
1425 0, GL_RGBA
, GL_UNSIGNED_BYTE
, gfx::Rect(1, 1));
1427 SetLevelInfo(default_texture
.get(), GL_TEXTURE_EXTERNAL_OES
, 0, GL_RGBA
,
1428 1, 1, 1, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, gfx::Rect(1, 1));
1433 *black_texture
= ids
[0];
1434 return default_texture
;
1437 bool TextureManager::ValidForTarget(
1438 GLenum target
, GLint level
, GLsizei width
, GLsizei height
, GLsizei depth
) {
1439 GLsizei max_size
= MaxSizeForTarget(target
) >> level
;
1440 return level
>= 0 &&
1444 level
< MaxLevelsForTarget(target
) &&
1445 width
<= max_size
&&
1446 height
<= max_size
&&
1447 depth
<= max_size
&&
1448 (level
== 0 || feature_info_
->feature_flags().npot_ok
||
1449 (!GLES2Util::IsNPOT(width
) &&
1450 !GLES2Util::IsNPOT(height
) &&
1451 !GLES2Util::IsNPOT(depth
))) &&
1452 (target
!= GL_TEXTURE_CUBE_MAP
|| (width
== height
&& depth
== 1)) &&
1453 (target
!= GL_TEXTURE_2D
|| (depth
== 1));
1456 void TextureManager::SetTarget(TextureRef
* ref
, GLenum target
) {
1459 ->SetTarget(feature_info_
.get(), target
, MaxLevelsForTarget(target
));
1462 void TextureManager::SetLevelClearedRect(TextureRef
* ref
,
1465 const gfx::Rect
& cleared_rect
) {
1467 ref
->texture()->SetLevelClearedRect(target
, level
, cleared_rect
);
1470 void TextureManager::SetLevelCleared(TextureRef
* ref
,
1475 ref
->texture()->SetLevelCleared(target
, level
, cleared
);
1478 bool TextureManager::ClearRenderableLevels(
1479 GLES2Decoder
* decoder
, TextureRef
* ref
) {
1481 return ref
->texture()->ClearRenderableLevels(decoder
);
1484 bool TextureManager::ClearTextureLevel(
1485 GLES2Decoder
* decoder
, TextureRef
* ref
,
1486 GLenum target
, GLint level
) {
1488 Texture
* texture
= ref
->texture();
1489 if (texture
->num_uncleared_mips() == 0) {
1492 bool result
= texture
->ClearLevel(decoder
, target
, level
);
1493 texture
->UpdateCleared();
1497 void TextureManager::SetLevelInfo(TextureRef
* ref
,
1500 GLenum internal_format
,
1507 const gfx::Rect
& cleared_rect
) {
1508 DCHECK(gfx::Rect(width
, height
).Contains(cleared_rect
));
1510 Texture
* texture
= ref
->texture();
1512 texture
->GetMemTracker()->TrackMemFree(texture
->estimated_size());
1513 texture
->SetLevelInfo(feature_info_
.get(), target
, level
, internal_format
,
1514 width
, height
, depth
, border
, format
, type
,
1516 texture
->GetMemTracker()->TrackMemAlloc(texture
->estimated_size());
1519 Texture
* TextureManager::Produce(TextureRef
* ref
) {
1521 return ref
->texture();
1524 TextureRef
* TextureManager::Consume(
1528 scoped_refptr
<TextureRef
> ref(new TextureRef(this, client_id
, texture
));
1529 bool result
= textures_
.insert(std::make_pair(client_id
, ref
)).second
;
1534 void TextureManager::SetParameteri(
1535 const char* function_name
, ErrorState
* error_state
,
1536 TextureRef
* ref
, GLenum pname
, GLint param
) {
1537 DCHECK(error_state
);
1539 Texture
* texture
= ref
->texture();
1540 GLenum result
= texture
->SetParameteri(feature_info_
.get(), pname
, param
);
1541 if (result
!= GL_NO_ERROR
) {
1542 if (result
== GL_INVALID_ENUM
) {
1543 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1544 error_state
, function_name
, param
, "param");
1546 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMI(
1547 error_state
, result
, function_name
, pname
, param
);
1550 // Texture tracking pools exist only for the command decoder, so
1551 // do not pass them on to the native GL implementation.
1552 if (pname
!= GL_TEXTURE_POOL_CHROMIUM
) {
1553 glTexParameteri(texture
->target(), pname
, param
);
1558 void TextureManager::SetParameterf(
1559 const char* function_name
, ErrorState
* error_state
,
1560 TextureRef
* ref
, GLenum pname
, GLfloat param
) {
1561 DCHECK(error_state
);
1563 Texture
* texture
= ref
->texture();
1564 GLenum result
= texture
->SetParameterf(feature_info_
.get(), pname
, param
);
1565 if (result
!= GL_NO_ERROR
) {
1566 if (result
== GL_INVALID_ENUM
) {
1567 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1568 error_state
, function_name
, pname
, "pname");
1570 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMF(
1571 error_state
, result
, function_name
, pname
, param
);
1574 // Texture tracking pools exist only for the command decoder, so
1575 // do not pass them on to the native GL implementation.
1576 if (pname
!= GL_TEXTURE_POOL_CHROMIUM
) {
1577 glTexParameterf(texture
->target(), pname
, param
);
1582 bool TextureManager::MarkMipmapsGenerated(TextureRef
* ref
) {
1584 Texture
* texture
= ref
->texture();
1585 texture
->GetMemTracker()->TrackMemFree(texture
->estimated_size());
1586 bool result
= texture
->MarkMipmapsGenerated(feature_info_
.get());
1587 texture
->GetMemTracker()->TrackMemAlloc(texture
->estimated_size());
1591 TextureRef
* TextureManager::CreateTexture(
1592 GLuint client_id
, GLuint service_id
) {
1593 DCHECK_NE(0u, service_id
);
1594 scoped_refptr
<TextureRef
> ref(TextureRef::Create(
1595 this, client_id
, service_id
));
1596 std::pair
<TextureMap::iterator
, bool> result
=
1597 textures_
.insert(std::make_pair(client_id
, ref
));
1598 DCHECK(result
.second
);
1602 TextureRef
* TextureManager::GetTexture(
1603 GLuint client_id
) const {
1604 TextureMap::const_iterator it
= textures_
.find(client_id
);
1605 return it
!= textures_
.end() ? it
->second
.get() : NULL
;
1608 void TextureManager::RemoveTexture(GLuint client_id
) {
1609 TextureMap::iterator it
= textures_
.find(client_id
);
1610 if (it
!= textures_
.end()) {
1611 it
->second
->reset_client_id();
1612 textures_
.erase(it
);
1616 void TextureManager::StartTracking(TextureRef
* ref
) {
1617 Texture
* texture
= ref
->texture();
1619 num_uncleared_mips_
+= texture
->num_uncleared_mips();
1620 if (!texture
->SafeToRenderFrom())
1621 ++num_unsafe_textures_
;
1622 if (!texture
->CanRender(feature_info_
.get()))
1623 ++num_unrenderable_textures_
;
1624 if (texture
->HasImages())
1628 void TextureManager::StopTracking(TextureRef
* ref
) {
1629 if (ref
->num_observers()) {
1630 for (unsigned int i
= 0; i
< destruction_observers_
.size(); i
++) {
1631 destruction_observers_
[i
]->OnTextureRefDestroying(ref
);
1633 DCHECK_EQ(ref
->num_observers(), 0);
1636 Texture
* texture
= ref
->texture();
1639 if (texture
->HasImages()) {
1640 DCHECK_NE(0, num_images_
);
1643 if (!texture
->CanRender(feature_info_
.get())) {
1644 DCHECK_NE(0, num_unrenderable_textures_
);
1645 --num_unrenderable_textures_
;
1647 if (!texture
->SafeToRenderFrom()) {
1648 DCHECK_NE(0, num_unsafe_textures_
);
1649 --num_unsafe_textures_
;
1651 num_uncleared_mips_
-= texture
->num_uncleared_mips();
1652 DCHECK_GE(num_uncleared_mips_
, 0);
1655 MemoryTypeTracker
* TextureManager::GetMemTracker(GLenum tracking_pool
) {
1656 switch (tracking_pool
) {
1657 case GL_TEXTURE_POOL_MANAGED_CHROMIUM
:
1658 return memory_tracker_managed_
.get();
1660 case GL_TEXTURE_POOL_UNMANAGED_CHROMIUM
:
1661 return memory_tracker_unmanaged_
.get();
1670 Texture
* TextureManager::GetTextureForServiceId(GLuint service_id
) const {
1671 // This doesn't need to be fast. It's only used during slow queries.
1672 for (TextureMap::const_iterator it
= textures_
.begin();
1673 it
!= textures_
.end(); ++it
) {
1674 Texture
* texture
= it
->second
->texture();
1675 if (texture
->service_id() == service_id
)
1681 GLsizei
TextureManager::ComputeMipMapCount(GLenum target
,
1686 case GL_TEXTURE_EXTERNAL_OES
:
1690 base::bits::Log2Floor(std::max(std::max(width
, height
), depth
));
1694 void TextureManager::SetLevelImage(
1698 gfx::GLImage
* image
) {
1700 ref
->texture()->SetLevelImage(feature_info_
.get(), target
, level
, image
);
1703 size_t TextureManager::GetSignatureSize() const {
1704 return sizeof(TextureTag
) + sizeof(TextureSignature
);
1707 void TextureManager::AddToSignature(
1711 std::string
* signature
) const {
1712 ref
->texture()->AddToSignature(feature_info_
.get(), target
, level
, signature
);
1715 void TextureManager::UpdateSafeToRenderFrom(int delta
) {
1716 num_unsafe_textures_
+= delta
;
1717 DCHECK_GE(num_unsafe_textures_
, 0);
1720 void TextureManager::UpdateUnclearedMips(int delta
) {
1721 num_uncleared_mips_
+= delta
;
1722 DCHECK_GE(num_uncleared_mips_
, 0);
1725 void TextureManager::UpdateCanRenderCondition(
1726 Texture::CanRenderCondition old_condition
,
1727 Texture::CanRenderCondition new_condition
) {
1728 if (old_condition
== Texture::CAN_RENDER_NEVER
||
1729 (old_condition
== Texture::CAN_RENDER_ONLY_IF_NPOT
&&
1730 !feature_info_
->feature_flags().npot_ok
)) {
1731 DCHECK_GT(num_unrenderable_textures_
, 0);
1732 --num_unrenderable_textures_
;
1734 if (new_condition
== Texture::CAN_RENDER_NEVER
||
1735 (new_condition
== Texture::CAN_RENDER_ONLY_IF_NPOT
&&
1736 !feature_info_
->feature_flags().npot_ok
))
1737 ++num_unrenderable_textures_
;
1740 void TextureManager::UpdateNumImages(int delta
) {
1741 num_images_
+= delta
;
1742 DCHECK_GE(num_images_
, 0);
1745 void TextureManager::IncFramebufferStateChangeCount() {
1746 if (framebuffer_manager_
)
1747 framebuffer_manager_
->IncFramebufferStateChangeCount();
1750 bool TextureManager::ValidateFormatAndTypeCombination(
1751 ErrorState
* error_state
, const char* function_name
, GLenum format
,
1753 // TODO(zmo): now this is only called by GLES2DecoderImpl::DoCopyTexImage2D
1754 // and is incorrect for ES3. Fix this.
1755 if (!g_format_type_validator
.Get().IsValid(format
, format
, type
)) {
1756 ERRORSTATE_SET_GL_ERROR(
1757 error_state
, GL_INVALID_OPERATION
, function_name
,
1758 (std::string("invalid type ") +
1759 GLES2Util::GetStringEnum(type
) + " for format " +
1760 GLES2Util::GetStringEnum(format
)).c_str());
1766 bool TextureManager::ValidateTextureParameters(
1767 ErrorState
* error_state
, const char* function_name
,
1768 GLenum format
, GLenum type
, GLenum internal_format
, GLint level
) {
1769 const Validators
* validators
= feature_info_
->validators();
1770 if (!validators
->texture_format
.IsValid(format
)) {
1771 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1772 error_state
, function_name
, format
, "format");
1775 if (!validators
->pixel_type
.IsValid(type
)) {
1776 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1777 error_state
, function_name
, type
, "type");
1780 if (!g_format_type_validator
.Get().IsValid(internal_format
, format
, type
)) {
1781 ERRORSTATE_SET_GL_ERROR(
1782 error_state
, GL_INVALID_OPERATION
, function_name
,
1783 "invalid internalformat/format/type combination");
1786 // For TexSubImage calls, internal_format isn't part of the parameters,
1787 // so its validation needs to be after the internal_format/format/type
1788 // combination validation. Otherwise, an unexpected INVALID_ENUM could be
1789 // generated instead of INVALID_OPERATION.
1790 if (!validators
->texture_internal_format
.IsValid(internal_format
)) {
1791 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1792 error_state
, function_name
, internal_format
, "internal_format");
1795 if (!feature_info_
->IsES3Enabled()) {
1796 uint32 channels
= GLES2Util::GetChannelsForFormat(format
);
1797 if ((channels
& (GLES2Util::kDepth
| GLES2Util::kStencil
)) != 0 && level
) {
1798 ERRORSTATE_SET_GL_ERROR(
1799 error_state
, GL_INVALID_OPERATION
, function_name
,
1800 (std::string("invalid format ") + GLES2Util::GetStringEnum(format
) +
1801 " for level != 0").c_str());
1808 // Gets the texture id for a given target.
1809 TextureRef
* TextureManager::GetTextureInfoForTarget(
1810 ContextState
* state
, GLenum target
) {
1811 TextureUnit
& unit
= state
->texture_units
[state
->active_texture_unit
];
1812 TextureRef
* texture
= NULL
;
1815 texture
= unit
.bound_texture_2d
.get();
1817 case GL_TEXTURE_CUBE_MAP
:
1818 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
1819 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
1820 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
1821 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
1822 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
1823 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
1824 texture
= unit
.bound_texture_cube_map
.get();
1826 case GL_TEXTURE_EXTERNAL_OES
:
1827 texture
= unit
.bound_texture_external_oes
.get();
1829 case GL_TEXTURE_RECTANGLE_ARB
:
1830 texture
= unit
.bound_texture_rectangle_arb
.get();
1833 texture
= unit
.bound_texture_3d
.get();
1835 case GL_TEXTURE_2D_ARRAY
:
1836 texture
= unit
.bound_texture_2d_array
.get();
1845 TextureRef
* TextureManager::GetTextureInfoForTargetUnlessDefault(
1846 ContextState
* state
, GLenum target
) {
1847 TextureRef
* texture
= GetTextureInfoForTarget(state
, target
);
1850 if (texture
== GetDefaultTextureInfo(target
))
1855 bool TextureManager::ValidateTexImage(
1856 ContextState
* state
,
1857 const char* function_name
,
1858 const DoTexImageArguments
& args
,
1859 TextureRef
** texture_ref
) {
1860 ErrorState
* error_state
= state
->GetErrorState();
1861 const Validators
* validators
= feature_info_
->validators();
1862 if (((args
.command_type
== DoTexImageArguments::kTexImage2D
) &&
1863 !validators
->texture_target
.IsValid(args
.target
)) ||
1864 ((args
.command_type
== DoTexImageArguments::kTexImage3D
) &&
1865 !validators
->texture_3_d_target
.IsValid(args
.target
))) {
1866 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1867 error_state
, function_name
, args
.target
, "target");
1870 if (!ValidateTextureParameters(
1871 error_state
, function_name
, args
.format
, args
.type
,
1872 args
.internal_format
, args
.level
)) {
1875 if (!ValidForTarget(args
.target
, args
.level
,
1876 args
.width
, args
.height
, args
.depth
) ||
1878 ERRORSTATE_SET_GL_ERROR(
1879 error_state
, GL_INVALID_VALUE
, function_name
,
1880 "dimensions out of range");
1883 if ((GLES2Util::GetChannelsForFormat(args
.format
) &
1884 (GLES2Util::kDepth
| GLES2Util::kStencil
)) != 0 && args
.pixels
) {
1885 ERRORSTATE_SET_GL_ERROR(
1886 error_state
, GL_INVALID_OPERATION
,
1887 function_name
, "can not supply data for depth or stencil textures");
1891 TextureRef
* local_texture_ref
= GetTextureInfoForTarget(state
, args
.target
);
1892 if (!local_texture_ref
) {
1893 ERRORSTATE_SET_GL_ERROR(
1894 error_state
, GL_INVALID_OPERATION
, function_name
,
1895 "unknown texture for target");
1898 if (local_texture_ref
->texture()->IsImmutable()) {
1899 ERRORSTATE_SET_GL_ERROR(
1900 error_state
, GL_INVALID_OPERATION
, function_name
,
1901 "texture is immutable");
1905 if (!memory_tracker_managed_
->EnsureGPUMemoryAvailable(args
.pixels_size
)) {
1906 ERRORSTATE_SET_GL_ERROR(error_state
, GL_OUT_OF_MEMORY
, function_name
,
1911 // Write the TextureReference since this is valid.
1912 *texture_ref
= local_texture_ref
;
1916 void TextureManager::ValidateAndDoTexImage(
1917 DecoderTextureState
* texture_state
,
1918 ContextState
* state
,
1919 DecoderFramebufferState
* framebuffer_state
,
1920 const char* function_name
,
1921 const DoTexImageArguments
& args
) {
1922 TextureRef
* texture_ref
;
1923 if (!ValidateTexImage(state
, function_name
, args
, &texture_ref
)) {
1927 DoTexImage(texture_state
, state
->GetErrorState(), framebuffer_state
,
1928 function_name
, texture_ref
, args
);
1931 GLenum
TextureManager::AdjustTexFormat(GLenum format
) const {
1932 // TODO(bajones): GLES 3 allows for internal format and format to differ.
1933 // This logic may need to change as a result.
1934 if (gfx::GetGLImplementation() == gfx::kGLImplementationDesktopGL
) {
1935 if (format
== GL_SRGB_EXT
)
1937 if (format
== GL_SRGB_ALPHA_EXT
)
1943 void TextureManager::DoTexImage(
1944 DecoderTextureState
* texture_state
,
1945 ErrorState
* error_state
,
1946 DecoderFramebufferState
* framebuffer_state
,
1947 const char* function_name
,
1948 TextureRef
* texture_ref
,
1949 const DoTexImageArguments
& args
) {
1950 Texture
* texture
= texture_ref
->texture();
1951 GLsizei tex_width
= 0;
1952 GLsizei tex_height
= 0;
1953 GLsizei tex_depth
= 0;
1954 GLenum tex_type
= 0;
1955 GLenum tex_format
= 0;
1956 bool level_is_same
=
1957 texture
->GetLevelSize(
1958 args
.target
, args
.level
, &tex_width
, &tex_height
, &tex_depth
) &&
1959 texture
->GetLevelType(args
.target
, args
.level
, &tex_type
, &tex_format
) &&
1960 args
.width
== tex_width
&& args
.height
== tex_height
&&
1961 args
.depth
== tex_depth
&& args
.type
== tex_type
&&
1962 args
.format
== tex_format
;
1964 if (level_is_same
&& !args
.pixels
) {
1965 // Just set the level texture but mark the texture as uncleared.
1966 SetLevelInfo(texture_ref
, args
.target
, args
.level
, args
.internal_format
,
1967 args
.width
, args
.height
, args
.depth
, args
.border
, args
.format
,
1968 args
.type
, gfx::Rect());
1969 texture_state
->tex_image_failed
= false;
1973 if (texture
->IsAttachedToFramebuffer()) {
1974 framebuffer_state
->clear_state_dirty
= true;
1977 if (texture_state
->texsubimage_faster_than_teximage
&&
1978 level_is_same
&& args
.pixels
) {
1980 ScopedTextureUploadTimer
timer(texture_state
);
1981 if (args
.command_type
== DoTexImageArguments::kTexImage3D
) {
1982 glTexSubImage3D(args
.target
, args
.level
, 0, 0, 0,
1983 args
.width
, args
.height
, args
.depth
,
1984 args
.format
, args
.type
, args
.pixels
);
1986 glTexSubImage2D(args
.target
, args
.level
, 0, 0, args
.width
, args
.height
,
1987 AdjustTexFormat(args
.format
), args
.type
, args
.pixels
);
1990 SetLevelCleared(texture_ref
, args
.target
, args
.level
, true);
1991 texture_state
->tex_image_failed
= false;
1995 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state
, function_name
);
1997 ScopedTextureUploadTimer
timer(texture_state
);
1998 if (args
.command_type
== DoTexImageArguments::kTexImage3D
) {
1999 glTexImage3D(args
.target
, args
.level
, args
.internal_format
, args
.width
,
2000 args
.height
, args
.depth
, args
.border
, args
.format
,
2001 args
.type
, args
.pixels
);
2003 glTexImage2D(args
.target
, args
.level
, args
.internal_format
, args
.width
,
2004 args
.height
, args
.border
, AdjustTexFormat(args
.format
),
2005 args
.type
, args
.pixels
);
2008 GLenum error
= ERRORSTATE_PEEK_GL_ERROR(error_state
, function_name
);
2009 if (error
== GL_NO_ERROR
) {
2011 texture_ref
, args
.target
, args
.level
, args
.internal_format
, args
.width
,
2012 args
.height
, args
.depth
, args
.border
, args
.format
, args
.type
,
2013 args
.pixels
!= NULL
? gfx::Rect(args
.width
, args
.height
) : gfx::Rect());
2014 texture_state
->tex_image_failed
= false;
2018 ScopedTextureUploadTimer::ScopedTextureUploadTimer(
2019 DecoderTextureState
* texture_state
)
2020 : texture_state_(texture_state
),
2021 begin_time_(base::TimeTicks::Now()) {
2024 ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
2025 texture_state_
->texture_upload_count
++;
2026 texture_state_
->total_texture_upload_time
+=
2027 base::TimeTicks::Now() - begin_time_
;
2030 } // namespace gles2