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
{
35 GLenum internal_format_
;
47 // Since we will be hashing this signature structure, the padding must be
48 // zero initialized. Although the C++11 specifications specify that this is
49 // true, we will use a constructor with a memset to further enforce it instead
50 // of relying on compilers adhering to this deep dark corner specification.
51 TextureSignature(GLenum target
,
58 GLenum internal_format
,
69 memset(this, 0, sizeof(TextureSignature
));
72 min_filter_
= min_filter
;
73 mag_filter_
= mag_filter
;
77 internal_format_
= internal_format
;
84 has_image_
= has_image
;
85 can_render_
= can_render
;
86 can_render_to_
= can_render_to
;
91 TextureManager::DestructionObserver::DestructionObserver() {}
93 TextureManager::DestructionObserver::~DestructionObserver() {}
95 TextureManager::~TextureManager() {
96 for (unsigned int i
= 0; i
< destruction_observers_
.size(); i
++)
97 destruction_observers_
[i
]->OnTextureManagerDestroying(this);
99 DCHECK(textures_
.empty());
101 // If this triggers, that means something is keeping a reference to
102 // a Texture belonging to this.
103 CHECK_EQ(texture_count_
, 0u);
105 DCHECK_EQ(0, num_unrenderable_textures_
);
106 DCHECK_EQ(0, num_unsafe_textures_
);
107 DCHECK_EQ(0, num_uncleared_mips_
);
108 DCHECK_EQ(0, num_images_
);
111 void TextureManager::Destroy(bool have_context
) {
112 have_context_
= have_context
;
114 for (int ii
= 0; ii
< kNumDefaultTextures
; ++ii
) {
115 default_textures_
[ii
] = NULL
;
119 glDeleteTextures(arraysize(black_texture_ids_
), black_texture_ids_
);
122 DCHECK_EQ(0u, memory_tracker_managed_
->GetMemRepresented());
123 DCHECK_EQ(0u, memory_tracker_unmanaged_
->GetMemRepresented());
126 Texture::Texture(GLuint service_id
)
127 : mailbox_manager_(NULL
),
128 memory_tracking_ref_(NULL
),
129 service_id_(service_id
),
131 num_uncleared_mips_(0),
134 min_filter_(GL_NEAREST_MIPMAP_LINEAR
),
135 mag_filter_(GL_LINEAR
),
139 pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM
),
141 texture_complete_(false),
142 texture_mips_dirty_(false),
143 texture_mips_complete_(false),
144 cube_complete_(false),
145 texture_level0_dirty_(false),
146 texture_level0_complete_(false),
148 has_been_bound_(false),
149 framebuffer_attachment_count_(0),
153 can_render_condition_(CAN_RENDER_ALWAYS
),
154 texture_max_anisotropy_initialized_(false) {
157 Texture::~Texture() {
158 if (mailbox_manager_
)
159 mailbox_manager_
->TextureDeleted(this);
162 void Texture::AddTextureRef(TextureRef
* ref
) {
163 DCHECK(refs_
.find(ref
) == refs_
.end());
165 if (!memory_tracking_ref_
) {
166 memory_tracking_ref_
= ref
;
167 GetMemTracker()->TrackMemAlloc(estimated_size());
171 void Texture::RemoveTextureRef(TextureRef
* ref
, bool have_context
) {
172 if (memory_tracking_ref_
== ref
) {
173 GetMemTracker()->TrackMemFree(estimated_size());
174 memory_tracking_ref_
= NULL
;
176 size_t result
= refs_
.erase(ref
);
177 DCHECK_EQ(result
, 1u);
180 GLuint id
= service_id();
181 glDeleteTextures(1, &id
);
184 } else if (memory_tracking_ref_
== NULL
) {
185 // TODO(piman): tune ownership semantics for cross-context group shared
187 memory_tracking_ref_
= *refs_
.begin();
188 GetMemTracker()->TrackMemAlloc(estimated_size());
192 MemoryTypeTracker
* Texture::GetMemTracker() {
193 DCHECK(memory_tracking_ref_
);
194 return memory_tracking_ref_
->manager()->GetMemTracker(pool_
);
197 Texture::LevelInfo::LevelInfo()
211 Texture::LevelInfo::LevelInfo(const LevelInfo
& rhs
)
212 : cleared(rhs
.cleared
),
215 internal_format(rhs
.internal_format
),
223 estimated_size(rhs
.estimated_size
) {
226 Texture::LevelInfo::~LevelInfo() {
229 Texture::FaceInfo::FaceInfo()
230 : num_mip_levels(0) {
233 Texture::FaceInfo::~FaceInfo() {
236 Texture::CanRenderCondition
Texture::GetCanRenderCondition() const {
238 return CAN_RENDER_ALWAYS
;
240 if (target_
!= GL_TEXTURE_EXTERNAL_OES
) {
241 if (face_infos_
.empty()) {
242 return CAN_RENDER_NEVER
;
245 const Texture::LevelInfo
& first_face
= face_infos_
[0].level_infos
[0];
246 if (first_face
.width
== 0 ||
247 first_face
.height
== 0 ||
248 first_face
.depth
== 0) {
249 return CAN_RENDER_NEVER
;
253 bool needs_mips
= NeedsMips();
255 if (!texture_complete())
256 return CAN_RENDER_NEVER
;
257 if (target_
== GL_TEXTURE_CUBE_MAP
&& !cube_complete())
258 return CAN_RENDER_NEVER
;
261 bool is_npot_compatible
= !needs_mips
&&
262 wrap_s_
== GL_CLAMP_TO_EDGE
&&
263 wrap_t_
== GL_CLAMP_TO_EDGE
;
265 if (!is_npot_compatible
) {
266 if (target_
== GL_TEXTURE_RECTANGLE_ARB
)
267 return CAN_RENDER_NEVER
;
269 return CAN_RENDER_ONLY_IF_NPOT
;
272 return CAN_RENDER_ALWAYS
;
275 bool Texture::CanRender(const FeatureInfo
* feature_info
) const {
276 switch (can_render_condition_
) {
277 case CAN_RENDER_ALWAYS
:
279 case CAN_RENDER_NEVER
:
281 case CAN_RENDER_ONLY_IF_NPOT
:
284 return feature_info
->feature_flags().npot_ok
;
287 void Texture::AddToSignature(
288 const FeatureInfo
* feature_info
,
291 std::string
* signature
) const {
292 DCHECK(feature_info
);
295 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
296 DCHECK_LT(static_cast<size_t>(face_index
),
298 DCHECK_LT(static_cast<size_t>(level
),
299 face_infos_
[face_index
].level_infos
.size());
301 const Texture::LevelInfo
& info
=
302 face_infos_
[face_index
].level_infos
[level
];
304 TextureSignature
signature_data(target
,
311 info
.internal_format
,
318 info
.image
.get() != NULL
,
319 CanRender(feature_info
),
323 signature
->append(TextureTag
, sizeof(TextureTag
));
324 signature
->append(reinterpret_cast<const char*>(&signature_data
),
325 sizeof(signature_data
));
328 void Texture::SetMailboxManager(MailboxManager
* mailbox_manager
) {
329 DCHECK(!mailbox_manager_
|| mailbox_manager_
== mailbox_manager
);
330 mailbox_manager_
= mailbox_manager
;
333 bool Texture::MarkMipmapsGenerated(
334 const FeatureInfo
* feature_info
) {
335 if (!CanGenerateMipmaps(feature_info
)) {
338 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
339 const Texture::FaceInfo
& face_info
= face_infos_
[ii
];
340 const Texture::LevelInfo
& level0_info
= face_info
.level_infos
[0];
341 GLsizei width
= level0_info
.width
;
342 GLsizei height
= level0_info
.height
;
343 GLsizei depth
= level0_info
.depth
;
344 GLenum target
= target_
== GL_TEXTURE_2D
? GL_TEXTURE_2D
:
345 GLES2Util::IndexToGLFaceTarget(ii
);
347 const GLsizei num_mips
= face_info
.num_mip_levels
;
348 for (GLsizei level
= 1; level
< num_mips
; ++level
) {
349 width
= std::max(1, width
>> 1);
350 height
= std::max(1, height
>> 1);
351 depth
= std::max(1, depth
>> 1);
352 SetLevelInfo(feature_info
,
355 level0_info
.internal_format
,
369 void Texture::SetTarget(
370 const FeatureInfo
* feature_info
, GLenum target
, GLint max_levels
) {
371 DCHECK_EQ(0u, target_
); // you can only set this once.
373 size_t num_faces
= (target
== GL_TEXTURE_CUBE_MAP
) ? 6 : 1;
374 face_infos_
.resize(num_faces
);
375 for (size_t ii
= 0; ii
< num_faces
; ++ii
) {
376 face_infos_
[ii
].level_infos
.resize(max_levels
);
379 if (target
== GL_TEXTURE_EXTERNAL_OES
|| target
== GL_TEXTURE_RECTANGLE_ARB
) {
380 min_filter_
= GL_LINEAR
;
381 wrap_s_
= wrap_t_
= GL_CLAMP_TO_EDGE
;
384 if (target
== GL_TEXTURE_EXTERNAL_OES
) {
387 Update(feature_info
);
388 UpdateCanRenderCondition();
391 bool Texture::CanGenerateMipmaps(
392 const FeatureInfo
* feature_info
) const {
393 if ((npot() && !feature_info
->feature_flags().npot_ok
) ||
394 face_infos_
.empty() ||
395 target_
== GL_TEXTURE_EXTERNAL_OES
||
396 target_
== GL_TEXTURE_RECTANGLE_ARB
) {
400 // Can't generate mips for depth or stencil textures.
401 const Texture::LevelInfo
& first
= face_infos_
[0].level_infos
[0];
402 uint32 channels
= GLES2Util::GetChannelsForFormat(first
.format
);
403 if (channels
& (GLES2Util::kDepth
| GLES2Util::kStencil
)) {
407 // TODO(gman): Check internal_format, format and type.
408 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
409 const LevelInfo
& info
= face_infos_
[ii
].level_infos
[0];
410 if ((info
.target
== 0) || (info
.width
!= first
.width
) ||
411 (info
.height
!= first
.height
) || (info
.depth
!= 1) ||
412 (info
.format
!= first
.format
) ||
413 (info
.internal_format
!= first
.internal_format
) ||
414 (info
.type
!= first
.type
) ||
415 feature_info
->validators()->compressed_texture_format
.IsValid(
416 info
.internal_format
) ||
424 bool Texture::TextureIsNPOT(GLsizei width
,
427 return (GLES2Util::IsNPOT(width
) ||
428 GLES2Util::IsNPOT(height
) ||
429 GLES2Util::IsNPOT(depth
));
432 bool Texture::TextureFaceComplete(const Texture::LevelInfo
& first_face
,
435 GLenum internal_format
,
441 bool complete
= (target
!= 0 && depth
== 1);
442 if (face_index
!= 0) {
443 complete
&= (width
== first_face
.width
&&
444 height
== first_face
.height
&&
445 internal_format
== first_face
.internal_format
&&
446 format
== first_face
.format
&&
447 type
== first_face
.type
);
452 bool Texture::TextureMipComplete(const Texture::LevelInfo
& level0_face
,
455 GLenum internal_format
,
461 bool complete
= (target
!= 0);
463 const GLsizei mip_width
= std::max(1, level0_face
.width
>> level
);
464 const GLsizei mip_height
= std::max(1, level0_face
.height
>> level
);
465 const GLsizei mip_depth
= std::max(1, level0_face
.depth
>> level
);
467 complete
&= (width
== mip_width
&&
468 height
== mip_height
&&
469 depth
== mip_depth
&&
470 internal_format
== level0_face
.internal_format
&&
471 format
== level0_face
.format
&&
472 type
== level0_face
.type
);
477 void Texture::SetLevelCleared(GLenum target
, GLint level
, bool cleared
) {
479 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
480 DCHECK_LT(static_cast<size_t>(face_index
),
482 DCHECK_LT(static_cast<size_t>(level
),
483 face_infos_
[face_index
].level_infos
.size());
484 Texture::LevelInfo
& info
=
485 face_infos_
[face_index
].level_infos
[level
];
486 UpdateMipCleared(&info
, cleared
);
490 void Texture::UpdateCleared() {
491 if (face_infos_
.empty()) {
495 const bool cleared
= (num_uncleared_mips_
== 0);
497 // If texture is uncleared and is attached to a framebuffer,
498 // that framebuffer must be marked possibly incomplete.
499 if (!cleared
&& IsAttachedToFramebuffer()) {
500 IncAllFramebufferStateChangeCount();
503 UpdateSafeToRenderFrom(cleared
);
506 void Texture::UpdateSafeToRenderFrom(bool cleared
) {
507 if (cleared_
== cleared
)
510 int delta
= cleared
? -1 : +1;
511 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
512 (*it
)->manager()->UpdateSafeToRenderFrom(delta
);
515 void Texture::UpdateMipCleared(LevelInfo
* info
, bool cleared
) {
516 if (info
->cleared
== cleared
)
518 info
->cleared
= cleared
;
519 int delta
= cleared
? -1 : +1;
520 num_uncleared_mips_
+= delta
;
521 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
522 (*it
)->manager()->UpdateUnclearedMips(delta
);
525 void Texture::UpdateCanRenderCondition() {
526 CanRenderCondition can_render_condition
= GetCanRenderCondition();
527 if (can_render_condition_
== can_render_condition
)
529 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
530 (*it
)->manager()->UpdateCanRenderCondition(can_render_condition_
,
531 can_render_condition
);
532 can_render_condition_
= can_render_condition
;
535 void Texture::UpdateHasImages() {
536 if (face_infos_
.empty())
539 bool has_images
= false;
540 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
541 for (size_t jj
= 0; jj
< face_infos_
[ii
].level_infos
.size(); ++jj
) {
542 const Texture::LevelInfo
& info
= face_infos_
[ii
].level_infos
[jj
];
543 if (info
.image
.get() != NULL
) {
550 if (has_images_
== has_images
)
552 has_images_
= has_images
;
553 int delta
= has_images
? +1 : -1;
554 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
555 (*it
)->manager()->UpdateNumImages(delta
);
558 void Texture::IncAllFramebufferStateChangeCount() {
559 for (RefSet::iterator it
= refs_
.begin(); it
!= refs_
.end(); ++it
)
560 (*it
)->manager()->IncFramebufferStateChangeCount();
563 void Texture::SetLevelInfo(
564 const FeatureInfo
* feature_info
,
567 GLenum internal_format
,
576 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
577 DCHECK_LT(static_cast<size_t>(face_index
),
579 DCHECK_LT(static_cast<size_t>(level
),
580 face_infos_
[face_index
].level_infos
.size());
582 DCHECK_GE(height
, 0);
584 Texture::LevelInfo
& info
=
585 face_infos_
[face_index
].level_infos
[level
];
587 // Update counters only if any attributes have changed. Counters are
588 // comparisons between the old and new values so it must be done before any
589 // assignment has been done to the LevelInfo.
590 if (info
.target
!= target
||
591 info
.internal_format
!= internal_format
||
592 info
.width
!= width
||
593 info
.height
!= height
||
594 info
.depth
!= depth
||
595 info
.format
!= format
||
598 // Calculate the mip level count.
599 face_infos_
[face_index
].num_mip_levels
=
600 TextureManager::ComputeMipMapCount(target_
, width
, height
, depth
);
602 // Update NPOT face count for the first level.
603 bool prev_npot
= TextureIsNPOT(info
.width
, info
.height
, info
.depth
);
604 bool now_npot
= TextureIsNPOT(width
, height
, depth
);
605 if (prev_npot
!= now_npot
)
606 num_npot_faces_
+= now_npot
? 1 : -1;
608 // Signify that level 0 has been changed, so they need to be reverified.
609 texture_level0_dirty_
= true;
612 // Signify that at least one of the mips has changed.
613 texture_mips_dirty_
= true;
616 info
.target
= target
;
618 info
.internal_format
= internal_format
;
620 info
.height
= height
;
622 info
.border
= border
;
623 info
.format
= format
;
627 estimated_size_
-= info
.estimated_size
;
628 GLES2Util::ComputeImageDataSizes(
629 width
, height
, 1, format
, type
, 4, &info
.estimated_size
, NULL
, NULL
);
630 estimated_size_
+= info
.estimated_size
;
632 UpdateMipCleared(&info
, cleared
);
633 max_level_set_
= std::max(max_level_set_
, level
);
634 Update(feature_info
);
636 UpdateCanRenderCondition();
638 if (IsAttachedToFramebuffer()) {
639 // TODO(gman): If textures tracked which framebuffers they were attached to
640 // we could just mark those framebuffers as not complete.
641 IncAllFramebufferStateChangeCount();
645 bool Texture::ValidForTexture(
653 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
654 if (level
>= 0 && face_index
< face_infos_
.size() &&
655 static_cast<size_t>(level
) < face_infos_
[face_index
].level_infos
.size()) {
656 const LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
659 return SafeAddInt32(xoffset
, width
, &right
) &&
660 SafeAddInt32(yoffset
, height
, &top
) &&
663 right
<= info
.width
&&
664 top
<= info
.height
&&
670 bool Texture::GetLevelSize(
671 GLint target
, GLint level
, GLsizei
* width
, GLsizei
* height
) const {
674 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
675 if (level
>= 0 && face_index
< face_infos_
.size() &&
676 static_cast<size_t>(level
) < face_infos_
[face_index
].level_infos
.size()) {
677 const LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
678 if (info
.target
!= 0) {
680 *height
= info
.height
;
687 bool Texture::GetLevelType(
688 GLint target
, GLint level
, GLenum
* type
, GLenum
* internal_format
) const {
690 DCHECK(internal_format
);
691 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
692 if (level
>= 0 && face_index
< face_infos_
.size() &&
693 static_cast<size_t>(level
) < face_infos_
[face_index
].level_infos
.size()) {
694 const LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
695 if (info
.target
!= 0) {
697 *internal_format
= info
.internal_format
;
704 GLenum
Texture::SetParameteri(
705 const FeatureInfo
* feature_info
, GLenum pname
, GLint param
) {
706 DCHECK(feature_info
);
708 if (target_
== GL_TEXTURE_EXTERNAL_OES
||
709 target_
== GL_TEXTURE_RECTANGLE_ARB
) {
710 if (pname
== GL_TEXTURE_MIN_FILTER
&&
711 (param
!= GL_NEAREST
&& param
!= GL_LINEAR
))
712 return GL_INVALID_ENUM
;
713 if ((pname
== GL_TEXTURE_WRAP_S
|| pname
== GL_TEXTURE_WRAP_T
) &&
714 param
!= GL_CLAMP_TO_EDGE
)
715 return GL_INVALID_ENUM
;
719 case GL_TEXTURE_MIN_FILTER
:
720 if (!feature_info
->validators()->texture_min_filter_mode
.IsValid(param
)) {
721 return GL_INVALID_ENUM
;
725 case GL_TEXTURE_MAG_FILTER
:
726 if (!feature_info
->validators()->texture_mag_filter_mode
.IsValid(param
)) {
727 return GL_INVALID_ENUM
;
731 case GL_TEXTURE_POOL_CHROMIUM
:
732 if (!feature_info
->validators()->texture_pool
.IsValid(param
)) {
733 return GL_INVALID_ENUM
;
735 GetMemTracker()->TrackMemFree(estimated_size());
737 GetMemTracker()->TrackMemAlloc(estimated_size());
739 case GL_TEXTURE_WRAP_S
:
740 if (!feature_info
->validators()->texture_wrap_mode
.IsValid(param
)) {
741 return GL_INVALID_ENUM
;
745 case GL_TEXTURE_WRAP_T
:
746 if (!feature_info
->validators()->texture_wrap_mode
.IsValid(param
)) {
747 return GL_INVALID_ENUM
;
751 case GL_TEXTURE_MAX_ANISOTROPY_EXT
:
753 return GL_INVALID_VALUE
;
756 case GL_TEXTURE_USAGE_ANGLE
:
757 if (!feature_info
->validators()->texture_usage
.IsValid(param
)) {
758 return GL_INVALID_ENUM
;
764 return GL_INVALID_ENUM
;
766 Update(feature_info
);
768 UpdateCanRenderCondition();
772 GLenum
Texture::SetParameterf(
773 const FeatureInfo
* feature_info
, GLenum pname
, GLfloat param
) {
775 case GL_TEXTURE_MIN_FILTER
:
776 case GL_TEXTURE_MAG_FILTER
:
777 case GL_TEXTURE_POOL_CHROMIUM
:
778 case GL_TEXTURE_WRAP_S
:
779 case GL_TEXTURE_WRAP_T
:
780 case GL_TEXTURE_USAGE_ANGLE
:
782 GLint iparam
= static_cast<GLint
>(param
);
783 return SetParameteri(feature_info
, pname
, iparam
);
785 case GL_TEXTURE_MAX_ANISOTROPY_EXT
:
787 return GL_INVALID_VALUE
;
792 return GL_INVALID_ENUM
;
797 void Texture::Update(const FeatureInfo
* feature_info
) {
798 // Update npot status.
799 // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others
800 npot_
= (target_
== GL_TEXTURE_EXTERNAL_OES
) || (num_npot_faces_
> 0);
802 if (face_infos_
.empty()) {
803 texture_complete_
= false;
804 cube_complete_
= false;
808 // Update texture_complete and cube_complete status.
809 const Texture::FaceInfo
& first_face
= face_infos_
[0];
810 const Texture::LevelInfo
& first_level
= first_face
.level_infos
[0];
811 const GLsizei levels_needed
= first_face
.num_mip_levels
;
814 max_level_set_
>= (levels_needed
- 1) && max_level_set_
>= 0;
815 cube_complete_
= (face_infos_
.size() == 6) &&
816 (first_level
.width
== first_level
.height
);
818 if (first_level
.width
== 0 || first_level
.height
== 0) {
819 texture_complete_
= false;
820 } else if (first_level
.type
== GL_FLOAT
&&
821 !feature_info
->feature_flags().enable_texture_float_linear
&&
822 (min_filter_
!= GL_NEAREST_MIPMAP_NEAREST
||
823 mag_filter_
!= GL_NEAREST
)) {
824 texture_complete_
= false;
825 } else if (first_level
.type
== GL_HALF_FLOAT_OES
&&
826 !feature_info
->feature_flags().enable_texture_half_float_linear
&&
827 (min_filter_
!= GL_NEAREST_MIPMAP_NEAREST
||
828 mag_filter_
!= GL_NEAREST
)) {
829 texture_complete_
= false;
832 if (cube_complete_
&& texture_level0_dirty_
) {
833 texture_level0_complete_
= true;
834 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
835 const Texture::LevelInfo
& level0
= face_infos_
[ii
].level_infos
[0];
836 if (!TextureFaceComplete(first_level
,
839 level0
.internal_format
,
845 texture_level0_complete_
= false;
849 texture_level0_dirty_
= false;
851 cube_complete_
&= texture_level0_complete_
;
853 if (texture_complete_
&& texture_mips_dirty_
) {
854 texture_mips_complete_
= true;
856 ii
< face_infos_
.size() && texture_mips_complete_
;
858 const Texture::FaceInfo
& face_info
= face_infos_
[ii
];
859 const Texture::LevelInfo
& level0
= face_info
.level_infos
[0];
860 for (GLsizei jj
= 1; jj
< levels_needed
; ++jj
) {
861 const Texture::LevelInfo
& level_info
= face_infos_
[ii
].level_infos
[jj
];
862 if (!TextureMipComplete(level0
,
865 level_info
.internal_format
,
871 texture_mips_complete_
= false;
876 texture_mips_dirty_
= false;
878 texture_complete_
&= texture_mips_complete_
;
881 bool Texture::ClearRenderableLevels(GLES2Decoder
* decoder
) {
887 for (size_t ii
= 0; ii
< face_infos_
.size(); ++ii
) {
888 const Texture::FaceInfo
& face_info
= face_infos_
[ii
];
889 for (GLint jj
= 0; jj
< face_info
.num_mip_levels
; ++jj
) {
890 const Texture::LevelInfo
& info
= face_info
.level_infos
[jj
];
891 if (info
.target
!= 0) {
892 if (!ClearLevel(decoder
, info
.target
, jj
)) {
898 UpdateSafeToRenderFrom(true);
902 bool Texture::IsLevelCleared(GLenum target
, GLint level
) const {
903 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
904 if (face_index
>= face_infos_
.size() ||
905 level
>= static_cast<GLint
>(face_infos_
[face_index
].level_infos
.size())) {
909 const Texture::LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
914 void Texture::InitTextureMaxAnisotropyIfNeeded(GLenum target
) {
915 if (texture_max_anisotropy_initialized_
)
917 texture_max_anisotropy_initialized_
= true;
918 GLfloat params
[] = { 1.0f
};
919 glTexParameterfv(target
, GL_TEXTURE_MAX_ANISOTROPY_EXT
, params
);
922 bool Texture::ClearLevel(
923 GLES2Decoder
* decoder
, GLenum target
, GLint level
) {
925 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
926 if (face_index
>= face_infos_
.size() ||
927 level
>= static_cast<GLint
>(face_infos_
[face_index
].level_infos
.size())) {
931 Texture::LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
933 DCHECK(target
== info
.target
);
935 if (info
.target
== 0 ||
943 // NOTE: It seems kind of gross to call back into the decoder for this
944 // but only the decoder knows all the state (like unpack_alignment_) that's
945 // needed to be able to call GL correctly.
946 bool cleared
= decoder
->ClearLevel(
947 this, info
.target
, info
.level
, info
.internal_format
, info
.format
,
948 info
.type
, info
.width
, info
.height
, immutable_
);
949 UpdateMipCleared(&info
, cleared
);
953 void Texture::SetLevelImage(
954 const FeatureInfo
* feature_info
,
957 gfx::GLImage
* image
) {
959 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
960 DCHECK_LT(static_cast<size_t>(face_index
),
962 DCHECK_LT(static_cast<size_t>(level
),
963 face_infos_
[face_index
].level_infos
.size());
964 Texture::LevelInfo
& info
=
965 face_infos_
[face_index
].level_infos
[level
];
966 DCHECK_EQ(info
.target
, target
);
967 DCHECK_EQ(info
.level
, level
);
969 UpdateCanRenderCondition();
973 gfx::GLImage
* Texture::GetLevelImage(GLint target
, GLint level
) const {
974 if (target
!= GL_TEXTURE_2D
&& target
!= GL_TEXTURE_EXTERNAL_OES
&&
975 target
!= GL_TEXTURE_RECTANGLE_ARB
) {
979 size_t face_index
= GLES2Util::GLTargetToFaceIndex(target
);
980 if (level
>= 0 && face_index
< face_infos_
.size() &&
981 static_cast<size_t>(level
) < face_infos_
[face_index
].level_infos
.size()) {
982 const LevelInfo
& info
= face_infos_
[face_index
].level_infos
[level
];
983 if (info
.target
!= 0) {
984 return info
.image
.get();
990 void Texture::OnWillModifyPixels() {
991 gfx::GLImage
* image
= GetLevelImage(target(), 0);
993 image
->WillModifyTexImage();
996 void Texture::OnDidModifyPixels() {
997 gfx::GLImage
* image
= GetLevelImage(target(), 0);
999 image
->DidModifyTexImage();
1002 TextureRef::TextureRef(TextureManager
* manager
,
1005 : manager_(manager
),
1007 client_id_(client_id
),
1011 texture_
->AddTextureRef(this);
1012 manager_
->StartTracking(this);
1015 scoped_refptr
<TextureRef
> TextureRef::Create(TextureManager
* manager
,
1017 GLuint service_id
) {
1018 return new TextureRef(manager
, client_id
, new Texture(service_id
));
1021 TextureRef::~TextureRef() {
1022 manager_
->StopTracking(this);
1023 texture_
->RemoveTextureRef(this, manager_
->have_context_
);
1027 TextureManager::TextureManager(MemoryTracker
* memory_tracker
,
1028 FeatureInfo
* feature_info
,
1029 GLint max_texture_size
,
1030 GLint max_cube_map_texture_size
,
1031 GLint max_rectangle_texture_size
,
1032 bool use_default_textures
)
1033 : memory_tracker_managed_(
1034 new MemoryTypeTracker(memory_tracker
, MemoryTracker::kManaged
)),
1035 memory_tracker_unmanaged_(
1036 new MemoryTypeTracker(memory_tracker
, MemoryTracker::kUnmanaged
)),
1037 feature_info_(feature_info
),
1038 framebuffer_manager_(NULL
),
1039 max_texture_size_(max_texture_size
),
1040 max_cube_map_texture_size_(max_cube_map_texture_size
),
1041 max_rectangle_texture_size_(max_rectangle_texture_size
),
1042 max_levels_(ComputeMipMapCount(GL_TEXTURE_2D
,
1046 max_cube_map_levels_(ComputeMipMapCount(GL_TEXTURE_CUBE_MAP
,
1047 max_cube_map_texture_size
,
1048 max_cube_map_texture_size
,
1049 max_cube_map_texture_size
)),
1050 use_default_textures_(use_default_textures
),
1051 num_unrenderable_textures_(0),
1052 num_unsafe_textures_(0),
1053 num_uncleared_mips_(0),
1056 have_context_(true) {
1057 for (int ii
= 0; ii
< kNumDefaultTextures
; ++ii
) {
1058 black_texture_ids_
[ii
] = 0;
1062 bool TextureManager::Initialize() {
1063 // TODO(gman): The default textures have to be real textures, not the 0
1064 // texture because we simulate non shared resources on top of shared
1065 // resources and all contexts that share resource share the same default
1067 default_textures_
[kTexture2D
] = CreateDefaultAndBlackTextures(
1068 GL_TEXTURE_2D
, &black_texture_ids_
[kTexture2D
]);
1069 default_textures_
[kCubeMap
] = CreateDefaultAndBlackTextures(
1070 GL_TEXTURE_CUBE_MAP
, &black_texture_ids_
[kCubeMap
]);
1072 if (feature_info_
->feature_flags().oes_egl_image_external
) {
1073 default_textures_
[kExternalOES
] = CreateDefaultAndBlackTextures(
1074 GL_TEXTURE_EXTERNAL_OES
, &black_texture_ids_
[kExternalOES
]);
1077 if (feature_info_
->feature_flags().arb_texture_rectangle
) {
1078 default_textures_
[kRectangleARB
] = CreateDefaultAndBlackTextures(
1079 GL_TEXTURE_RECTANGLE_ARB
, &black_texture_ids_
[kRectangleARB
]);
1085 scoped_refptr
<TextureRef
>
1086 TextureManager::CreateDefaultAndBlackTextures(
1088 GLuint
* black_texture
) {
1089 static uint8 black
[] = {0, 0, 0, 255};
1091 // Sampling a texture not associated with any EGLImage sibling will return
1092 // black values according to the spec.
1093 bool needs_initialization
= (target
!= GL_TEXTURE_EXTERNAL_OES
);
1094 bool needs_faces
= (target
== GL_TEXTURE_CUBE_MAP
);
1096 // Make default textures and texture for replacing non-renderable textures.
1098 const int num_ids
= use_default_textures_
? 2 : 1;
1099 glGenTextures(num_ids
, ids
);
1100 for (int ii
= 0; ii
< num_ids
; ++ii
) {
1101 glBindTexture(target
, ids
[ii
]);
1102 if (needs_initialization
) {
1104 for (int jj
= 0; jj
< GLES2Util::kNumFaces
; ++jj
) {
1105 glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj
), 0, GL_RGBA
, 1, 1, 0,
1106 GL_RGBA
, GL_UNSIGNED_BYTE
, black
);
1109 glTexImage2D(target
, 0, GL_RGBA
, 1, 1, 0, GL_RGBA
,
1110 GL_UNSIGNED_BYTE
, black
);
1114 glBindTexture(target
, 0);
1116 scoped_refptr
<TextureRef
> default_texture
;
1117 if (use_default_textures_
) {
1118 default_texture
= TextureRef::Create(this, 0, ids
[1]);
1119 SetTarget(default_texture
.get(), target
);
1121 for (int ii
= 0; ii
< GLES2Util::kNumFaces
; ++ii
) {
1122 SetLevelInfo(default_texture
.get(),
1123 GLES2Util::IndexToGLFaceTarget(ii
),
1135 if (needs_initialization
) {
1136 SetLevelInfo(default_texture
.get(),
1148 SetLevelInfo(default_texture
.get(),
1149 GL_TEXTURE_EXTERNAL_OES
,
1163 *black_texture
= ids
[0];
1164 return default_texture
;
1167 bool TextureManager::ValidForTarget(
1168 GLenum target
, GLint level
, GLsizei width
, GLsizei height
, GLsizei depth
) {
1169 GLsizei max_size
= MaxSizeForTarget(target
) >> level
;
1170 return level
>= 0 &&
1174 level
< MaxLevelsForTarget(target
) &&
1175 width
<= max_size
&&
1176 height
<= max_size
&&
1177 depth
<= max_size
&&
1178 (level
== 0 || feature_info_
->feature_flags().npot_ok
||
1179 (!GLES2Util::IsNPOT(width
) &&
1180 !GLES2Util::IsNPOT(height
) &&
1181 !GLES2Util::IsNPOT(depth
))) &&
1182 (target
!= GL_TEXTURE_CUBE_MAP
|| (width
== height
&& depth
== 1)) &&
1183 (target
!= GL_TEXTURE_2D
|| (depth
== 1));
1186 void TextureManager::SetTarget(TextureRef
* ref
, GLenum target
) {
1189 ->SetTarget(feature_info_
.get(), target
, MaxLevelsForTarget(target
));
1192 void TextureManager::SetLevelCleared(TextureRef
* ref
,
1197 ref
->texture()->SetLevelCleared(target
, level
, cleared
);
1200 bool TextureManager::ClearRenderableLevels(
1201 GLES2Decoder
* decoder
, TextureRef
* ref
) {
1203 return ref
->texture()->ClearRenderableLevels(decoder
);
1206 bool TextureManager::ClearTextureLevel(
1207 GLES2Decoder
* decoder
, TextureRef
* ref
,
1208 GLenum target
, GLint level
) {
1210 Texture
* texture
= ref
->texture();
1211 if (texture
->num_uncleared_mips() == 0) {
1214 bool result
= texture
->ClearLevel(decoder
, target
, level
);
1215 texture
->UpdateCleared();
1219 void TextureManager::SetLevelInfo(
1223 GLenum internal_format
,
1232 Texture
* texture
= ref
->texture();
1234 texture
->GetMemTracker()->TrackMemFree(texture
->estimated_size());
1235 texture
->SetLevelInfo(feature_info_
.get(),
1246 texture
->GetMemTracker()->TrackMemAlloc(texture
->estimated_size());
1249 Texture
* TextureManager::Produce(TextureRef
* ref
) {
1251 return ref
->texture();
1254 TextureRef
* TextureManager::Consume(
1258 scoped_refptr
<TextureRef
> ref(new TextureRef(this, client_id
, texture
));
1259 bool result
= textures_
.insert(std::make_pair(client_id
, ref
)).second
;
1264 void TextureManager::SetParameteri(
1265 const char* function_name
, ErrorState
* error_state
,
1266 TextureRef
* ref
, GLenum pname
, GLint param
) {
1267 DCHECK(error_state
);
1269 Texture
* texture
= ref
->texture();
1270 GLenum result
= texture
->SetParameteri(feature_info_
.get(), pname
, param
);
1271 if (result
!= GL_NO_ERROR
) {
1272 if (result
== GL_INVALID_ENUM
) {
1273 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1274 error_state
, function_name
, param
, "param");
1276 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMI(
1277 error_state
, result
, function_name
, pname
, param
);
1280 // Texture tracking pools exist only for the command decoder, so
1281 // do not pass them on to the native GL implementation.
1282 if (pname
!= GL_TEXTURE_POOL_CHROMIUM
) {
1283 glTexParameteri(texture
->target(), pname
, param
);
1288 void TextureManager::SetParameterf(
1289 const char* function_name
, ErrorState
* error_state
,
1290 TextureRef
* ref
, GLenum pname
, GLfloat param
) {
1291 DCHECK(error_state
);
1293 Texture
* texture
= ref
->texture();
1294 GLenum result
= texture
->SetParameterf(feature_info_
.get(), pname
, param
);
1295 if (result
!= GL_NO_ERROR
) {
1296 if (result
== GL_INVALID_ENUM
) {
1297 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1298 error_state
, function_name
, pname
, "pname");
1300 ERRORSTATE_SET_GL_ERROR_INVALID_PARAMF(
1301 error_state
, result
, function_name
, pname
, param
);
1304 // Texture tracking pools exist only for the command decoder, so
1305 // do not pass them on to the native GL implementation.
1306 if (pname
!= GL_TEXTURE_POOL_CHROMIUM
) {
1307 glTexParameterf(texture
->target(), pname
, param
);
1312 bool TextureManager::MarkMipmapsGenerated(TextureRef
* ref
) {
1314 Texture
* texture
= ref
->texture();
1315 texture
->GetMemTracker()->TrackMemFree(texture
->estimated_size());
1316 bool result
= texture
->MarkMipmapsGenerated(feature_info_
.get());
1317 texture
->GetMemTracker()->TrackMemAlloc(texture
->estimated_size());
1321 TextureRef
* TextureManager::CreateTexture(
1322 GLuint client_id
, GLuint service_id
) {
1323 DCHECK_NE(0u, service_id
);
1324 scoped_refptr
<TextureRef
> ref(TextureRef::Create(
1325 this, client_id
, service_id
));
1326 std::pair
<TextureMap::iterator
, bool> result
=
1327 textures_
.insert(std::make_pair(client_id
, ref
));
1328 DCHECK(result
.second
);
1332 TextureRef
* TextureManager::GetTexture(
1333 GLuint client_id
) const {
1334 TextureMap::const_iterator it
= textures_
.find(client_id
);
1335 return it
!= textures_
.end() ? it
->second
.get() : NULL
;
1338 void TextureManager::RemoveTexture(GLuint client_id
) {
1339 TextureMap::iterator it
= textures_
.find(client_id
);
1340 if (it
!= textures_
.end()) {
1341 it
->second
->reset_client_id();
1342 textures_
.erase(it
);
1346 void TextureManager::StartTracking(TextureRef
* ref
) {
1347 Texture
* texture
= ref
->texture();
1349 num_uncleared_mips_
+= texture
->num_uncleared_mips();
1350 if (!texture
->SafeToRenderFrom())
1351 ++num_unsafe_textures_
;
1352 if (!texture
->CanRender(feature_info_
.get()))
1353 ++num_unrenderable_textures_
;
1354 if (texture
->HasImages())
1358 void TextureManager::StopTracking(TextureRef
* ref
) {
1359 if (ref
->num_observers()) {
1360 for (unsigned int i
= 0; i
< destruction_observers_
.size(); i
++) {
1361 destruction_observers_
[i
]->OnTextureRefDestroying(ref
);
1363 DCHECK_EQ(ref
->num_observers(), 0);
1366 Texture
* texture
= ref
->texture();
1369 if (texture
->HasImages()) {
1370 DCHECK_NE(0, num_images_
);
1373 if (!texture
->CanRender(feature_info_
.get())) {
1374 DCHECK_NE(0, num_unrenderable_textures_
);
1375 --num_unrenderable_textures_
;
1377 if (!texture
->SafeToRenderFrom()) {
1378 DCHECK_NE(0, num_unsafe_textures_
);
1379 --num_unsafe_textures_
;
1381 num_uncleared_mips_
-= texture
->num_uncleared_mips();
1382 DCHECK_GE(num_uncleared_mips_
, 0);
1385 MemoryTypeTracker
* TextureManager::GetMemTracker(GLenum tracking_pool
) {
1386 switch (tracking_pool
) {
1387 case GL_TEXTURE_POOL_MANAGED_CHROMIUM
:
1388 return memory_tracker_managed_
.get();
1390 case GL_TEXTURE_POOL_UNMANAGED_CHROMIUM
:
1391 return memory_tracker_unmanaged_
.get();
1400 Texture
* TextureManager::GetTextureForServiceId(GLuint service_id
) const {
1401 // This doesn't need to be fast. It's only used during slow queries.
1402 for (TextureMap::const_iterator it
= textures_
.begin();
1403 it
!= textures_
.end(); ++it
) {
1404 Texture
* texture
= it
->second
->texture();
1405 if (texture
->service_id() == service_id
)
1411 GLsizei
TextureManager::ComputeMipMapCount(GLenum target
,
1416 case GL_TEXTURE_EXTERNAL_OES
:
1420 base::bits::Log2Floor(std::max(std::max(width
, height
), depth
));
1424 void TextureManager::SetLevelImage(
1428 gfx::GLImage
* image
) {
1430 ref
->texture()->SetLevelImage(feature_info_
.get(), target
, level
, image
);
1433 size_t TextureManager::GetSignatureSize() const {
1434 return sizeof(TextureTag
) + sizeof(TextureSignature
);
1437 void TextureManager::AddToSignature(
1441 std::string
* signature
) const {
1442 ref
->texture()->AddToSignature(feature_info_
.get(), target
, level
, signature
);
1445 void TextureManager::UpdateSafeToRenderFrom(int delta
) {
1446 num_unsafe_textures_
+= delta
;
1447 DCHECK_GE(num_unsafe_textures_
, 0);
1450 void TextureManager::UpdateUnclearedMips(int delta
) {
1451 num_uncleared_mips_
+= delta
;
1452 DCHECK_GE(num_uncleared_mips_
, 0);
1455 void TextureManager::UpdateCanRenderCondition(
1456 Texture::CanRenderCondition old_condition
,
1457 Texture::CanRenderCondition new_condition
) {
1458 if (old_condition
== Texture::CAN_RENDER_NEVER
||
1459 (old_condition
== Texture::CAN_RENDER_ONLY_IF_NPOT
&&
1460 !feature_info_
->feature_flags().npot_ok
)) {
1461 DCHECK_GT(num_unrenderable_textures_
, 0);
1462 --num_unrenderable_textures_
;
1464 if (new_condition
== Texture::CAN_RENDER_NEVER
||
1465 (new_condition
== Texture::CAN_RENDER_ONLY_IF_NPOT
&&
1466 !feature_info_
->feature_flags().npot_ok
))
1467 ++num_unrenderable_textures_
;
1470 void TextureManager::UpdateNumImages(int delta
) {
1471 num_images_
+= delta
;
1472 DCHECK_GE(num_images_
, 0);
1475 void TextureManager::IncFramebufferStateChangeCount() {
1476 if (framebuffer_manager_
)
1477 framebuffer_manager_
->IncFramebufferStateChangeCount();
1480 bool TextureManager::ValidateFormatAndTypeCombination(
1481 ErrorState
* error_state
, const char* function_name
, GLenum format
,
1483 if (!feature_info_
->GetTextureFormatValidator(format
).IsValid(type
)) {
1484 ERRORSTATE_SET_GL_ERROR(
1485 error_state
, GL_INVALID_OPERATION
, function_name
,
1486 (std::string("invalid type ") +
1487 GLES2Util::GetStringEnum(type
) + " for format " +
1488 GLES2Util::GetStringEnum(format
)).c_str());
1494 bool TextureManager::ValidateTextureParameters(
1495 ErrorState
* error_state
, const char* function_name
,
1496 GLenum format
, GLenum type
, GLenum internal_format
, GLint level
) {
1497 const Validators
* validators
= feature_info_
->validators();
1498 if (!validators
->texture_format
.IsValid(format
)) {
1499 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1500 error_state
, function_name
, format
, "format");
1503 if (!validators
->pixel_type
.IsValid(type
)) {
1504 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1505 error_state
, function_name
, type
, "type");
1508 if (format
!= internal_format
&&
1509 !((internal_format
== GL_RGBA32F
&& format
== GL_RGBA
) ||
1510 (internal_format
== GL_RGB32F
&& format
== GL_RGB
))) {
1511 ERRORSTATE_SET_GL_ERROR(
1512 error_state
, GL_INVALID_OPERATION
, function_name
,
1513 "format != internalformat");
1516 uint32 channels
= GLES2Util::GetChannelsForFormat(format
);
1517 if ((channels
& (GLES2Util::kDepth
| GLES2Util::kStencil
)) != 0 && level
) {
1518 ERRORSTATE_SET_GL_ERROR(
1519 error_state
, GL_INVALID_OPERATION
, function_name
,
1520 (std::string("invalid format ") + GLES2Util::GetStringEnum(format
) +
1521 " for level != 0").c_str());
1524 return ValidateFormatAndTypeCombination(error_state
, function_name
,
1528 // Gets the texture id for a given target.
1529 TextureRef
* TextureManager::GetTextureInfoForTarget(
1530 ContextState
* state
, GLenum target
) {
1531 TextureUnit
& unit
= state
->texture_units
[state
->active_texture_unit
];
1532 TextureRef
* texture
= NULL
;
1535 texture
= unit
.bound_texture_2d
.get();
1537 case GL_TEXTURE_CUBE_MAP
:
1538 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
1539 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
1540 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
1541 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
1542 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
1543 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
1544 texture
= unit
.bound_texture_cube_map
.get();
1546 case GL_TEXTURE_EXTERNAL_OES
:
1547 texture
= unit
.bound_texture_external_oes
.get();
1549 case GL_TEXTURE_RECTANGLE_ARB
:
1550 texture
= unit
.bound_texture_rectangle_arb
.get();
1559 TextureRef
* TextureManager::GetTextureInfoForTargetUnlessDefault(
1560 ContextState
* state
, GLenum target
) {
1561 TextureRef
* texture
= GetTextureInfoForTarget(state
, target
);
1564 if (texture
== GetDefaultTextureInfo(target
))
1569 bool TextureManager::ValidateTexImage2D(
1570 ContextState
* state
,
1571 const char* function_name
,
1572 const DoTextImage2DArguments
& args
,
1573 TextureRef
** texture_ref
) {
1574 ErrorState
* error_state
= state
->GetErrorState();
1575 const Validators
* validators
= feature_info_
->validators();
1576 if (!validators
->texture_target
.IsValid(args
.target
)) {
1577 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1578 error_state
, function_name
, args
.target
, "target");
1581 if (!validators
->texture_internal_format
.IsValid(args
.internal_format
)) {
1582 ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
1583 error_state
, function_name
, args
.internal_format
,
1587 if (!ValidateTextureParameters(
1588 error_state
, function_name
, args
.format
, args
.type
,
1589 args
.internal_format
, args
.level
)) {
1592 if (!ValidForTarget(args
.target
, args
.level
, args
.width
, args
.height
, 1) ||
1594 ERRORSTATE_SET_GL_ERROR(
1595 error_state
, GL_INVALID_VALUE
, function_name
,
1596 "dimensions out of range");
1599 if ((GLES2Util::GetChannelsForFormat(args
.format
) &
1600 (GLES2Util::kDepth
| GLES2Util::kStencil
)) != 0 && args
.pixels
) {
1601 ERRORSTATE_SET_GL_ERROR(
1602 error_state
, GL_INVALID_OPERATION
,
1603 function_name
, "can not supply data for depth or stencil textures");
1607 TextureRef
* local_texture_ref
= GetTextureInfoForTarget(state
, args
.target
);
1608 if (!local_texture_ref
) {
1609 ERRORSTATE_SET_GL_ERROR(
1610 error_state
, GL_INVALID_OPERATION
, function_name
,
1611 "unknown texture for target");
1614 if (local_texture_ref
->texture()->IsImmutable()) {
1615 ERRORSTATE_SET_GL_ERROR(
1616 error_state
, GL_INVALID_OPERATION
, function_name
,
1617 "texture is immutable");
1621 if (!memory_tracker_managed_
->EnsureGPUMemoryAvailable(args
.pixels_size
)) {
1622 ERRORSTATE_SET_GL_ERROR(error_state
, GL_OUT_OF_MEMORY
, function_name
,
1627 // Write the TextureReference since this is valid.
1628 *texture_ref
= local_texture_ref
;
1632 void TextureManager::ValidateAndDoTexImage2D(
1633 DecoderTextureState
* texture_state
,
1634 ContextState
* state
,
1635 DecoderFramebufferState
* framebuffer_state
,
1636 const DoTextImage2DArguments
& args
) {
1637 TextureRef
* texture_ref
;
1638 if (!ValidateTexImage2D(state
, "glTexImage2D", args
, &texture_ref
)) {
1642 DoTexImage2D(texture_state
, state
->GetErrorState(), framebuffer_state
,
1646 GLenum
TextureManager::AdjustTexFormat(GLenum format
) const {
1647 // TODO(bajones): GLES 3 allows for internal format and format to differ.
1648 // This logic may need to change as a result.
1649 if (gfx::GetGLImplementation() == gfx::kGLImplementationDesktopGL
) {
1650 if (format
== GL_SRGB_EXT
)
1652 if (format
== GL_SRGB_ALPHA_EXT
)
1658 void TextureManager::DoTexImage2D(
1659 DecoderTextureState
* texture_state
,
1660 ErrorState
* error_state
,
1661 DecoderFramebufferState
* framebuffer_state
,
1662 TextureRef
* texture_ref
,
1663 const DoTextImage2DArguments
& args
) {
1664 Texture
* texture
= texture_ref
->texture();
1665 GLsizei tex_width
= 0;
1666 GLsizei tex_height
= 0;
1667 GLenum tex_type
= 0;
1668 GLenum tex_format
= 0;
1669 bool level_is_same
=
1670 texture
->GetLevelSize(args
.target
, args
.level
, &tex_width
, &tex_height
) &&
1671 texture
->GetLevelType(args
.target
, args
.level
, &tex_type
, &tex_format
) &&
1672 args
.width
== tex_width
&& args
.height
== tex_height
&&
1673 args
.type
== tex_type
&& args
.format
== tex_format
;
1675 if (level_is_same
&& !args
.pixels
) {
1676 // Just set the level texture but mark the texture as uncleared.
1679 args
.target
, args
.level
, args
.internal_format
, args
.width
, args
.height
,
1680 1, args
.border
, args
.format
, args
.type
, false);
1681 texture_state
->tex_image_2d_failed
= false;
1685 if (texture
->IsAttachedToFramebuffer()) {
1686 framebuffer_state
->clear_state_dirty
= true;
1689 if (texture_state
->texsubimage2d_faster_than_teximage2d
&&
1690 level_is_same
&& args
.pixels
) {
1692 ScopedTextureUploadTimer
timer(texture_state
);
1693 glTexSubImage2D(args
.target
, args
.level
, 0, 0, args
.width
, args
.height
,
1694 AdjustTexFormat(args
.format
), args
.type
, args
.pixels
);
1696 SetLevelCleared(texture_ref
, args
.target
, args
.level
, true);
1697 texture_state
->tex_image_2d_failed
= false;
1701 ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state
, "glTexImage2D");
1703 ScopedTextureUploadTimer
timer(texture_state
);
1705 args
.target
, args
.level
, args
.internal_format
, args
.width
, args
.height
,
1706 args
.border
, AdjustTexFormat(args
.format
), args
.type
, args
.pixels
);
1708 GLenum error
= ERRORSTATE_PEEK_GL_ERROR(error_state
, "glTexImage2D");
1709 if (error
== GL_NO_ERROR
) {
1712 args
.target
, args
.level
, args
.internal_format
, args
.width
, args
.height
,
1713 1, args
.border
, args
.format
, args
.type
, args
.pixels
!= NULL
);
1714 texture_state
->tex_image_2d_failed
= false;
1718 ScopedTextureUploadTimer::ScopedTextureUploadTimer(
1719 DecoderTextureState
* texture_state
)
1720 : texture_state_(texture_state
),
1721 begin_time_(base::TimeTicks::Now()) {
1724 ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
1725 texture_state_
->texture_upload_count
++;
1726 texture_state_
->total_texture_upload_time
+=
1727 base::TimeTicks::Now() - begin_time_
;
1730 } // namespace gles2