Chromium Code Reviews| 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..ceb958d680aedfdac4b1e04fdda4f3b1862b0ee3 100644 |
| --- a/gpu/command_buffer/service/texture_manager.cc |
| +++ b/gpu/command_buffer/service/texture_manager.cc |
| @@ -128,6 +128,7 @@ Texture::Texture(GLuint service_id) |
| service_id_(service_id), |
| cleared_(true), |
| num_uncleared_mips_(0), |
| + num_npot_faces_(0), |
| target_(0), |
| min_filter_(GL_NEAREST_MIPMAP_LINEAR), |
| mag_filter_(GL_LINEAR), |
| @@ -137,7 +138,9 @@ Texture::Texture(GLuint service_id) |
| pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM), |
| max_level_set_(-1), |
| texture_complete_(false), |
| + texture_mips_dirty_(false), |
| cube_complete_(false), |
| + texture_level0_dirty_(false), |
| npot_(false), |
| has_been_bound_(false), |
| framebuffer_attachment_count_(0), |
| @@ -220,16 +223,23 @@ Texture::LevelInfo::LevelInfo(const LevelInfo& rhs) |
| Texture::LevelInfo::~LevelInfo() { |
| } |
| +Texture::FaceInfo::FaceInfo() |
| + : num_mip_levels(0) { |
| +} |
| + |
| +Texture::FaceInfo::~FaceInfo() { |
| +} |
| + |
| Texture::CanRenderCondition Texture::GetCanRenderCondition() const { |
| if (target_ == 0) |
| return CAN_RENDER_ALWAYS; |
| if (target_ != GL_TEXTURE_EXTERNAL_OES) { |
| - if (level_infos_.empty()) { |
| + if (face_infos_.empty()) { |
| return CAN_RENDER_NEVER; |
| } |
| - const Texture::LevelInfo& first_face = level_infos_[0][0]; |
| + const Texture::LevelInfo& first_face = face_infos_[0].level_infos[0]; |
| if (first_face.width == 0 || |
| first_face.height == 0 || |
| first_face.depth == 0) { |
| @@ -281,12 +291,12 @@ void Texture::AddToSignature( |
| DCHECK_GE(level, 0); |
| size_t face_index = GLES2Util::GLTargetToFaceIndex(target); |
| DCHECK_LT(static_cast<size_t>(face_index), |
| - level_infos_.size()); |
| + face_infos_.size()); |
| DCHECK_LT(static_cast<size_t>(level), |
| - level_infos_[face_index].size()); |
| + face_infos_[face_index].level_infos.size()); |
| const Texture::LevelInfo& info = |
| - level_infos_[face_index][level]; |
| + face_infos_[face_index].level_infos[level]; |
| TextureSignature signature_data(target, |
| level, |
| @@ -322,29 +332,30 @@ bool Texture::MarkMipmapsGenerated( |
| if (!CanGenerateMipmaps(feature_info)) { |
| return false; |
| } |
| - for (size_t ii = 0; ii < level_infos_.size(); ++ii) { |
| - const Texture::LevelInfo& info1 = level_infos_[ii][0]; |
| - GLsizei width = info1.width; |
| - GLsizei height = info1.height; |
| - GLsizei depth = info1.depth; |
| + for (size_t ii = 0; ii < face_infos_.size(); ++ii) { |
| + const Texture::FaceInfo& face_info = face_infos_[ii]; |
| + const Texture::LevelInfo& level0_info = face_info.level_infos[0]; |
| + GLsizei width = level0_info.width; |
| + GLsizei height = level0_info.height; |
| + GLsizei depth = level0_info.depth; |
| GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D : |
| GLES2Util::IndexToGLFaceTarget(ii); |
| - int num_mips = |
| - TextureManager::ComputeMipMapCount(target_, width, height, depth); |
| - for (int level = 1; level < num_mips; ++level) { |
| + |
| + const GLsizei num_mips = face_info.num_mip_levels; |
| + for (GLsizei 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, |
| level, |
| - info1.internal_format, |
| + level0_info.internal_format, |
| width, |
| height, |
| depth, |
| - info1.border, |
| - info1.format, |
| - info1.type, |
| + level0_info.border, |
| + level0_info.format, |
| + level0_info.type, |
| true); |
| } |
| } |
| @@ -357,9 +368,9 @@ void Texture::SetTarget( |
| DCHECK_EQ(0u, target_); // you can only set this once. |
| target_ = target; |
| size_t num_faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; |
| - level_infos_.resize(num_faces); |
| + face_infos_.resize(num_faces); |
| for (size_t ii = 0; ii < num_faces; ++ii) { |
| - level_infos_[ii].resize(max_levels); |
| + face_infos_[ii].level_infos.resize(max_levels); |
| } |
| if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) { |
| @@ -377,22 +388,22 @@ void Texture::SetTarget( |
| bool Texture::CanGenerateMipmaps( |
| const FeatureInfo* feature_info) const { |
| if ((npot() && !feature_info->feature_flags().npot_ok) || |
| - level_infos_.empty() || |
| + face_infos_.empty() || |
| target_ == GL_TEXTURE_EXTERNAL_OES || |
| target_ == GL_TEXTURE_RECTANGLE_ARB) { |
| return false; |
| } |
| // Can't generate mips for depth or stencil textures. |
| - const Texture::LevelInfo& first = level_infos_[0][0]; |
| + const Texture::LevelInfo& first = face_infos_[0].level_infos[0]; |
| uint32 channels = GLES2Util::GetChannelsForFormat(first.format); |
| if (channels & (GLES2Util::kDepth | GLES2Util::kStencil)) { |
| return false; |
| } |
| // 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]; |
| + for (size_t ii = 0; ii < face_infos_.size(); ++ii) { |
| + const LevelInfo& info = face_infos_[ii].level_infos[0]; |
| if ((info.target == 0) || (info.width != first.width) || |
| (info.height != first.height) || (info.depth != 1) || |
| (info.format != first.format) || |
| @@ -407,21 +418,74 @@ 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); |
| + |
| + 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); |
| DCHECK_LT(static_cast<size_t>(face_index), |
| - level_infos_.size()); |
| + face_infos_.size()); |
| DCHECK_LT(static_cast<size_t>(level), |
| - level_infos_[face_index].size()); |
| + face_infos_[face_index].level_infos.size()); |
| Texture::LevelInfo& info = |
| - level_infos_[face_index][level]; |
| + face_infos_[face_index].level_infos[level]; |
| UpdateMipCleared(&info, cleared); |
| UpdateCleared(); |
| } |
| void Texture::UpdateCleared() { |
| - if (level_infos_.empty()) { |
| + if (face_infos_.empty()) { |
| return; |
| } |
| @@ -466,13 +530,13 @@ void Texture::UpdateCanRenderCondition() { |
| } |
| void Texture::UpdateHasImages() { |
| - if (level_infos_.empty()) |
| + if (face_infos_.empty()) |
| return; |
| bool has_images = false; |
| - for (size_t ii = 0; ii < level_infos_.size(); ++ii) { |
| - for (size_t jj = 0; jj < level_infos_[ii].size(); ++jj) { |
| - const Texture::LevelInfo& info = level_infos_[ii][jj]; |
| + for (size_t ii = 0; ii < face_infos_.size(); ++ii) { |
| + for (size_t jj = 0; jj < face_infos_[ii].level_infos.size(); ++jj) { |
| + const Texture::LevelInfo& info = face_infos_[ii].level_infos[jj]; |
| if (info.image.get() != NULL) { |
| has_images = true; |
| break; |
| @@ -508,14 +572,44 @@ void Texture::SetLevelInfo( |
| DCHECK_GE(level, 0); |
| size_t face_index = GLES2Util::GLTargetToFaceIndex(target); |
| DCHECK_LT(static_cast<size_t>(face_index), |
| - level_infos_.size()); |
| + face_infos_.size()); |
| DCHECK_LT(static_cast<size_t>(level), |
| - level_infos_[face_index].size()); |
| + face_infos_[face_index].level_infos.size()); |
| DCHECK_GE(width, 0); |
| DCHECK_GE(height, 0); |
| DCHECK_GE(depth, 0); |
| Texture::LevelInfo& info = |
| - level_infos_[face_index][level]; |
| + face_infos_[face_index].level_infos[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. |
| + face_infos_[face_index].num_mip_levels = |
| + 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; |
| + |
| + // Signify that level 0 has been changed, so they need to be reverified. |
| + texture_level0_dirty_ = true; |
| + } |
| + |
| + // Signify that at least one of the mips has changed. |
| + texture_mips_dirty_ = true; |
| + } |
| + |
| info.target = target; |
| info.level = level; |
| info.internal_format = internal_format; |
| @@ -554,9 +648,9 @@ bool Texture::ValidForTexture( |
| GLsizei height, |
| GLenum type) const { |
| size_t face_index = GLES2Util::GLTargetToFaceIndex(target); |
| - if (level >= 0 && face_index < level_infos_.size() && |
| - static_cast<size_t>(level) < level_infos_[face_index].size()) { |
| - const LevelInfo& info = level_infos_[face_index][level]; |
| + if (level >= 0 && face_index < face_infos_.size() && |
| + static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) { |
| + const LevelInfo& info = face_infos_[face_index].level_infos[level]; |
| int32 right; |
| int32 top; |
| return SafeAddInt32(xoffset, width, &right) && |
| @@ -575,9 +669,9 @@ bool Texture::GetLevelSize( |
| DCHECK(width); |
| DCHECK(height); |
| size_t face_index = GLES2Util::GLTargetToFaceIndex(target); |
| - if (level >= 0 && face_index < level_infos_.size() && |
| - static_cast<size_t>(level) < level_infos_[face_index].size()) { |
| - const LevelInfo& info = level_infos_[face_index][level]; |
| + if (level >= 0 && face_index < face_infos_.size() && |
| + static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) { |
| + const LevelInfo& info = face_infos_[face_index].level_infos[level]; |
| if (info.target != 0) { |
| *width = info.width; |
| *height = info.height; |
| @@ -592,9 +686,9 @@ bool Texture::GetLevelType( |
| DCHECK(type); |
| DCHECK(internal_format); |
| size_t face_index = GLES2Util::GLTargetToFaceIndex(target); |
| - if (level >= 0 && face_index < level_infos_.size() && |
| - static_cast<size_t>(level) < level_infos_[face_index].size()) { |
| - const LevelInfo& info = level_infos_[face_index][level]; |
| + if (level >= 0 && face_index < face_infos_.size() && |
| + static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) { |
| + const LevelInfo& info = face_infos_[face_index].level_infos[level]; |
| if (info.target != 0) { |
| *type = info.type; |
| *internal_format = info.internal_format; |
| @@ -700,82 +794,77 @@ 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()) { |
| + if (face_infos_.empty()) { |
| texture_complete_ = false; |
| cube_complete_ = false; |
| 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); |
| + const Texture::FaceInfo& first_face = face_infos_[0]; |
| + const Texture::LevelInfo& first_level = first_face.level_infos[0]; |
| + const GLsizei levels_needed = first_face.num_mip_levels; |
| texture_complete_ = |
| max_level_set_ >= (levels_needed - 1) && max_level_set_ >= 0; |
| - cube_complete_ = (level_infos_.size() == 6) && |
| - (first_face.width == first_face.height); |
| + cube_complete_ = (face_infos_.size() == 6) && |
| + (first_level.width == first_level.height); |
| - if (first_face.width == 0 || first_face.height == 0) { |
| + if (first_level.width == 0 || first_level.height == 0) { |
| texture_complete_ = false; |
| - } |
| - if (first_face.type == GL_FLOAT && |
| + } else if (first_level.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 && |
| + } else if (first_level.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; |
| + |
| + if (cube_complete_ && texture_level0_dirty_) { |
| + for (size_t ii = 0; ii < face_infos_.size(); ++ii) { |
| + const Texture::LevelInfo& level0 = face_infos_[ii].level_infos[0]; |
| + if (!TextureFaceComplete(first_level, |
| + ii, |
| + level0.target, |
| + level0.internal_format, |
| + level0.width, |
| + level0.height, |
| + level0.depth, |
| + level0.format, |
| + level0.type)) { |
| + cube_complete_ = false; |
|
vmiura
2014/10/10 17:40:37
I think you need to save the result, so if Texture
David Yen
2014/10/10 17:50:59
Done.
|
| break; |
| } |
| } |
| + texture_level0_dirty_ = false; |
| + } |
| + |
| + if (texture_complete_ && texture_mips_dirty_) { |
| + for (size_t ii = 0; ii < face_infos_.size() && texture_complete_; ++ii) { |
| + const Texture::FaceInfo& face_info = face_infos_[ii]; |
| + const Texture::LevelInfo& level0 = face_info.level_infos[0]; |
| + for (GLsizei jj = 1; jj < levels_needed; ++jj) { |
| + const Texture::LevelInfo& level_info = face_infos_[ii].level_infos[jj]; |
| + if (!TextureMipComplete(level0, |
| + level_info.target, |
| + jj, |
| + level_info.internal_format, |
| + level_info.width, |
| + level_info.height, |
| + level_info.depth, |
| + level_info.format, |
| + level_info.type)) { |
| + texture_complete_ = false; |
|
vmiura
2014/10/10 17:40:37
Same as above.
if texture_complete_ && texture_mi
David Yen
2014/10/10 17:50:59
Done.
|
| + break; |
| + } |
| + } |
| + } |
| + texture_mips_dirty_ = false; |
| } |
| } |
| @@ -785,13 +874,10 @@ bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) { |
| return true; |
| } |
| - const Texture::LevelInfo& first_face = level_infos_[0][0]; |
| - int levels_needed = TextureManager::ComputeMipMapCount( |
| - target_, 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) { |
| - Texture::LevelInfo& info = level_infos_[ii][jj]; |
| + for (size_t ii = 0; ii < face_infos_.size(); ++ii) { |
| + const Texture::FaceInfo& face_info = face_infos_[ii]; |
| + for (GLint jj = 0; jj < face_info.num_mip_levels; ++jj) { |
| + const Texture::LevelInfo& info = face_info.level_infos[jj]; |
| if (info.target != 0) { |
| if (!ClearLevel(decoder, info.target, jj)) { |
| return false; |
| @@ -805,12 +891,12 @@ bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) { |
| bool Texture::IsLevelCleared(GLenum target, GLint level) const { |
| size_t face_index = GLES2Util::GLTargetToFaceIndex(target); |
| - if (face_index >= level_infos_.size() || |
| - level >= static_cast<GLint>(level_infos_[face_index].size())) { |
| + if (face_index >= face_infos_.size() || |
| + level >= static_cast<GLint>(face_infos_[face_index].level_infos.size())) { |
| return true; |
| } |
| - const Texture::LevelInfo& info = level_infos_[face_index][level]; |
| + const Texture::LevelInfo& info = face_infos_[face_index].level_infos[level]; |
| return info.cleared; |
| } |
| @@ -827,12 +913,12 @@ bool Texture::ClearLevel( |
| GLES2Decoder* decoder, GLenum target, GLint level) { |
| DCHECK(decoder); |
| size_t face_index = GLES2Util::GLTargetToFaceIndex(target); |
| - if (face_index >= level_infos_.size() || |
| - level >= static_cast<GLint>(level_infos_[face_index].size())) { |
| + if (face_index >= face_infos_.size() || |
| + level >= static_cast<GLint>(face_infos_[face_index].level_infos.size())) { |
| return true; |
| } |
| - Texture::LevelInfo& info = level_infos_[face_index][level]; |
| + Texture::LevelInfo& info = face_infos_[face_index].level_infos[level]; |
| DCHECK(target == info.target); |
| @@ -862,11 +948,11 @@ void Texture::SetLevelImage( |
| DCHECK_GE(level, 0); |
| size_t face_index = GLES2Util::GLTargetToFaceIndex(target); |
| DCHECK_LT(static_cast<size_t>(face_index), |
| - level_infos_.size()); |
| + face_infos_.size()); |
| DCHECK_LT(static_cast<size_t>(level), |
| - level_infos_[face_index].size()); |
| + face_infos_[face_index].level_infos.size()); |
| Texture::LevelInfo& info = |
| - level_infos_[face_index][level]; |
| + face_infos_[face_index].level_infos[level]; |
| DCHECK_EQ(info.target, target); |
| DCHECK_EQ(info.level, level); |
| info.image = image; |
| @@ -881,9 +967,9 @@ gfx::GLImage* Texture::GetLevelImage(GLint target, GLint level) const { |
| } |
| size_t face_index = GLES2Util::GLTargetToFaceIndex(target); |
| - if (level >= 0 && face_index < level_infos_.size() && |
| - static_cast<size_t>(level) < level_infos_[face_index].size()) { |
| - const LevelInfo& info = level_infos_[face_index][level]; |
| + if (level >= 0 && face_index < face_infos_.size() && |
| + static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) { |
| + const LevelInfo& info = face_infos_[face_index].level_infos[level]; |
| if (info.target != 0) { |
| return info.image.get(); |
| } |