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"
10 #include "base/bits.h"
11 #include "base/strings/stringprintf.h"
12 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
13 #include "gpu/command_buffer/service/context_state.h"
14 #include "gpu/command_buffer/service/error_state.h"
15 #include "gpu/command_buffer/service/feature_info.h"
16 #include "gpu/command_buffer/service/framebuffer_manager.h"
17 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
18 #include "gpu/command_buffer/service/mailbox_manager.h"
19 #include "gpu/command_buffer/service/memory_tracking.h"
20 #include "ui/gl/gl_implementation.h"
25 // This should contain everything to uniquely identify a Texture.
26 static const char TextureTag
[] = "|Texture|";
27 struct TextureSignature
{
36 GLenum internal_format_
;
54 // Since we will be hashing this signature structure, the padding must be
55 // zero initialized. Although the C++11 specifications specify that this is
56 // true, we will use a constructor with a memset to further enforce it instead
57 // of relying on compilers adhering to this deep dark corner specification.
58 TextureSignature(GLenum target
,
66 GLenum internal_format
,
83 memset(this, 0, sizeof(TextureSignature
));
86 min_filter_
= min_filter
;
87 mag_filter_
= mag_filter
;
92 internal_format_
= internal_format
;
93 compare_func_
= compare_func
;
94 compare_mode_
= compare_mode
;
100 base_level_
= base_level
;
102 max_level_
= max_level
;
105 has_image_
= has_image
;
106 can_render_
= can_render
;
107 can_render_to_
= can_render_to
;
112 TextureManager::DestructionObserver::DestructionObserver() {}
114 TextureManager::DestructionObserver::~DestructionObserver() {}
116 TextureManager::~TextureManager() {
117 for (unsigned int i
= 0; i
< destruction_observers_
.size(); i
++)
118 destruction_observers_
[i
]->OnTextureManagerDestroying(this);
120 DCHECK(textures_
.empty());
122 // If this triggers, that means something is keeping a reference to
123 // a Texture belonging to this.
124 CHECK_EQ(texture_count_
, 0u);
126 DCHECK_EQ(0, num_unrenderable_textures_
);
127 DCHECK_EQ(0, num_unsafe_textures_
);
128 DCHECK_EQ(0, num_uncleared_mips_
);
129 DCHECK_EQ(0, num_images_
);
132 void TextureManager::Destroy(bool have_context
) {
133 have_context_
= have_context
;
135 for (int ii
= 0; ii
< kNumDefaultTextures
; ++ii
) {
136 default_textures_
[ii
] = NULL
;
140 glDeleteTextures(arraysize(black_texture_ids_
), black_texture_ids_
);
143 DCHECK_EQ(0u, memory_tracker_managed_
->GetMemRepresented());
144 DCHECK_EQ(0u, memory_tracker_unmanaged_
->GetMemRepresented());
147 Texture::Texture(GLuint service_id
)
148 : mailbox_manager_(NULL
),
149 memory_tracking_ref_(NULL
),
150 service_id_(service_id
),
152 num_uncleared_mips_(0),
155 min_filter_(GL_NEAREST_MIPMAP_LINEAR
),
156 mag_filter_(GL_LINEAR
),
161 pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM
),
162 compare_func_(GL_LEQUAL
),
163 compare_mode_(GL_NONE
),
169 texture_complete_(false),
170 texture_mips_dirty_(false),
171 texture_mips_complete_(false),
172 cube_complete_(false),
173 texture_level0_dirty_(false),
174 texture_level0_complete_(false),
176 has_been_bound_(false),
177 framebuffer_attachment_count_(0),
181 can_render_condition_(CAN_RENDER_ALWAYS
),
182 texture_max_anisotropy_initialized_(false) {
185 Texture::~Texture() {
186 if (mailbox_manager_
)
187 mailbox_manager_
->TextureDeleted(this);
190 void Texture::AddTextureRef(TextureRef
* ref
) {
191 DCHECK(refs_
.find(ref
) == refs_
.end());
193 if (!memory_tracking_ref_
) {
194 memory_tracking_ref_
= ref
;
195 GetMemTracker()->TrackMemAlloc(estimated_size());
199 void Texture::RemoveTextureRef(TextureRef
* ref
, bool have_context
) {
200 if (memory_tracking_ref_
== ref
) {
201 GetMemTracker()->TrackMemFree(estimated_size());
202 memory_tracking_ref_
= NULL
;
204 size_t result
= refs_
.erase(ref
);
205 DCHECK_EQ(result
, 1u);
208 GLuint id
= service_id();
209 glDeleteTextures(1, &id
);
212 } else if (memory_tracking_ref_
== NULL
) {
213 // TODO(piman): tune ownership semantics for cross-context group shared
215 memory_tracking_ref_
= *refs_
.begin();
216 GetMemTracker()->TrackMemAlloc(estimated_size());
220 MemoryTypeTracker
* Texture::GetMemTracker() {
221 DCHECK(memory_tracking_ref_
);
222 return memory_tracking_ref_
->manager()->GetMemTracker(pool_
);
225 Texture::LevelInfo::LevelInfo()
239 Texture::LevelInfo::LevelInfo(const LevelInfo
& rhs
)
240 : cleared(rhs
.cleared
),
243 internal_format(rhs
.internal_format
),
251 estimated_size(rhs
.estimated_size
) {
254 Texture::LevelInfo::~LevelInfo() {
257 Texture::FaceInfo::FaceInfo()
258 : num_mip_levels(0) {
261 Texture::FaceInfo::~FaceInfo() {
264 Texture::CanRenderCondition
Texture::GetCanRenderCondition() const {
266 return CAN_RENDER_ALWAYS
;
268 if (target_
!= GL_TEXTURE_EXTERNAL_OES
) {
269 if (face_infos_
.empty()) {
270 return CAN_RENDER_NEVER
;
273 const Texture::LevelInfo
& first_face
= face_infos_
[0].level_infos
[0];
274 if (first_face
.width
== 0 ||
275 first_face
.height
== 0 ||
276 first_face
.depth
== 0) {
277 return CAN_RENDER_NEVER
;
281 bool needs_mips
= NeedsMips();
283 if (!texture_complete())
284 return CAN_RENDER_NEVER
;
285 if (target_
== GL_TEXTURE_CUBE_MAP
&& !cube_complete())
286 return CAN_RENDER_NEVER
;
289 bool is_npot_compatible
= !needs_mips
&&
290 wrap_s_
== GL_CLAMP_TO_EDGE
&&
291 wrap_t_
== GL_CLAMP_TO_EDGE
;
293 if (!is_npot_compatible
) {
294 if (target_
== GL_TEXTURE_RECTANGLE_ARB
)
295 return CAN_RENDER_NEVER
;
297 return CAN_RENDER_ONLY_IF_NPOT
;
300 return CAN_RENDER_ALWAYS
;
303 bool Texture::CanRender(const FeatureInfo
* feature_info
) const {
304 switch (can_render_condition_
) {
305 case CAN_RENDER_ALWAYS
:
307 case CAN_RENDER_NEVER
:
309 case CAN_RENDER_ONLY_IF_NPOT
:
312 return feature_info
->feature_flags().npot_ok
;
315 void Texture::AddToSignature(
316 const FeatureInfo
* feature_info
,
319 std::string
* signature
) const {
320 DCHECK(feature_info
);
323 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
324 DCHECK_LT(static_cast<size_t>(face_index
),
326 DCHECK_LT(static_cast<size_t>(level
),
327 face_infos_
[face_index
].level_infos
.size());
329 const Texture::LevelInfo
& info
=
330 face_infos_
[face_index
].level_infos
[level
];
332 TextureSignature
signature_data(target
,
340 info
.internal_format
,
353 info
.image
.get() != NULL
,
354 CanRender(feature_info
),
358 signature
->append(TextureTag
, sizeof(TextureTag
));
359 signature
->append(reinterpret_cast<const char*>(&signature_data
),
360 sizeof(signature_data
));
363 void Texture::SetMailboxManager(MailboxManager
* mailbox_manager
) {
364 DCHECK(!mailbox_manager_
|| mailbox_manager_
== mailbox_manager
);
365 mailbox_manager_
= mailbox_manager
;
368 bool Texture::MarkMipmapsGenerated(
369 const FeatureInfo
* feature_info
) {
370 if (!CanGenerateMipmaps(feature_info
)) {
373 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
374 const Texture::FaceInfo
& face_info
= face_infos_
[ii
];
375 const Texture::LevelInfo
& level0_info
= face_info
.level_infos
[0];
376 GLsizei width
= level0_info
.width
;
377 GLsizei height
= level0_info
.height
;
378 GLsizei depth
= level0_info
.depth
;
379 GLenum target
= target_
== GL_TEXTURE_2D
? GL_TEXTURE_2D
:
380 GLES2Util::IndexToGLFaceTarget(ii
);
382 const GLsizei num_mips
= face_info
.num_mip_levels
;
383 for (GLsizei level
= 1; level
< num_mips
; ++level
) {
384 width
= std::max(1, width
>> 1);
385 height
= std::max(1, height
>> 1);
386 depth
= std::max(1, depth
>> 1);
387 SetLevelInfo(feature_info
,
390 level0_info
.internal_format
,
404 void Texture::SetTarget(
405 const FeatureInfo
* feature_info
, GLenum target
, GLint max_levels
) {
406 DCHECK_EQ(0u, target_
); // you can only set this once.
408 size_t num_faces
= (target
== GL_TEXTURE_CUBE_MAP
) ? 6 : 1;
409 face_infos_
.resize(num_faces
);
410 for (size_t ii
= 0; ii
< num_faces
; ++ii
) {
411 face_infos_
[ii
].level_infos
.resize(max_levels
);
414 if (target
== GL_TEXTURE_EXTERNAL_OES
|| target
== GL_TEXTURE_RECTANGLE_ARB
) {
415 min_filter_
= GL_LINEAR
;
416 wrap_s_
= wrap_t_
= GL_CLAMP_TO_EDGE
;
419 if (target
== GL_TEXTURE_EXTERNAL_OES
) {
422 Update(feature_info
);
423 UpdateCanRenderCondition();
426 bool Texture::CanGenerateMipmaps(
427 const FeatureInfo
* feature_info
) const {
428 if ((npot() && !feature_info
->feature_flags().npot_ok
) ||
429 face_infos_
.empty() ||
430 target_
== GL_TEXTURE_EXTERNAL_OES
||
431 target_
== GL_TEXTURE_RECTANGLE_ARB
) {
435 // Can't generate mips for depth or stencil textures.
436 const Texture::LevelInfo
& first
= face_infos_
[0].level_infos
[0];
437 uint32 channels
= GLES2Util::GetChannelsForFormat(first
.format
);
438 if (channels
& (GLES2Util::kDepth
| GLES2Util::kStencil
)) {
442 // TODO(gman): Check internal_format, format and type.
443 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
444 const LevelInfo
& info
= face_infos_
[ii
].level_infos
[0];
445 if ((info
.target
== 0) || (info
.width
!= first
.width
) ||
446 (info
.height
!= first
.height
) || (info
.depth
!= 1) ||
447 (info
.format
!= first
.format
) ||
448 (info
.internal_format
!= first
.internal_format
) ||
449 (info
.type
!= first
.type
) ||
450 feature_info
->validators()->compressed_texture_format
.IsValid(
451 info
.internal_format
) ||
459 bool Texture::TextureIsNPOT(GLsizei width
,
462 return (GLES2Util::IsNPOT(width
) ||
463 GLES2Util::IsNPOT(height
) ||
464 GLES2Util::IsNPOT(depth
));
467 bool Texture::TextureFaceComplete(const Texture::LevelInfo
& first_face
,
470 GLenum internal_format
,
476 bool complete
= (target
!= 0 && depth
== 1);
477 if (face_index
!= 0) {
478 complete
&= (width
== first_face
.width
&&
479 height
== first_face
.height
&&
480 internal_format
== first_face
.internal_format
&&
481 format
== first_face
.format
&&
482 type
== first_face
.type
);
487 bool Texture::TextureMipComplete(const Texture::LevelInfo
& level0_face
,
490 GLenum internal_format
,
496 bool complete
= (target
!= 0);
498 const GLsizei mip_width
= std::max(1, level0_face
.width
>> level
);
499 const GLsizei mip_height
= std::max(1, level0_face
.height
>> level
);
500 const GLsizei mip_depth
= std::max(1, level0_face
.depth
>> level
);
502 complete
&= (width
== mip_width
&&
503 height
== mip_height
&&
504 depth
== mip_depth
&&
505 internal_format
== level0_face
.internal_format
&&
506 format
== level0_face
.format
&&
507 type
== level0_face
.type
);
512 void Texture::SetLevelCleared(GLenum target
, GLint level
, bool cleared
) {
514 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
515 DCHECK_LT(static_cast<size_t>(face_index
),
517 DCHECK_LT(static_cast<size_t>(level
),
518 face_infos_
[face_index
].level_infos
.size());
519 Texture::LevelInfo
& info
=
520 face_infos_
[face_index
].level_infos
[level
];
521 UpdateMipCleared(&info
, cleared
);
525 void Texture::UpdateCleared() {
526 if (face_infos_
.empty()) {
530 const bool cleared
= (num_uncleared_mips_
== 0);
532 // If texture is uncleared and is attached to a framebuffer,
533 // that framebuffer must be marked possibly incomplete.
534 if (!cleared
&& IsAttachedToFramebuffer()) {
535 IncAllFramebufferStateChangeCount();
538 UpdateSafeToRenderFrom(cleared
);
541 void Texture::UpdateSafeToRenderFrom(bool cleared
) {
542 if (cleared_
== cleared
)
545 int delta
= cleared
? -1 : +1;
546 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
547 (*it
)->manager()->UpdateSafeToRenderFrom(delta
);
550 void Texture::UpdateMipCleared(LevelInfo
* info
, bool cleared
) {
551 if (info
->cleared
== cleared
)
553 info
->cleared
= cleared
;
554 int delta
= cleared
? -1 : +1;
555 num_uncleared_mips_
+= delta
;
556 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
557 (*it
)->manager()->UpdateUnclearedMips(delta
);
560 void Texture::UpdateCanRenderCondition() {
561 CanRenderCondition can_render_condition
= GetCanRenderCondition();
562 if (can_render_condition_
== can_render_condition
)
564 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
565 (*it
)->manager()->UpdateCanRenderCondition(can_render_condition_
,
566 can_render_condition
);
567 can_render_condition_
= can_render_condition
;
570 void Texture::UpdateHasImages() {
571 if (face_infos_
.empty())
574 bool has_images
= false;
575 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
576 for (size_t jj
= 0; jj
< face_infos_
[ii
].level_infos
.size(); ++jj
) {
577 const Texture::LevelInfo
& info
= face_infos_
[ii
].level_infos
[jj
];
578 if (info
.image
.get() != NULL
) {
585 if (has_images_
== has_images
)
587 has_images_
= has_images
;
588 int delta
= has_images
? +1 : -1;
589 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
590 (*it
)->manager()->UpdateNumImages(delta
);
593 void Texture::IncAllFramebufferStateChangeCount() {
594 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
595 (*it
)->manager()->IncFramebufferStateChangeCount();
598 void Texture::SetLevelInfo(
599 const FeatureInfo
* feature_info
,
602 GLenum internal_format
,
611 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
612 DCHECK_LT(static_cast<size_t>(face_index
),
614 DCHECK_LT(static_cast<size_t>(level
),
615 face_infos_
[face_index
].level_infos
.size());
617 DCHECK_GE(height
, 0);
619 Texture::LevelInfo
& info
=
620 face_infos_
[face_index
].level_infos
[level
];
622 // Update counters only if any attributes have changed. Counters are
623 // comparisons between the old and new values so it must be done before any
624 // assignment has been done to the LevelInfo.
625 if (info
.target
!= target
||
626 info
.internal_format
!= internal_format
||
627 info
.width
!= width
||
628 info
.height
!= height
||
629 info
.depth
!= depth
||
630 info
.format
!= format
||
633 // Calculate the mip level count.
634 face_infos_
[face_index
].num_mip_levels
=
635 TextureManager::ComputeMipMapCount(target_
, width
, height
, depth
);
637 // Update NPOT face count for the first level.
638 bool prev_npot
= TextureIsNPOT(info
.width
, info
.height
, info
.depth
);
639 bool now_npot
= TextureIsNPOT(width
, height
, depth
);
640 if (prev_npot
!= now_npot
)
641 num_npot_faces_
+= now_npot
? 1 : -1;
643 // Signify that level 0 has been changed, so they need to be reverified.
644 texture_level0_dirty_
= true;
647 // Signify that at least one of the mips has changed.
648 texture_mips_dirty_
= true;
651 info
.target
= target
;
653 info
.internal_format
= internal_format
;
655 info
.height
= height
;
657 info
.border
= border
;
658 info
.format
= format
;
662 estimated_size_
-= info
.estimated_size
;
663 GLES2Util::ComputeImageDataSizes(
664 width
, height
, 1, format
, type
, 4, &info
.estimated_size
, NULL
, NULL
);
665 estimated_size_
+= info
.estimated_size
;
667 UpdateMipCleared(&info
, cleared
);
668 max_level_set_
= std::max(max_level_set_
, level
);
669 Update(feature_info
);
671 UpdateCanRenderCondition();
673 if (IsAttachedToFramebuffer()) {
674 // TODO(gman): If textures tracked which framebuffers they were attached to
675 // we could just mark those framebuffers as not complete.
676 IncAllFramebufferStateChangeCount();
680 bool Texture::ValidForTexture(
690 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
691 if (level
>= 0 && face_index
< face_infos_
.size() &&
692 static_cast<size_t>(level
) < face_infos_
[face_index
].level_infos
.size()) {
693 const LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
697 return SafeAddInt32(xoffset
, width
, &max_x
) &&
698 SafeAddInt32(yoffset
, height
, &max_y
) &&
699 SafeAddInt32(zoffset
, depth
, &max_z
) &&
703 max_x
<= info
.width
&&
704 max_y
<= info
.height
&&
705 max_z
<= info
.depth
&&
711 bool Texture::GetLevelSize(
712 GLint target
, GLint level
,
713 GLsizei
* width
, GLsizei
* height
, GLsizei
* depth
) const {
716 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
717 if (level
>= 0 && face_index
< face_infos_
.size() &&
718 static_cast<size_t>(level
) < face_infos_
[face_index
].level_infos
.size()) {
719 const LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
720 if (info
.target
!= 0) {
722 *height
= info
.height
;
731 bool Texture::GetLevelType(
732 GLint target
, GLint level
, GLenum
* type
, GLenum
* internal_format
) const {
734 DCHECK(internal_format
);
735 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
736 if (level
>= 0 && face_index
< face_infos_
.size() &&
737 static_cast<size_t>(level
) < face_infos_
[face_index
].level_infos
.size()) {
738 const LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
739 if (info
.target
!= 0) {
741 *internal_format
= info
.internal_format
;
748 GLenum
Texture::SetParameteri(
749 const FeatureInfo
* feature_info
, GLenum pname
, GLint param
) {
750 DCHECK(feature_info
);
752 if (target_
== GL_TEXTURE_EXTERNAL_OES
||
753 target_
== GL_TEXTURE_RECTANGLE_ARB
) {
754 if (pname
== GL_TEXTURE_MIN_FILTER
&&
755 (param
!= GL_NEAREST
&& param
!= GL_LINEAR
))
756 return GL_INVALID_ENUM
;
757 if ((pname
== GL_TEXTURE_WRAP_S
|| pname
== GL_TEXTURE_WRAP_T
) &&
758 param
!= GL_CLAMP_TO_EDGE
)
759 return GL_INVALID_ENUM
;
763 case GL_TEXTURE_MIN_FILTER
:
764 if (!feature_info
->validators()->texture_min_filter_mode
.IsValid(param
)) {
765 return GL_INVALID_ENUM
;
769 case GL_TEXTURE_MAG_FILTER
:
770 if (!feature_info
->validators()->texture_mag_filter_mode
.IsValid(param
)) {
771 return GL_INVALID_ENUM
;
775 case GL_TEXTURE_POOL_CHROMIUM
:
776 if (!feature_info
->validators()->texture_pool
.IsValid(param
)) {
777 return GL_INVALID_ENUM
;
779 GetMemTracker()->TrackMemFree(estimated_size());
781 GetMemTracker()->TrackMemAlloc(estimated_size());
783 case GL_TEXTURE_WRAP_R
:
784 if (!feature_info
->validators()->texture_wrap_mode
.IsValid(param
)) {
785 return GL_INVALID_ENUM
;
789 case GL_TEXTURE_WRAP_S
:
790 if (!feature_info
->validators()->texture_wrap_mode
.IsValid(param
)) {
791 return GL_INVALID_ENUM
;
795 case GL_TEXTURE_WRAP_T
:
796 if (!feature_info
->validators()->texture_wrap_mode
.IsValid(param
)) {
797 return GL_INVALID_ENUM
;
801 case GL_TEXTURE_COMPARE_FUNC
:
802 if (!feature_info
->validators()->texture_compare_func
.IsValid(param
)) {
803 return GL_INVALID_ENUM
;
805 compare_func_
= param
;
807 case GL_TEXTURE_COMPARE_MODE
:
808 if (!feature_info
->validators()->texture_compare_mode
.IsValid(param
)) {
809 return GL_INVALID_ENUM
;
811 compare_mode_
= param
;
813 case GL_TEXTURE_BASE_LEVEL
:
815 return GL_INVALID_VALUE
;
819 case GL_TEXTURE_MAX_LEVEL
:
821 return GL_INVALID_VALUE
;
825 case GL_TEXTURE_MAX_ANISOTROPY_EXT
:
827 return GL_INVALID_VALUE
;
830 case GL_TEXTURE_USAGE_ANGLE
:
831 if (!feature_info
->validators()->texture_usage
.IsValid(param
)) {
832 return GL_INVALID_ENUM
;
838 return GL_INVALID_ENUM
;
840 Update(feature_info
);
842 UpdateCanRenderCondition();
846 GLenum
Texture::SetParameterf(
847 const FeatureInfo
* feature_info
, GLenum pname
, GLfloat param
) {
849 case GL_TEXTURE_MIN_FILTER
:
850 case GL_TEXTURE_MAG_FILTER
:
851 case GL_TEXTURE_POOL_CHROMIUM
:
852 case GL_TEXTURE_WRAP_S
:
853 case GL_TEXTURE_WRAP_T
:
854 case GL_TEXTURE_USAGE_ANGLE
:
856 GLint iparam
= static_cast<GLint
>(param
);
857 return SetParameteri(feature_info
, pname
, iparam
);
859 case GL_TEXTURE_MIN_LOD
:
862 case GL_TEXTURE_MAX_LOD
:
865 case GL_TEXTURE_MAX_ANISOTROPY_EXT
:
867 return GL_INVALID_VALUE
;
872 return GL_INVALID_ENUM
;
877 void Texture::Update(const FeatureInfo
* feature_info
) {
878 // Update npot status.
879 // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others
880 npot_
= (target_
== GL_TEXTURE_EXTERNAL_OES
) || (num_npot_faces_
> 0);
882 if (face_infos_
.empty()) {
883 texture_complete_
= false;
884 cube_complete_
= false;
888 // Update texture_complete and cube_complete status.
889 const Texture::FaceInfo
& first_face
= face_infos_
[0];
890 const Texture::LevelInfo
& first_level
= first_face
.level_infos
[0];
891 const GLsizei levels_needed
= first_face
.num_mip_levels
;
894 max_level_set_
>= (levels_needed
- 1) && max_level_set_
>= 0;
895 cube_complete_
= (face_infos_
.size() == 6) &&
896 (first_level
.width
== first_level
.height
);
898 if (first_level
.width
== 0 || first_level
.height
== 0) {
899 texture_complete_
= false;
900 } else if (first_level
.type
== GL_FLOAT
&&
901 !feature_info
->feature_flags().enable_texture_float_linear
&&
902 (min_filter_
!= GL_NEAREST_MIPMAP_NEAREST
||
903 mag_filter_
!= GL_NEAREST
)) {
904 texture_complete_
= false;
905 } else if (first_level
.type
== GL_HALF_FLOAT_OES
&&
906 !feature_info
->feature_flags().enable_texture_half_float_linear
&&
907 (min_filter_
!= GL_NEAREST_MIPMAP_NEAREST
||
908 mag_filter_
!= GL_NEAREST
)) {
909 texture_complete_
= false;
912 if (cube_complete_
&& texture_level0_dirty_
) {
913 texture_level0_complete_
= true;
914 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
915 const Texture::LevelInfo
& level0
= face_infos_
[ii
].level_infos
[0];
916 if (!TextureFaceComplete(first_level
,
919 level0
.internal_format
,
925 texture_level0_complete_
= false;
929 texture_level0_dirty_
= false;
931 cube_complete_
&= texture_level0_complete_
;
933 if (texture_complete_
&& texture_mips_dirty_
) {
934 texture_mips_complete_
= true;
936 ii
< face_infos_
.size() && texture_mips_complete_
;
938 const Texture::FaceInfo
& face_info
= face_infos_
[ii
];
939 const Texture::LevelInfo
& level0
= face_info
.level_infos
[0];
940 for (GLsizei jj
= 1; jj
< levels_needed
; ++jj
) {
941 const Texture::LevelInfo
& level_info
= face_infos_
[ii
].level_infos
[jj
];
942 if (!TextureMipComplete(level0
,
945 level_info
.internal_format
,
951 texture_mips_complete_
= false;
956 texture_mips_dirty_
= false;
958 texture_complete_
&= texture_mips_complete_
;
961 bool Texture::ClearRenderableLevels(GLES2Decoder
* decoder
) {
967 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
968 const Texture::FaceInfo
& face_info
= face_infos_
[ii
];
969 for (GLint jj
= 0; jj
< face_info
.num_mip_levels
; ++jj
) {
970 const Texture::LevelInfo
& info
= face_info
.level_infos
[jj
];
971 if (info
.target
!= 0) {
972 if (!ClearLevel(decoder
, info
.target
, jj
)) {
978 UpdateSafeToRenderFrom(true);
982 bool Texture::IsLevelCleared(GLenum target
, GLint level
) const {
983 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
984 if (face_index
>= face_infos_
.size() ||
985 level
>= static_cast<GLint
>(face_infos_
[face_index
].level_infos
.size())) {
989 const Texture::LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
994 void Texture::InitTextureMaxAnisotropyIfNeeded(GLenum target
) {
995 if (texture_max_anisotropy_initialized_
)
997 texture_max_anisotropy_initialized_
= true;
998 GLfloat params
[] = { 1.0f
};
999 glTexParameterfv(target
, GL_TEXTURE_MAX_ANISOTROPY_EXT
, params
);
1002 bool Texture::ClearLevel(
1003 GLES2Decoder
* decoder
, GLenum target
, GLint level
) {
1005 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
1006 if (face_index
>= face_infos_
.size() ||
1007 level
>= static_cast<GLint
>(face_infos_
[face_index
].level_infos
.size())) {
1011 Texture::LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
1013 DCHECK(target
== info
.target
);
1015 if (info
.target
== 0 ||
1023 // NOTE: It seems kind of gross to call back into the decoder for this
1024 // but only the decoder knows all the state (like unpack_alignment_) that's
1025 // needed to be able to call GL correctly.
1026 bool cleared
= decoder
->ClearLevel(
1027 this, info
.target
, info
.level
, info
.internal_format
, info
.format
,
1028 info
.type
, info
.width
, info
.height
, immutable_
);
1029 UpdateMipCleared(&info
, cleared
);
1030 return info
.cleared
;
1033 void Texture::SetLevelImage(
1034 const FeatureInfo
* feature_info
,
1037 gfx::GLImage
* image
) {
1038 DCHECK_GE(level
, 0);
1039 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
1040 DCHECK_LT(static_cast<size_t>(face_index
),
1041 face_infos_
.size());
1042 DCHECK_LT(static_cast<size_t>(level
),
1043 face_infos_
[face_index
].level_infos
.size());
1044 Texture::LevelInfo
& info
=
1045 face_infos_
[face_index
].level_infos
[level
];
1046 DCHECK_EQ(info
.target
, target
);
1047 DCHECK_EQ(info
.level
, level
);
1049 UpdateCanRenderCondition();
1053 gfx::GLImage
* Texture::GetLevelImage(GLint target
, GLint level
) const {
1054 if (target
!= GL_TEXTURE_2D
&& target
!= GL_TEXTURE_EXTERNAL_OES
&&
1055 target
!= GL_TEXTURE_RECTANGLE_ARB
) {
1059 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
1060 if (level
>= 0 && face_index
< face_infos_
.size() &&
1061 static_cast<size_t>(level
) < face_infos_
[face_index
].level_infos
.size()) {
1062 const LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
1063 if (info
.target
!= 0) {
1064 return info
.image
.get();
1070 void Texture::OnWillModifyPixels() {
1071 gfx::GLImage
* image
= GetLevelImage(target(), 0);
1073 image
->WillModifyTexImage();
1076 void Texture::OnDidModifyPixels() {
1077 gfx::GLImage
* image
= GetLevelImage(target(), 0);
1079 image
->DidModifyTexImage();
1082 TextureRef::TextureRef(TextureManager
* manager
,
1085 : manager_(manager
),
1087 client_id_(client_id
),
1091 texture_
->AddTextureRef(this);
1092 manager_
->StartTracking(this);
1095 scoped_refptr
<TextureRef
> TextureRef::Create(TextureManager
* manager
,
1097 GLuint service_id
) {
1098 return new TextureRef(manager
, client_id
, new Texture(service_id
));
1101 TextureRef::~TextureRef() {
1102 manager_
->StopTracking(this);
1103 texture_
->RemoveTextureRef(this, manager_
->have_context_
);
1107 TextureManager::TextureManager(MemoryTracker
* memory_tracker
,
1108 FeatureInfo
* feature_info
,
1109 GLint max_texture_size
,
1110 GLint max_cube_map_texture_size
,
1111 GLint max_rectangle_texture_size
,
1112 GLint max_3d_texture_size
,
1113 bool use_default_textures
)
1114 : memory_tracker_managed_(
1115 new MemoryTypeTracker(memory_tracker
, MemoryTracker::kManaged
)),
1116 memory_tracker_unmanaged_(
1117 new MemoryTypeTracker(memory_tracker
, MemoryTracker::kUnmanaged
)),
1118 feature_info_(feature_info
),
1119 framebuffer_manager_(NULL
),
1120 max_texture_size_(max_texture_size
),
1121 max_cube_map_texture_size_(max_cube_map_texture_size
),
1122 max_rectangle_texture_size_(max_rectangle_texture_size
),
1123 max_3d_texture_size_(max_3d_texture_size
),
1124 max_levels_(ComputeMipMapCount(GL_TEXTURE_2D
,
1128 max_cube_map_levels_(ComputeMipMapCount(GL_TEXTURE_CUBE_MAP
,
1129 max_cube_map_texture_size
,
1130 max_cube_map_texture_size
,
1131 max_cube_map_texture_size
)),
1132 max_3d_levels_(ComputeMipMapCount(GL_TEXTURE_3D
,
1133 // Same as GL_TEXTURE_2D_ARRAY
1134 max_3d_texture_size
,
1135 max_3d_texture_size
,
1136 max_3d_texture_size
)),
1137 use_default_textures_(use_default_textures
),
1138 num_unrenderable_textures_(0),
1139 num_unsafe_textures_(0),
1140 num_uncleared_mips_(0),
1143 have_context_(true) {
1144 for (int ii
= 0; ii
< kNumDefaultTextures
; ++ii
) {
1145 black_texture_ids_
[ii
] = 0;
1149 bool TextureManager::Initialize() {
1150 // TODO(gman): The default textures have to be real textures, not the 0
1151 // texture because we simulate non shared resources on top of shared
1152 // resources and all contexts that share resource share the same default
1154 default_textures_
[kTexture2D
] = CreateDefaultAndBlackTextures(
1155 GL_TEXTURE_2D
, &black_texture_ids_
[kTexture2D
]);
1156 default_textures_
[kCubeMap
] = CreateDefaultAndBlackTextures(
1157 GL_TEXTURE_CUBE_MAP
, &black_texture_ids_
[kCubeMap
]);
1159 if (feature_info_
->feature_flags().oes_egl_image_external
) {
1160 default_textures_
[kExternalOES
] = CreateDefaultAndBlackTextures(
1161 GL_TEXTURE_EXTERNAL_OES
, &black_texture_ids_
[kExternalOES
]);
1164 if (feature_info_
->feature_flags().arb_texture_rectangle
) {
1165 default_textures_
[kRectangleARB
] = CreateDefaultAndBlackTextures(
1166 GL_TEXTURE_RECTANGLE_ARB
, &black_texture_ids_
[kRectangleARB
]);
1172 scoped_refptr
<TextureRef
>
1173 TextureManager::CreateDefaultAndBlackTextures(
1175 GLuint
* black_texture
) {
1176 static uint8 black
[] = {0, 0, 0, 255};
1178 // Sampling a texture not associated with any EGLImage sibling will return
1179 // black values according to the spec.
1180 bool needs_initialization
= (target
!= GL_TEXTURE_EXTERNAL_OES
);
1181 bool needs_faces
= (target
== GL_TEXTURE_CUBE_MAP
);
1183 // Make default textures and texture for replacing non-renderable textures.
1185 const int num_ids
= use_default_textures_
? 2 : 1;
1186 glGenTextures(num_ids
, ids
);
1187 for (int ii
= 0; ii
< num_ids
; ++ii
) {
1188 glBindTexture(target
, ids
[ii
]);
1189 if (needs_initialization
) {
1191 for (int jj
= 0; jj
< GLES2Util::kNumFaces
; ++jj
) {
1192 glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj
), 0, GL_RGBA
, 1, 1, 0,
1193 GL_RGBA
, GL_UNSIGNED_BYTE
, black
);
1196 glTexImage2D(target
, 0, GL_RGBA
, 1, 1, 0, GL_RGBA
,
1197 GL_UNSIGNED_BYTE
, black
);
1201 glBindTexture(target
, 0);
1203 scoped_refptr
<TextureRef
> default_texture
;
1204 if (use_default_textures_
) {
1205 default_texture
= TextureRef::Create(this, 0, ids
[1]);
1206 SetTarget(default_texture
.get(), target
);
1208 for (int ii
= 0; ii
< GLES2Util::kNumFaces
; ++ii
) {
1209 SetLevelInfo(default_texture
.get(),
1210 GLES2Util::IndexToGLFaceTarget(ii
),
1222 if (needs_initialization
) {
1223 SetLevelInfo(default_texture
.get(),
1235 SetLevelInfo(default_texture
.get(),
1236 GL_TEXTURE_EXTERNAL_OES
,
1250 *black_texture
= ids
[0];
1251 return default_texture
;
1254 bool TextureManager::ValidForTarget(
1255 GLenum target
, GLint level
, GLsizei width
, GLsizei height
, GLsizei depth
) {
1256 GLsizei max_size
= MaxSizeForTarget(target
) >> level
;
1257 return level
>= 0 &&
1261 level
< MaxLevelsForTarget(target
) &&
1262 width
<= max_size
&&
1263 height
<= max_size
&&
1264 depth
<= max_size
&&
1265 (level
== 0 || feature_info_
->feature_flags().npot_ok
||
1266 (!GLES2Util::IsNPOT(width
) &&
1267 !GLES2Util::IsNPOT(height
) &&
1268 !GLES2Util::IsNPOT(depth
))) &&
1269 (target
!= GL_TEXTURE_CUBE_MAP
|| (width
== height
&& depth
== 1)) &&
1270 (target
!= GL_TEXTURE_2D
|| (depth
== 1));
1273 void TextureManager::SetTarget(TextureRef
* ref
, GLenum target
) {
1276 ->SetTarget(feature_info_
.get(), target
, MaxLevelsForTarget(target
));
1279 void TextureManager::SetLevelCleared(TextureRef
* ref
,
1284 ref
->texture()->SetLevelCleared(target
, level
, cleared
);
1287 bool TextureManager::ClearRenderableLevels(
1288 GLES2Decoder
* decoder
, TextureRef
* ref
) {
1290 return ref
->texture()->ClearRenderableLevels(decoder
);
1293 bool TextureManager::ClearTextureLevel(
1294 GLES2Decoder
* decoder
, TextureRef
* ref
,
1295 GLenum target
, GLint level
) {
1297 Texture
* texture
= ref
->texture();
1298 if (texture
->num_uncleared_mips() == 0) {
1301 bool result
= texture
->ClearLevel(decoder
, target
, level
);
1302 texture
->UpdateCleared();
1306 void TextureManager::SetLevelInfo(
1310 GLenum internal_format
,
1319 Texture
* texture
= ref
->texture();
1321 texture
->GetMemTracker()->TrackMemFree(texture
->estimated_size());
1322 texture
->SetLevelInfo(feature_info_
.get(),
1333 texture
->GetMemTracker()->TrackMemAlloc(texture
->estimated_size());
1336 Texture
* TextureManager::Produce(TextureRef
* ref
) {
1338 return ref
->texture();
1341 TextureRef
* TextureManager::Consume(
1345 scoped_refptr
<TextureRef
> ref(new TextureRef(this, client_id
, texture
));
1346 bool result
= textures_
.insert(std::make_pair(client_id
, ref
)).second
;
1351 void TextureManager::SetParameteri(
1352 const char* function_name
, ErrorState
* error_state
,
1353 TextureRef
* ref
, GLenum pname
, GLint param
) {
1354 DCHECK(error_state
);
1356 Texture
* texture
= ref
->texture();
1357 GLenum result
= texture
->SetParameteri(feature_info_
.get(), pname
, param
);
1358 if (result
!= GL_NO_ERROR
) {
1359 if (result
== GL_INVALID_ENUM
) {
1360 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1361 error_state
, function_name
, param
, "param");
1363 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMI(
1364 error_state
, result
, function_name
, pname
, param
);
1367 // Texture tracking pools exist only for the command decoder, so
1368 // do not pass them on to the native GL implementation.
1369 if (pname
!= GL_TEXTURE_POOL_CHROMIUM
) {
1370 glTexParameteri(texture
->target(), pname
, param
);
1375 void TextureManager::SetParameterf(
1376 const char* function_name
, ErrorState
* error_state
,
1377 TextureRef
* ref
, GLenum pname
, GLfloat param
) {
1378 DCHECK(error_state
);
1380 Texture
* texture
= ref
->texture();
1381 GLenum result
= texture
->SetParameterf(feature_info_
.get(), pname
, param
);
1382 if (result
!= GL_NO_ERROR
) {
1383 if (result
== GL_INVALID_ENUM
) {
1384 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1385 error_state
, function_name
, pname
, "pname");
1387 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMF(
1388 error_state
, result
, function_name
, pname
, param
);
1391 // Texture tracking pools exist only for the command decoder, so
1392 // do not pass them on to the native GL implementation.
1393 if (pname
!= GL_TEXTURE_POOL_CHROMIUM
) {
1394 glTexParameterf(texture
->target(), pname
, param
);
1399 bool TextureManager::MarkMipmapsGenerated(TextureRef
* ref
) {
1401 Texture
* texture
= ref
->texture();
1402 texture
->GetMemTracker()->TrackMemFree(texture
->estimated_size());
1403 bool result
= texture
->MarkMipmapsGenerated(feature_info_
.get());
1404 texture
->GetMemTracker()->TrackMemAlloc(texture
->estimated_size());
1408 TextureRef
* TextureManager::CreateTexture(
1409 GLuint client_id
, GLuint service_id
) {
1410 DCHECK_NE(0u, service_id
);
1411 scoped_refptr
<TextureRef
> ref(TextureRef::Create(
1412 this, client_id
, service_id
));
1413 std::pair
<TextureMap::iterator
, bool> result
=
1414 textures_
.insert(std::make_pair(client_id
, ref
));
1415 DCHECK(result
.second
);
1419 TextureRef
* TextureManager::GetTexture(
1420 GLuint client_id
) const {
1421 TextureMap::const_iterator it
= textures_
.find(client_id
);
1422 return it
!= textures_
.end() ? it
->second
.get() : NULL
;
1425 void TextureManager::RemoveTexture(GLuint client_id
) {
1426 TextureMap::iterator it
= textures_
.find(client_id
);
1427 if (it
!= textures_
.end()) {
1428 it
->second
->reset_client_id();
1429 textures_
.erase(it
);
1433 void TextureManager::StartTracking(TextureRef
* ref
) {
1434 Texture
* texture
= ref
->texture();
1436 num_uncleared_mips_
+= texture
->num_uncleared_mips();
1437 if (!texture
->SafeToRenderFrom())
1438 ++num_unsafe_textures_
;
1439 if (!texture
->CanRender(feature_info_
.get()))
1440 ++num_unrenderable_textures_
;
1441 if (texture
->HasImages())
1445 void TextureManager::StopTracking(TextureRef
* ref
) {
1446 if (ref
->num_observers()) {
1447 for (unsigned int i
= 0; i
< destruction_observers_
.size(); i
++) {
1448 destruction_observers_
[i
]->OnTextureRefDestroying(ref
);
1450 DCHECK_EQ(ref
->num_observers(), 0);
1453 Texture
* texture
= ref
->texture();
1456 if (texture
->HasImages()) {
1457 DCHECK_NE(0, num_images_
);
1460 if (!texture
->CanRender(feature_info_
.get())) {
1461 DCHECK_NE(0, num_unrenderable_textures_
);
1462 --num_unrenderable_textures_
;
1464 if (!texture
->SafeToRenderFrom()) {
1465 DCHECK_NE(0, num_unsafe_textures_
);
1466 --num_unsafe_textures_
;
1468 num_uncleared_mips_
-= texture
->num_uncleared_mips();
1469 DCHECK_GE(num_uncleared_mips_
, 0);
1472 MemoryTypeTracker
* TextureManager::GetMemTracker(GLenum tracking_pool
) {
1473 switch (tracking_pool
) {
1474 case GL_TEXTURE_POOL_MANAGED_CHROMIUM
:
1475 return memory_tracker_managed_
.get();
1477 case GL_TEXTURE_POOL_UNMANAGED_CHROMIUM
:
1478 return memory_tracker_unmanaged_
.get();
1487 Texture
* TextureManager::GetTextureForServiceId(GLuint service_id
) const {
1488 // This doesn't need to be fast. It's only used during slow queries.
1489 for (TextureMap::const_iterator it
= textures_
.begin();
1490 it
!= textures_
.end(); ++it
) {
1491 Texture
* texture
= it
->second
->texture();
1492 if (texture
->service_id() == service_id
)
1498 GLsizei
TextureManager::ComputeMipMapCount(GLenum target
,
1503 case GL_TEXTURE_EXTERNAL_OES
:
1507 base::bits::Log2Floor(std::max(std::max(width
, height
), depth
));
1511 void TextureManager::SetLevelImage(
1515 gfx::GLImage
* image
) {
1517 ref
->texture()->SetLevelImage(feature_info_
.get(), target
, level
, image
);
1520 size_t TextureManager::GetSignatureSize() const {
1521 return sizeof(TextureTag
) + sizeof(TextureSignature
);
1524 void TextureManager::AddToSignature(
1528 std::string
* signature
) const {
1529 ref
->texture()->AddToSignature(feature_info_
.get(), target
, level
, signature
);
1532 void TextureManager::UpdateSafeToRenderFrom(int delta
) {
1533 num_unsafe_textures_
+= delta
;
1534 DCHECK_GE(num_unsafe_textures_
, 0);
1537 void TextureManager::UpdateUnclearedMips(int delta
) {
1538 num_uncleared_mips_
+= delta
;
1539 DCHECK_GE(num_uncleared_mips_
, 0);
1542 void TextureManager::UpdateCanRenderCondition(
1543 Texture::CanRenderCondition old_condition
,
1544 Texture::CanRenderCondition new_condition
) {
1545 if (old_condition
== Texture::CAN_RENDER_NEVER
||
1546 (old_condition
== Texture::CAN_RENDER_ONLY_IF_NPOT
&&
1547 !feature_info_
->feature_flags().npot_ok
)) {
1548 DCHECK_GT(num_unrenderable_textures_
, 0);
1549 --num_unrenderable_textures_
;
1551 if (new_condition
== Texture::CAN_RENDER_NEVER
||
1552 (new_condition
== Texture::CAN_RENDER_ONLY_IF_NPOT
&&
1553 !feature_info_
->feature_flags().npot_ok
))
1554 ++num_unrenderable_textures_
;
1557 void TextureManager::UpdateNumImages(int delta
) {
1558 num_images_
+= delta
;
1559 DCHECK_GE(num_images_
, 0);
1562 void TextureManager::IncFramebufferStateChangeCount() {
1563 if (framebuffer_manager_
)
1564 framebuffer_manager_
->IncFramebufferStateChangeCount();
1567 bool TextureManager::ValidateFormatAndTypeCombination(
1568 ErrorState
* error_state
, const char* function_name
, GLenum format
,
1570 if (!feature_info_
->GetTextureFormatValidator(format
).IsValid(type
)) {
1571 ERRORSTATE_SET_GL_ERROR(
1572 error_state
, GL_INVALID_OPERATION
, function_name
,
1573 (std::string("invalid type ") +
1574 GLES2Util::GetStringEnum(type
) + " for format " +
1575 GLES2Util::GetStringEnum(format
)).c_str());
1581 bool TextureManager::ValidateTextureParameters(
1582 ErrorState
* error_state
, const char* function_name
,
1583 GLenum format
, GLenum type
, GLenum internal_format
, GLint level
) {
1584 const Validators
* validators
= feature_info_
->validators();
1585 if (!validators
->texture_format
.IsValid(format
)) {
1586 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1587 error_state
, function_name
, format
, "format");
1590 if (!validators
->pixel_type
.IsValid(type
)) {
1591 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1592 error_state
, function_name
, type
, "type");
1595 if (format
!= internal_format
&&
1596 !((internal_format
== GL_RGBA32F
&& format
== GL_RGBA
) ||
1597 (internal_format
== GL_RGB32F
&& format
== GL_RGB
))) {
1598 ERRORSTATE_SET_GL_ERROR(
1599 error_state
, GL_INVALID_OPERATION
, function_name
,
1600 "format != internalformat");
1603 uint32 channels
= GLES2Util::GetChannelsForFormat(format
);
1604 if ((channels
& (GLES2Util::kDepth
| GLES2Util::kStencil
)) != 0 && level
) {
1605 ERRORSTATE_SET_GL_ERROR(
1606 error_state
, GL_INVALID_OPERATION
, function_name
,
1607 (std::string("invalid format ") + GLES2Util::GetStringEnum(format
) +
1608 " for level != 0").c_str());
1611 return ValidateFormatAndTypeCombination(error_state
, function_name
,
1615 // Gets the texture id for a given target.
1616 TextureRef
* TextureManager::GetTextureInfoForTarget(
1617 ContextState
* state
, GLenum target
) {
1618 TextureUnit
& unit
= state
->texture_units
[state
->active_texture_unit
];
1619 TextureRef
* texture
= NULL
;
1622 texture
= unit
.bound_texture_2d
.get();
1624 case GL_TEXTURE_CUBE_MAP
:
1625 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
1626 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
1627 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
1628 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
1629 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
1630 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
1631 texture
= unit
.bound_texture_cube_map
.get();
1633 case GL_TEXTURE_EXTERNAL_OES
:
1634 texture
= unit
.bound_texture_external_oes
.get();
1636 case GL_TEXTURE_RECTANGLE_ARB
:
1637 texture
= unit
.bound_texture_rectangle_arb
.get();
1640 texture
= unit
.bound_texture_3d
.get();
1642 case GL_TEXTURE_2D_ARRAY
:
1643 texture
= unit
.bound_texture_2d_array
.get();
1652 TextureRef
* TextureManager::GetTextureInfoForTargetUnlessDefault(
1653 ContextState
* state
, GLenum target
) {
1654 TextureRef
* texture
= GetTextureInfoForTarget(state
, target
);
1657 if (texture
== GetDefaultTextureInfo(target
))
1662 bool TextureManager::ValidateTexImage2D(
1663 ContextState
* state
,
1664 const char* function_name
,
1665 const DoTextImage2DArguments
& args
,
1666 TextureRef
** texture_ref
) {
1667 ErrorState
* error_state
= state
->GetErrorState();
1668 const Validators
* validators
= feature_info_
->validators();
1669 if (!validators
->texture_target
.IsValid(args
.target
)) {
1670 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1671 error_state
, function_name
, args
.target
, "target");
1674 if (!validators
->texture_internal_format
.IsValid(args
.internal_format
)) {
1675 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1676 error_state
, function_name
, args
.internal_format
,
1680 if (!ValidateTextureParameters(
1681 error_state
, function_name
, args
.format
, args
.type
,
1682 args
.internal_format
, args
.level
)) {
1685 if (!ValidForTarget(args
.target
, args
.level
, args
.width
, args
.height
, 1) ||
1687 ERRORSTATE_SET_GL_ERROR(
1688 error_state
, GL_INVALID_VALUE
, function_name
,
1689 "dimensions out of range");
1692 if ((GLES2Util::GetChannelsForFormat(args
.format
) &
1693 (GLES2Util::kDepth
| GLES2Util::kStencil
)) != 0 && args
.pixels
) {
1694 ERRORSTATE_SET_GL_ERROR(
1695 error_state
, GL_INVALID_OPERATION
,
1696 function_name
, "can not supply data for depth or stencil textures");
1700 TextureRef
* local_texture_ref
= GetTextureInfoForTarget(state
, args
.target
);
1701 if (!local_texture_ref
) {
1702 ERRORSTATE_SET_GL_ERROR(
1703 error_state
, GL_INVALID_OPERATION
, function_name
,
1704 "unknown texture for target");
1707 if (local_texture_ref
->texture()->IsImmutable()) {
1708 ERRORSTATE_SET_GL_ERROR(
1709 error_state
, GL_INVALID_OPERATION
, function_name
,
1710 "texture is immutable");
1714 if (!memory_tracker_managed_
->EnsureGPUMemoryAvailable(args
.pixels_size
)) {
1715 ERRORSTATE_SET_GL_ERROR(error_state
, GL_OUT_OF_MEMORY
, function_name
,
1720 // Write the TextureReference since this is valid.
1721 *texture_ref
= local_texture_ref
;
1725 void TextureManager::ValidateAndDoTexImage2D(
1726 DecoderTextureState
* texture_state
,
1727 ContextState
* state
,
1728 DecoderFramebufferState
* framebuffer_state
,
1729 const DoTextImage2DArguments
& args
) {
1730 TextureRef
* texture_ref
;
1731 if (!ValidateTexImage2D(state
, "glTexImage2D", args
, &texture_ref
)) {
1735 DoTexImage2D(texture_state
, state
->GetErrorState(), framebuffer_state
,
1739 GLenum
TextureManager::AdjustTexFormat(GLenum format
) const {
1740 // TODO(bajones): GLES 3 allows for internal format and format to differ.
1741 // This logic may need to change as a result.
1742 if (gfx::GetGLImplementation() == gfx::kGLImplementationDesktopGL
) {
1743 if (format
== GL_SRGB_EXT
)
1745 if (format
== GL_SRGB_ALPHA_EXT
)
1751 void TextureManager::DoTexImage2D(
1752 DecoderTextureState
* texture_state
,
1753 ErrorState
* error_state
,
1754 DecoderFramebufferState
* framebuffer_state
,
1755 TextureRef
* texture_ref
,
1756 const DoTextImage2DArguments
& args
) {
1757 Texture
* texture
= texture_ref
->texture();
1758 GLsizei tex_width
= 0;
1759 GLsizei tex_height
= 0;
1760 GLenum tex_type
= 0;
1761 GLenum tex_format
= 0;
1762 bool level_is_same
=
1763 texture
->GetLevelSize(
1764 args
.target
, args
.level
, &tex_width
, &tex_height
, nullptr) &&
1765 texture
->GetLevelType(args
.target
, args
.level
, &tex_type
, &tex_format
) &&
1766 args
.width
== tex_width
&& args
.height
== tex_height
&&
1767 args
.type
== tex_type
&& args
.format
== tex_format
;
1769 if (level_is_same
&& !args
.pixels
) {
1770 // Just set the level texture but mark the texture as uncleared.
1773 args
.target
, args
.level
, args
.internal_format
, args
.width
, args
.height
,
1774 1, args
.border
, args
.format
, args
.type
, false);
1775 texture_state
->tex_image_2d_failed
= false;
1779 if (texture
->IsAttachedToFramebuffer()) {
1780 framebuffer_state
->clear_state_dirty
= true;
1783 if (texture_state
->texsubimage2d_faster_than_teximage2d
&&
1784 level_is_same
&& args
.pixels
) {
1786 ScopedTextureUploadTimer
timer(texture_state
);
1787 glTexSubImage2D(args
.target
, args
.level
, 0, 0, args
.width
, args
.height
,
1788 AdjustTexFormat(args
.format
), args
.type
, args
.pixels
);
1790 SetLevelCleared(texture_ref
, args
.target
, args
.level
, true);
1791 texture_state
->tex_image_2d_failed
= false;
1795 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state
, "glTexImage2D");
1797 ScopedTextureUploadTimer
timer(texture_state
);
1799 args
.target
, args
.level
, args
.internal_format
, args
.width
, args
.height
,
1800 args
.border
, AdjustTexFormat(args
.format
), args
.type
, args
.pixels
);
1802 GLenum error
= ERRORSTATE_PEEK_GL_ERROR(error_state
, "glTexImage2D");
1803 if (error
== GL_NO_ERROR
) {
1806 args
.target
, args
.level
, args
.internal_format
, args
.width
, args
.height
,
1807 1, args
.border
, args
.format
, args
.type
, args
.pixels
!= NULL
);
1808 texture_state
->tex_image_2d_failed
= false;
1812 ScopedTextureUploadTimer::ScopedTextureUploadTimer(
1813 DecoderTextureState
* texture_state
)
1814 : texture_state_(texture_state
),
1815 begin_time_(base::TimeTicks::Now()) {
1818 ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
1819 texture_state_
->texture_upload_count
++;
1820 texture_state_
->total_texture_upload_time
+=
1821 base::TimeTicks::Now() - begin_time_
;
1824 } // namespace gles2