Index: gpu/command_buffer/service/texture_manager.cc |
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc |
index 329a1f8568f1402a56000d8fe287ee7a9e321298..e5ace9f8b912c91606779728ec16485269ecc4a7 100644 |
--- a/gpu/command_buffer/service/texture_manager.cc |
+++ b/gpu/command_buffer/service/texture_manager.cc |
@@ -118,14 +118,15 @@ bool TextureManager::TextureInfo::MarkMipmapsGenerated( |
GLsizei width = info1.width; |
GLsizei height = info1.height; |
GLsizei depth = info1.depth; |
+ GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D : |
+ FaceIndexToGLTarget(ii); |
int num_mips = ComputeMipMapCount(width, height, depth); |
for (int level = 1; level < num_mips; ++level) { |
width = std::max(1, width >> 1); |
height = std::max(1, height >> 1); |
depth = std::max(1, depth >> 1); |
SetLevelInfo(feature_info, |
- target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D : |
- FaceIndexToGLTarget(ii), |
+ target, |
level, |
info1.internal_format, |
width, |
@@ -133,9 +134,11 @@ bool TextureManager::TextureInfo::MarkMipmapsGenerated( |
depth, |
info1.border, |
info1.format, |
- info1.type); |
+ info1.type, |
+ true); |
} |
} |
+ |
return true; |
} |
@@ -165,7 +168,7 @@ bool TextureManager::TextureInfo::CanGenerateMipmaps( |
// TODO(gman): Check internal_format, format and type. |
for (size_t ii = 0; ii < level_infos_.size(); ++ii) { |
const LevelInfo& info = level_infos_[ii][0]; |
- if ((!info.valid) || |
+ if ((info.target == 0) || |
(info.width != first.width) || |
(info.height != first.height) || |
(info.depth != 1) || |
@@ -178,6 +181,43 @@ bool TextureManager::TextureInfo::CanGenerateMipmaps( |
return true; |
} |
+void TextureManager::TextureInfo::SetLevelCleared(GLenum target, GLint level) { |
+ DCHECK_GE(level, 0); |
+ DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)), |
+ level_infos_.size()); |
+ DCHECK_LT(static_cast<size_t>(level), |
+ level_infos_[GLTargetToFaceIndex(target)].size()); |
+ TextureInfo::LevelInfo& info = |
+ level_infos_[GLTargetToFaceIndex(target)][level]; |
+ if (!info.cleared) { |
+ DCHECK_NE(0, num_uncleared_mips_); |
+ --num_uncleared_mips_; |
+ } |
+ info.cleared = true; |
+ UpdateCleared(); |
+} |
+ |
+void TextureManager::TextureInfo::UpdateCleared() { |
+ if (level_infos_.empty()) { |
+ return; |
+ } |
+ |
+ const TextureInfo::LevelInfo& first_face = level_infos_[0][0]; |
+ int levels_needed = ComputeMipMapCount( |
+ first_face.width, first_face.height, first_face.depth); |
+ cleared_ = true; |
+ for (size_t ii = 0; ii < level_infos_.size(); ++ii) { |
+ for (GLint jj = 0; jj < levels_needed; ++jj) { |
+ const TextureInfo::LevelInfo& info = level_infos_[ii][jj]; |
+ if (info.width > 0 && info.height > 0 && info.depth > 0 && |
+ !info.cleared) { |
+ cleared_ = false; |
+ return; |
+ } |
+ } |
+ } |
+} |
+ |
void TextureManager::TextureInfo::SetLevelInfo( |
const FeatureInfo* feature_info, |
GLenum target, |
@@ -188,7 +228,8 @@ void TextureManager::TextureInfo::SetLevelInfo( |
GLsizei depth, |
GLint border, |
GLenum format, |
- GLenum type) { |
+ GLenum type, |
+ bool cleared) { |
DCHECK_GE(level, 0); |
DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)), |
level_infos_.size()); |
@@ -199,7 +240,8 @@ void TextureManager::TextureInfo::SetLevelInfo( |
DCHECK_GE(depth, 0); |
TextureInfo::LevelInfo& info = |
level_infos_[GLTargetToFaceIndex(target)][level]; |
- info.valid = true; |
+ info.target = target; |
+ info.level = level; |
info.internal_format = internal_format; |
info.width = width; |
info.height = height; |
@@ -207,8 +249,17 @@ void TextureManager::TextureInfo::SetLevelInfo( |
info.border = border; |
info.format = format; |
info.type = type; |
+ if (!info.cleared) { |
+ DCHECK_NE(0, num_uncleared_mips_); |
+ --num_uncleared_mips_; |
+ } |
+ info.cleared = cleared; |
+ if (!info.cleared) { |
+ ++num_uncleared_mips_; |
+ } |
max_level_set_ = std::max(max_level_set_, level); |
Update(feature_info); |
+ UpdateCleared(); |
} |
bool TextureManager::TextureInfo::ValidForTexture( |
@@ -246,7 +297,7 @@ bool TextureManager::TextureInfo::GetLevelSize( |
if (!IsDeleted() && level >= 0 && face_index < level_infos_.size() && |
static_cast<size_t>(level) < level_infos_[face_index].size()) { |
const LevelInfo& info = level_infos_[GLTargetToFaceIndex(face)][level]; |
- if (info.valid) { |
+ if (info.target != 0) { |
*width = info.width; |
*height = info.height; |
return true; |
@@ -263,7 +314,7 @@ bool TextureManager::TextureInfo::GetLevelType( |
if (!IsDeleted() && level >= 0 && face_index < level_infos_.size() && |
static_cast<size_t>(level) < level_infos_[face_index].size()) { |
const LevelInfo& info = level_infos_[GLTargetToFaceIndex(face)][level]; |
- if (info.valid) { |
+ if (info.target != 0) { |
*type = info.type; |
*internal_format = info.internal_format; |
return true; |
@@ -318,6 +369,7 @@ bool TextureManager::TextureInfo::SetParameter( |
return false; |
} |
Update(feature_info); |
+ UpdateCleared(); |
return true; |
} |
@@ -331,6 +383,7 @@ void TextureManager::TextureInfo::Update(const FeatureInfo* feature_info) { |
return; |
} |
+ // checks that the first mip of any face is npot. |
for (size_t ii = 0; ii < level_infos_.size(); ++ii) { |
const TextureInfo::LevelInfo& info = level_infos_[ii][0]; |
if (GLES2Util::IsNPOT(info.width) || |
@@ -367,7 +420,7 @@ void TextureManager::TextureInfo::Update(const FeatureInfo* feature_info) { |
ii < level_infos_.size() && (cube_complete_ || texture_complete_); |
++ii) { |
const TextureInfo::LevelInfo& level0 = level_infos_[ii][0]; |
- if (!level0.valid || |
+ if (level0.target == 0 || |
level0.width != first_face.width || |
level0.height != first_face.height || |
level0.depth != 1 || |
@@ -386,7 +439,7 @@ void TextureManager::TextureInfo::Update(const FeatureInfo* feature_info) { |
height = std::max(1, height >> 1); |
depth = std::max(1, depth >> 1); |
const TextureInfo::LevelInfo& info = level_infos_[ii][jj]; |
- if (!info.valid || |
+ if (info.target == 0 || |
info.width != width || |
info.height != height || |
info.depth != depth || |
@@ -400,6 +453,80 @@ void TextureManager::TextureInfo::Update(const FeatureInfo* feature_info) { |
} |
} |
+bool TextureManager::TextureInfo::ClearRenderableLevels(GLES2Decoder* decoder) { |
+ DCHECK(decoder); |
+ if (SafeToRenderFrom()) { |
+ return true; |
+ } |
+ |
+ const TextureInfo::LevelInfo& first_face = level_infos_[0][0]; |
+ int levels_needed = ComputeMipMapCount( |
+ first_face.width, first_face.height, first_face.depth); |
+ |
+ for (size_t ii = 0; ii < level_infos_.size(); ++ii) { |
+ for (GLint jj = 0; jj < levels_needed; ++jj) { |
+ TextureInfo::LevelInfo& info = level_infos_[ii][jj]; |
+ if (info.target != 0) { |
+ if (!ClearLevel(decoder, info.target, jj)) { |
+ return false; |
+ } |
+ } |
+ } |
+ } |
+ cleared_ = true; |
+ return true; |
+} |
+ |
+bool TextureManager::TextureInfo::IsLevelCleared(GLenum target, GLint level) { |
+ size_t face_index = GLTargetToFaceIndex(target); |
+ if (IsDeleted() || |
+ face_index >= level_infos_.size() || |
+ level >= static_cast<GLint>(level_infos_[face_index].size())) { |
+ return true; |
+ } |
+ |
+ TextureInfo::LevelInfo& info = level_infos_[face_index][level]; |
+ |
+ return info.cleared; |
+} |
+ |
+bool TextureManager::TextureInfo::ClearLevel( |
+ GLES2Decoder* decoder, GLenum target, GLint level) { |
+ DCHECK(decoder); |
+ size_t face_index = GLTargetToFaceIndex(target); |
+ if (IsDeleted() || |
+ face_index >= level_infos_.size() || |
+ level >= static_cast<GLint>(level_infos_[face_index].size())) { |
+ return true; |
+ } |
+ |
+ TextureInfo::LevelInfo& info = level_infos_[face_index][level]; |
+ |
+ DCHECK(target == info.target); |
+ |
+ if (info.target == 0 || |
+ info.cleared || |
+ info.width == 0 || |
+ info.height == 0 || |
+ info.depth == 0) { |
+ return true; |
+ } |
+ |
+ DCHECK_NE(0, num_uncleared_mips_); |
+ --num_uncleared_mips_; |
+ |
+ // NOTE: It seems kind of gross to call back into the decoder for this |
+ // but only the decoder knows all the state (like unpack_alignment_) that's |
+ // needed to be able to call GL correctly. |
+ info.cleared = decoder->ClearLevel( |
+ service_id_, target_, info.target, info.level, info.format, info.type, |
+ info.width, info.height); |
+ if (!info.cleared) { |
+ ++num_uncleared_mips_; |
+ } |
+ return info.cleared; |
+} |
+ |
TextureManager::TextureManager( |
GLint max_texture_size, |
GLint max_cube_map_texture_size) |
@@ -412,6 +539,8 @@ TextureManager::TextureManager( |
max_cube_map_texture_size, |
max_cube_map_texture_size)), |
num_unrenderable_textures_(0), |
+ num_unsafe_textures_(0), |
+ num_uncleared_mips_(0), |
black_2d_texture_id_(0), |
black_cube_texture_id_(0) { |
} |
@@ -439,23 +568,30 @@ bool TextureManager::Initialize(const FeatureInfo* feature_info) { |
glBindTexture(GL_TEXTURE_2D, 0); |
glBindTexture(GL_TEXTURE_CUBE_MAP, 0); |
+ // Since we are manually setting up these textures |
+ // we need to manually manipulate some of the their bookkeeping. |
+ num_unrenderable_textures_ += 2; |
FeatureInfo temp_feature_info; |
default_texture_2d_ = TextureInfo::Ref(new TextureInfo(ids[1])); |
SetInfoTarget(feature_info, default_texture_2d_, GL_TEXTURE_2D); |
- default_texture_2d_->SetLevelInfo(&temp_feature_info, |
- GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE); |
+ SetLevelInfo(&temp_feature_info, default_texture_2d_, |
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true); |
default_texture_cube_map_ = TextureInfo::Ref(new TextureInfo(ids[3])); |
SetInfoTarget(feature_info, default_texture_cube_map_, GL_TEXTURE_CUBE_MAP); |
for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) { |
- default_texture_cube_map_->SetLevelInfo( |
- &temp_feature_info, GLES2Util::IndexToGLFaceTarget(ii), |
- 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE); |
+ SetLevelInfo( |
+ &temp_feature_info, default_texture_cube_map_, |
+ GLES2Util::IndexToGLFaceTarget(ii), |
+ 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true); |
} |
black_2d_texture_id_ = ids[0]; |
black_cube_texture_id_ = ids[2]; |
if (feature_info->feature_flags().oes_egl_image_external) { |
+ // Since we are manually setting up these textures |
+ // we need to manually manipulate some of the their bookkeeping. |
+ num_unrenderable_textures_ += 1; |
GLuint external_ids[2]; |
glGenTextures(arraysize(external_ids), external_ids); |
glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); |
@@ -466,7 +602,7 @@ bool TextureManager::Initialize(const FeatureInfo* feature_info) { |
GL_TEXTURE_EXTERNAL_OES); |
default_texture_external_oes_->SetLevelInfo( |
&temp_feature_info, GL_TEXTURE_EXTERNAL_OES, 0, |
- GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE); |
+ GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true); |
// Sampling a texture not associated with any EGLImage sibling will return |
// black values according to the spec. |
@@ -499,9 +635,10 @@ bool TextureManager::ValidForTarget( |
void TextureManager::SetInfoTarget( |
const FeatureInfo* feature_info, |
- TextureInfo* info, GLenum target) { |
+ TextureManager::TextureInfo* info, GLenum target) { |
DCHECK(info); |
if (!info->CanRender(feature_info)) { |
+ DCHECK_NE(0, num_unrenderable_textures_); |
--num_unrenderable_textures_; |
} |
info->SetTarget(target, MaxLevelsForTarget(target)); |
@@ -510,6 +647,65 @@ void TextureManager::SetInfoTarget( |
} |
} |
+void TextureManager::SetLevelCleared( |
+ TextureManager::TextureInfo* info, GLenum target, GLint level) { |
+ DCHECK(info); |
+ DCHECK(!info->IsDeleted()); |
+ if (!info->SafeToRenderFrom()) { |
+ DCHECK_NE(0, num_unsafe_textures_); |
+ --num_unsafe_textures_; |
+ } |
+ num_uncleared_mips_ -= info->num_uncleared_mips(); |
+ DCHECK_GE(num_uncleared_mips_, 0); |
+ info->SetLevelCleared(target, level); |
+ num_uncleared_mips_ += info->num_uncleared_mips(); |
+ if (!info->SafeToRenderFrom()) { |
+ ++num_unsafe_textures_; |
+ } |
+} |
+ |
+bool TextureManager::ClearRenderableLevels( |
+ GLES2Decoder* decoder,TextureManager::TextureInfo* info) { |
+ DCHECK(info); |
+ DCHECK(!info->IsDeleted()); |
+ if (info->SafeToRenderFrom()) { |
+ return true; |
+ } |
+ DCHECK_NE(0, num_unsafe_textures_); |
+ --num_unsafe_textures_; |
+ num_uncleared_mips_ -= info->num_uncleared_mips(); |
+ DCHECK_GE(num_uncleared_mips_, 0); |
+ bool result = info->ClearRenderableLevels(decoder); |
+ num_uncleared_mips_ += info->num_uncleared_mips(); |
+ if (!info->SafeToRenderFrom()) { |
+ ++num_unsafe_textures_; |
+ } |
+ return result; |
+} |
+ |
+bool TextureManager::ClearTextureLevel( |
+ GLES2Decoder* decoder,TextureManager::TextureInfo* info, |
+ GLenum target, GLint level) { |
+ DCHECK(info); |
+ DCHECK(!info->IsDeleted()); |
+ if (info->num_uncleared_mips() == 0) { |
+ return true; |
+ } |
+ num_uncleared_mips_ -= info->num_uncleared_mips(); |
+ DCHECK_GE(num_uncleared_mips_, 0); |
+ if (!info->SafeToRenderFrom()) { |
+ DCHECK_NE(0, num_unsafe_textures_); |
+ --num_unsafe_textures_; |
+ } |
+ bool result = info->ClearLevel(decoder, target, level); |
+ info->UpdateCleared(); |
+ num_uncleared_mips_ += info->num_uncleared_mips(); |
+ if (!info->SafeToRenderFrom()) { |
+ ++num_unsafe_textures_; |
+ } |
+ return result; |
+} |
+ |
void TextureManager::SetLevelInfo( |
const FeatureInfo* feature_info, |
TextureManager::TextureInfo* info, |
@@ -521,18 +717,30 @@ void TextureManager::SetLevelInfo( |
GLsizei depth, |
GLint border, |
GLenum format, |
- GLenum type) { |
+ GLenum type, |
+ bool cleared) { |
DCHECK(info); |
DCHECK(!info->IsDeleted()); |
if (!info->CanRender(feature_info)) { |
+ DCHECK_NE(0, num_unrenderable_textures_); |
--num_unrenderable_textures_; |
} |
+ if (!info->SafeToRenderFrom()) { |
+ DCHECK_NE(0, num_unsafe_textures_); |
+ --num_unsafe_textures_; |
+ } |
+ num_uncleared_mips_ -= info->num_uncleared_mips(); |
+ DCHECK_GE(num_uncleared_mips_, 0); |
info->SetLevelInfo( |
feature_info, target, level, internal_format, width, height, depth, |
- border, format, type); |
+ border, format, type, cleared); |
+ num_uncleared_mips_ += info->num_uncleared_mips(); |
if (!info->CanRender(feature_info)) { |
++num_unrenderable_textures_; |
} |
+ if (!info->SafeToRenderFrom()) { |
+ ++num_unsafe_textures_; |
+ } |
} |
bool TextureManager::SetParameter( |
@@ -542,12 +750,20 @@ bool TextureManager::SetParameter( |
DCHECK(info); |
DCHECK(!info->IsDeleted()); |
if (!info->CanRender(feature_info)) { |
+ DCHECK_NE(0, num_unrenderable_textures_); |
--num_unrenderable_textures_; |
} |
+ if (!info->SafeToRenderFrom()) { |
+ DCHECK_NE(0, num_unsafe_textures_); |
+ --num_unsafe_textures_; |
+ } |
bool result = info->SetParameter(feature_info, pname, param); |
if (!info->CanRender(feature_info)) { |
++num_unrenderable_textures_; |
} |
+ if (!info->SafeToRenderFrom()) { |
+ ++num_unsafe_textures_; |
+ } |
return result; |
} |
@@ -557,12 +773,23 @@ bool TextureManager::MarkMipmapsGenerated( |
DCHECK(info); |
DCHECK(!info->IsDeleted()); |
if (!info->CanRender(feature_info)) { |
+ DCHECK_NE(0, num_unrenderable_textures_); |
--num_unrenderable_textures_; |
} |
+ if (!info->SafeToRenderFrom()) { |
+ DCHECK_NE(0, num_unsafe_textures_); |
+ --num_unsafe_textures_; |
+ } |
+ num_uncleared_mips_ -= info->num_uncleared_mips(); |
+ DCHECK_GE(num_uncleared_mips_, 0); |
bool result = info->MarkMipmapsGenerated(feature_info); |
+ num_uncleared_mips_ += info->num_uncleared_mips(); |
if (!info->CanRender(feature_info)) { |
++num_unrenderable_textures_; |
} |
+ if (!info->SafeToRenderFrom()) { |
+ ++num_unsafe_textures_; |
+ } |
return result; |
} |
@@ -576,6 +803,10 @@ TextureManager::TextureInfo* TextureManager::CreateTextureInfo( |
if (!info->CanRender(feature_info)) { |
++num_unrenderable_textures_; |
} |
+ if (!info->SafeToRenderFrom()) { |
+ ++num_unsafe_textures_; |
+ } |
+ num_uncleared_mips_ += info->num_uncleared_mips(); |
return info.get(); |
} |
@@ -591,8 +822,15 @@ void TextureManager::RemoveTextureInfo( |
if (it != texture_infos_.end()) { |
TextureInfo* info = it->second; |
if (!info->CanRender(feature_info)) { |
+ DCHECK_NE(0, num_unrenderable_textures_); |
--num_unrenderable_textures_; |
} |
+ if (!info->SafeToRenderFrom()) { |
+ DCHECK_NE(0, num_unsafe_textures_); |
+ --num_unsafe_textures_; |
+ } |
+ num_uncleared_mips_ -= info->num_uncleared_mips(); |
+ DCHECK_GE(num_uncleared_mips_, 0); |
info->MarkAsDeleted(); |
texture_infos_.erase(it); |
} |