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 acc63d779c8f0ee8bf5868015d09ddbb2ee5a416..08fe659d6fa4cbf1e92aa87f1f3de53b2c012c7a 100644 |
--- a/gpu/command_buffer/service/texture_manager.cc |
+++ b/gpu/command_buffer/service/texture_manager.cc |
@@ -128,6 +128,9 @@ Texture::Texture(GLuint service_id) |
service_id_(service_id), |
cleared_(true), |
num_uncleared_mips_(0), |
+ num_npot_faces_(0), |
+ num_complete_faces_(0), |
+ num_incomplete_mips_(0), |
target_(0), |
min_filter_(GL_NEAREST_MIPMAP_LINEAR), |
mag_filter_(GL_LINEAR), |
@@ -329,8 +332,8 @@ bool Texture::MarkMipmapsGenerated( |
GLsizei depth = info1.depth; |
GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D : |
GLES2Util::IndexToGLFaceTarget(ii); |
- int num_mips = |
- TextureManager::ComputeMipMapCount(target_, width, height, depth); |
+ |
+ const int num_mips = num_mip_levels_[ii]; |
for (int level = 1; level < num_mips; ++level) { |
width = std::max(1, width >> 1); |
height = std::max(1, height >> 1); |
@@ -361,6 +364,7 @@ void Texture::SetTarget( |
for (size_t ii = 0; ii < num_faces; ++ii) { |
level_infos_[ii].resize(max_levels); |
} |
+ num_mip_levels_.resize(num_faces); |
if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) { |
min_filter_ = GL_LINEAR; |
@@ -407,6 +411,59 @@ bool Texture::CanGenerateMipmaps( |
return true; |
} |
+bool Texture::TextureIsNPOT(GLsizei width, |
+ GLsizei height, |
+ GLsizei depth) { |
+ return (GLES2Util::IsNPOT(width) || |
+ GLES2Util::IsNPOT(height) || |
+ GLES2Util::IsNPOT(depth)); |
+} |
+ |
+bool Texture::TextureFaceComplete(const Texture::LevelInfo& first_face, |
+ size_t face_index, |
+ GLenum target, |
+ GLenum internal_format, |
+ GLsizei width, |
+ GLsizei height, |
+ GLsizei depth, |
+ GLenum format, |
+ GLenum type) { |
+ bool complete = (target != 0 && depth == 1); |
+ if (face_index != 0) { |
+ complete &= (width == first_face.width && |
+ height == first_face.height && |
+ internal_format == first_face.internal_format && |
+ format == first_face.format && |
+ type == first_face.type); |
+ } |
+ return complete; |
+} |
+ |
+bool Texture::TextureMipComplete(const Texture::LevelInfo& level0_face, |
+ GLenum target, |
+ GLint level, |
+ GLenum internal_format, |
+ GLsizei width, |
+ GLsizei height, |
+ GLsizei depth, |
+ GLenum format, |
+ GLenum type) { |
+ bool complete = (target != 0); |
+ if (level != 0) { |
+ const GLsizei mip_width = std::max(1, level0_face.width >> level); |
+ const GLsizei mip_height = std::max(1, level0_face.height >> level); |
+ const GLsizei mip_depth = std::max(1, level0_face.depth >> level); |
vmiura
2014/10/07 00:13:03
Do we need to handle the case of width/height/dept
David Yen
2014/10/09 20:20:16
That check is already done before this function is
|
+ |
+ complete &= (width == mip_width && |
+ height == mip_height && |
+ depth == mip_depth && |
+ internal_format == level0_face.internal_format && |
+ format == level0_face.format && |
+ type == level0_face.type); |
+ } |
+ return complete; |
+} |
+ |
void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) { |
DCHECK_GE(level, 0); |
size_t face_index = GLES2Util::GLTargetToFaceIndex(target); |
@@ -516,6 +573,89 @@ void Texture::SetLevelInfo( |
DCHECK_GE(depth, 0); |
Texture::LevelInfo& info = |
level_infos_[face_index][level]; |
+ |
+ // Update counters only if any attributes have changed. Counters are |
+ // comparisons between the old and new values so it must be done before any |
+ // assignment has been done to the LevelInfo. |
+ if (info.target != target || |
+ info.internal_format != internal_format || |
+ info.width != width || |
+ info.height != height || |
+ info.depth != depth || |
+ info.format != format || |
+ info.type != type) { |
+ if (level == 0) { |
+ // Calculate the mip level count. |
+ num_mip_levels_[face_index] = TextureManager::ComputeMipMapCount( |
+ target_, width, height, depth); |
+ |
+ // Update NPOT face count for the first level. |
+ bool prev_npot = TextureIsNPOT(info.width, info.height, info.depth); |
+ bool now_npot = TextureIsNPOT(width, height, depth); |
+ if (prev_npot != now_npot) |
+ num_npot_faces_ += now_npot ? 1 : -1; |
+ |
+ // Update number of complete faces. |
+ const Texture::LevelInfo& first_face = level_infos_[0][0]; |
+ for (size_t i = face_index; i < level_infos_.size(); ++i) { |
vmiura
2014/10/07 00:13:03
I think this compares face 0 to itself, so I think
David Yen
2014/10/09 20:20:16
No longer relevant, using dirty bit now.
|
+ bool prev_face_status = TextureFaceComplete(first_face, |
+ face_index, |
+ info.target, |
+ info.internal_format, |
+ info.width, |
+ info.height, |
+ info.depth, |
+ info.format, |
+ info.type); |
+ bool new_face_status = TextureFaceComplete(first_face, |
+ face_index, |
+ target, |
+ internal_format, |
+ width, |
+ height, |
+ depth, |
+ format, |
+ type); |
+ if (prev_face_status != new_face_status) |
+ num_complete_faces_ += new_face_status ? 1 : -1; |
+ |
+ // Only need to validate all faces if the first face is changing. |
+ if (face_index != 0) |
+ break; |
+ } |
+ } |
+ |
+ // Update incomplete mip counter. |
+ const Texture::LevelInfo& level0_face = level_infos_[face_index][0]; |
+ const GLsizei num_mip_levels = num_mip_levels_[face_index]; |
vmiura
2014/10/07 00:13:03
If num_mip_levels changes, for example decreasing,
David Yen
2014/10/09 20:20:16
No longer relevant, using dirty bit now.
|
+ for (GLsizei i = static_cast<GLsizei>(level); i < num_mip_levels; ++i) { |
+ bool prev_mip_status = TextureMipComplete(level0_face, |
+ info.target, |
+ i, |
+ info.internal_format, |
+ info.width, |
+ info.height, |
+ info.depth, |
+ info.format, |
+ info.type); |
+ bool new_mip_status = TextureMipComplete(level0_face, |
+ target, |
+ i, |
+ internal_format, |
+ width, |
+ height, |
+ depth, |
+ format, |
+ type); |
+ if (prev_mip_status != new_mip_status) |
+ num_incomplete_mips_ += new_mip_status ? -1 : 1; |
vmiura
2014/10/07 00:13:03
As above, I'm not sure we will count correctly whe
David Yen
2014/10/09 20:20:16
No longer relevant, using dirty bit now.
|
+ |
+ // Only need to validate all faces if the first face is changing. |
+ if (face_index != 0) |
+ break; |
+ } |
+ } |
+ |
info.target = target; |
info.level = level; |
info.internal_format = internal_format; |
@@ -700,7 +840,7 @@ GLenum Texture::SetParameterf( |
void Texture::Update(const FeatureInfo* feature_info) { |
// Update npot status. |
// Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others |
- npot_ = target_ == GL_TEXTURE_EXTERNAL_OES; |
+ npot_ = (target_ == GL_TEXTURE_EXTERNAL_OES) || (num_npot_faces_ > 0); |
if (level_infos_.empty()) { |
texture_complete_ = false; |
@@ -708,74 +848,29 @@ void Texture::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 Texture::LevelInfo& info = level_infos_[ii][0]; |
- if (GLES2Util::IsNPOT(info.width) || |
- GLES2Util::IsNPOT(info.height) || |
- GLES2Util::IsNPOT(info.depth)) { |
- npot_ = true; |
- break; |
- } |
- } |
- |
// Update texture_complete and cube_complete status. |
const Texture::LevelInfo& first_face = level_infos_[0][0]; |
- int levels_needed = TextureManager::ComputeMipMapCount( |
- target_, first_face.width, first_face.height, first_face.depth); |
+ int levels_needed = num_mip_levels_[0]; |
texture_complete_ = |
max_level_set_ >= (levels_needed - 1) && max_level_set_ >= 0; |
cube_complete_ = (level_infos_.size() == 6) && |
- (first_face.width == first_face.height); |
+ (first_face.width == first_face.height) && |
+ (num_complete_faces_ == 6); |
if (first_face.width == 0 || first_face.height == 0) { |
texture_complete_ = false; |
- } |
- if (first_face.type == GL_FLOAT && |
- !feature_info->feature_flags().enable_texture_float_linear && |
- (min_filter_ != GL_NEAREST_MIPMAP_NEAREST || |
- mag_filter_ != GL_NEAREST)) { |
+ } else if (first_face.type == GL_FLOAT && |
+ !feature_info->feature_flags().enable_texture_float_linear && |
+ (min_filter_ != GL_NEAREST_MIPMAP_NEAREST || |
+ mag_filter_ != GL_NEAREST)) { |
texture_complete_ = false; |
} else if (first_face.type == GL_HALF_FLOAT_OES && |
!feature_info->feature_flags().enable_texture_half_float_linear && |
(min_filter_ != GL_NEAREST_MIPMAP_NEAREST || |
mag_filter_ != GL_NEAREST)) { |
texture_complete_ = false; |
- } |
- for (size_t ii = 0; |
- ii < level_infos_.size() && (cube_complete_ || texture_complete_); |
- ++ii) { |
- const Texture::LevelInfo& level0 = level_infos_[ii][0]; |
- if (level0.target == 0 || |
- level0.width != first_face.width || |
- level0.height != first_face.height || |
- level0.depth != 1 || |
- level0.internal_format != first_face.internal_format || |
- level0.format != first_face.format || |
- level0.type != first_face.type) { |
- cube_complete_ = false; |
- } |
- // Get level0 dimensions |
- GLsizei width = level0.width; |
- GLsizei height = level0.height; |
- GLsizei depth = level0.depth; |
- for (GLint jj = 1; jj < levels_needed; ++jj) { |
- // compute required size for mip. |
- width = std::max(1, width >> 1); |
- height = std::max(1, height >> 1); |
- depth = std::max(1, depth >> 1); |
- const Texture::LevelInfo& info = level_infos_[ii][jj]; |
- if (info.target == 0 || |
- info.width != width || |
- info.height != height || |
- info.depth != depth || |
- info.internal_format != level0.internal_format || |
- info.format != level0.format || |
- info.type != level0.type) { |
- texture_complete_ = false; |
- break; |
- } |
- } |
+ } else if (num_incomplete_mips_ > 0) { |
+ texture_complete_ = false; |
} |
} |
@@ -786,8 +881,7 @@ bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) { |
} |
const Texture::LevelInfo& first_face = level_infos_[0][0]; |
- int levels_needed = TextureManager::ComputeMipMapCount( |
- target_, first_face.width, first_face.height, first_face.depth); |
+ int levels_needed = num_mip_levels_[0]; |
for (size_t ii = 0; ii < level_infos_.size(); ++ii) { |
for (GLint jj = 0; jj < levels_needed; ++jj) { |