diff --git a/impeller/renderer/backend/gles/blit_command_gles.cc b/impeller/renderer/backend/gles/blit_command_gles.cc index 14016f7123b0f..d6e56b6996081 100644 --- a/impeller/renderer/backend/gles/blit_command_gles.cc +++ b/impeller/renderer/backend/gles/blit_command_gles.cc @@ -163,7 +163,7 @@ std::string BlitGenerateMipmapCommandGLES::GetLabel() const { bool BlitGenerateMipmapCommandGLES::Encode(const ReactorGLES& reactor) const { auto texture_gles = TextureGLES::Cast(texture.get()); - if (!texture_gles->GenerateMipmaps()) { + if (!texture_gles->GenerateMipmap()) { return false; } diff --git a/impeller/renderer/backend/gles/sampler_gles.cc b/impeller/renderer/backend/gles/sampler_gles.cc index 47f2ce56ddddb..054c0f7782468 100644 --- a/impeller/renderer/backend/gles/sampler_gles.cc +++ b/impeller/renderer/backend/gles/sampler_gles.cc @@ -3,8 +3,10 @@ // found in the LICENSE file. #include "impeller/renderer/backend/gles/sampler_gles.h" + #include +#include "impeller/base/validation.h" #include "impeller/renderer/backend/gles/formats_gles.h" #include "impeller/renderer/backend/gles/proc_table_gles.h" #include "impeller/renderer/backend/gles/texture_gles.h" @@ -69,6 +71,13 @@ bool SamplerGLES::ConfigureBoundTexture(const TextureGLES& texture, return false; } + if (texture.NeedsMipmapGeneration()) { + VALIDATION_LOG + << "Texture mip count is > 1, but the mipmap has not been generated. " + "Texture can not be sampled safely."; + return false; + } + auto target = ToTextureTarget(texture.GetTextureDescriptor().type); if (!target.has_value()) { diff --git a/impeller/renderer/backend/gles/texture_gles.cc b/impeller/renderer/backend/gles/texture_gles.cc index e315ba6239bc9..ff7c8c7865ee7 100644 --- a/impeller/renderer/backend/gles/texture_gles.cc +++ b/impeller/renderer/backend/gles/texture_gles.cc @@ -425,7 +425,7 @@ bool TextureGLES::Bind() const { return true; } -bool TextureGLES::GenerateMipmaps() const { +bool TextureGLES::GenerateMipmap() { if (!IsValid()) { return false; } @@ -453,6 +453,7 @@ bool TextureGLES::GenerateMipmaps() const { const auto& gl = reactor_->GetProcTable(); gl.GenerateMipmap(ToTextureType(type)); + mipmap_generated_ = true; return true; } diff --git a/impeller/renderer/backend/gles/texture_gles.h b/impeller/renderer/backend/gles/texture_gles.h index 03c8b5cbcfdd7..0ece901d2be6c 100644 --- a/impeller/renderer/backend/gles/texture_gles.h +++ b/impeller/renderer/backend/gles/texture_gles.h @@ -37,7 +37,7 @@ class TextureGLES final : public Texture, [[nodiscard]] bool Bind() const; - [[nodiscard]] bool GenerateMipmaps() const; + [[nodiscard]] bool GenerateMipmap(); enum class AttachmentPoint { kColor0, diff --git a/impeller/renderer/backend/metal/blit_command_mtl.mm b/impeller/renderer/backend/metal/blit_command_mtl.mm index 90c05fd15b830..2d9b95a75018b 100644 --- a/impeller/renderer/backend/metal/blit_command_mtl.mm +++ b/impeller/renderer/backend/metal/blit_command_mtl.mm @@ -147,14 +147,7 @@ bool BlitGenerateMipmapCommandMTL::Encode( id encoder) const { - auto texture_mtl = TextureMTL::Cast(*texture).GetMTLTexture(); - if (!texture_mtl) { - return false; - } - - [encoder generateMipmapsForTexture:texture_mtl]; - - return true; + return TextureMTL::Cast(*texture).GenerateMipmap(encoder); }; } // namespace impeller diff --git a/impeller/renderer/backend/metal/render_pass_mtl.mm b/impeller/renderer/backend/metal/render_pass_mtl.mm index 9c06b48bd5b0e..cce54c841d584 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/impeller/renderer/backend/metal/render_pass_mtl.mm @@ -382,6 +382,13 @@ static bool Bind(PassBindingsCache& pass, return false; } + if (texture.NeedsMipmapGeneration()) { + VALIDATION_LOG + << "Texture at binding index " << bind_index + << " has a mip count > 1, but the mipmap has not been generated."; + return false; + } + return pass.SetTexture(stage, bind_index, TextureMTL::Cast(texture).GetMTLTexture()); } diff --git a/impeller/renderer/backend/metal/texture_mtl.h b/impeller/renderer/backend/metal/texture_mtl.h index 1aedbeacaa6af..0ff8d849ca04e 100644 --- a/impeller/renderer/backend/metal/texture_mtl.h +++ b/impeller/renderer/backend/metal/texture_mtl.h @@ -29,6 +29,8 @@ class TextureMTL final : public Texture, bool IsWrapped() const; + bool GenerateMipmap(id encoder); + private: id texture_ = nullptr; bool is_valid_ = false; diff --git a/impeller/renderer/backend/metal/texture_mtl.mm b/impeller/renderer/backend/metal/texture_mtl.mm index 5c1332330096b..b719f96e23511 100644 --- a/impeller/renderer/backend/metal/texture_mtl.mm +++ b/impeller/renderer/backend/metal/texture_mtl.mm @@ -92,4 +92,15 @@ return is_wrapped_; } +bool TextureMTL::GenerateMipmap(id encoder) { + if (!texture_) { + return false; + } + + [encoder generateMipmapsForTexture:texture_]; + mipmap_generated_ = true; + + return true; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/blit_command_vk.cc b/impeller/renderer/backend/vulkan/blit_command_vk.cc index 8c27935cf84c8..3139621d89a18 100644 --- a/impeller/renderer/backend/vulkan/blit_command_vk.cc +++ b/impeller/renderer/backend/vulkan/blit_command_vk.cc @@ -148,7 +148,7 @@ static void InsertImageMemoryBarrier(const vk::CommandBuffer& cmd, } bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const { - const auto& src = TextureVK::Cast(*texture); + auto& src = TextureVK::Cast(*texture); const auto size = src.GetTextureDescriptor().size; uint32_t mip_count = src.GetTextureDescriptor().mip_count; @@ -249,6 +249,7 @@ bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const { // state so it doesn't try to perform redundant transitions under the hood. src.SetLayoutWithoutEncoding(vk::ImageLayout::eShaderReadOnlyOptimal); + src.SetMipmapGenerated(); return true; } diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc index b929e647e2594..8f0318d384b01 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -351,6 +351,12 @@ static bool UpdateDescriptorSets(vk::Device device, } auto texture = bindings.textures.at(index).resource; + if (texture->NeedsMipmapGeneration()) { + VALIDATION_LOG + << "Texture at binding index " << index + << " has a mip count > 1, but the mipmap has not been generated."; + return false; + } const auto& texture_vk = TextureVK::Cast(*texture); const SamplerVK& sampler = SamplerVK::Cast(*sampler_handle.resource); diff --git a/impeller/renderer/backend/vulkan/texture_vk.cc b/impeller/renderer/backend/vulkan/texture_vk.cc index 70c048e1f459f..e512537a52f94 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.cc +++ b/impeller/renderer/backend/vulkan/texture_vk.cc @@ -85,6 +85,10 @@ vk::ImageLayout TextureVK::GetLayout() const { return layout_; } +void TextureVK::SetMipmapGenerated() { + mipmap_generated_ = true; +} + vk::ImageLayout TextureVK::SetLayoutWithoutEncoding( vk::ImageLayout layout) const { WriterLock lock(layout_mutex_); diff --git a/impeller/renderer/backend/vulkan/texture_vk.h b/impeller/renderer/backend/vulkan/texture_vk.h index 8ab9a00d27aa3..60dd392be99c7 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.h +++ b/impeller/renderer/backend/vulkan/texture_vk.h @@ -36,6 +36,8 @@ class TextureVK final : public Texture, public BackendCast { vk::ImageLayout GetLayout() const; + void SetMipmapGenerated(); + private: std::weak_ptr context_; std::shared_ptr source_; diff --git a/impeller/renderer/texture.cc b/impeller/renderer/texture.cc index 64860c181a038..aaa800aef03a2 100644 --- a/impeller/renderer/texture.cc +++ b/impeller/renderer/texture.cc @@ -73,4 +73,8 @@ Scalar Texture::GetYCoordScale() const { return 1.0; } +bool Texture::NeedsMipmapGeneration() const { + return !mipmap_generated_ && desc_.mip_count > 1; +} + } // namespace impeller diff --git a/impeller/renderer/texture.h b/impeller/renderer/texture.h index 4491e06f859e9..cfeea6225c594 100644 --- a/impeller/renderer/texture.h +++ b/impeller/renderer/texture.h @@ -41,6 +41,8 @@ class Texture { virtual Scalar GetYCoordScale() const; + bool NeedsMipmapGeneration() const; + protected: explicit Texture(TextureDescriptor desc); @@ -52,6 +54,8 @@ class Texture { std::shared_ptr mapping, size_t slice) = 0; + bool mipmap_generated_ = false; + private: TextureIntent intent_ = TextureIntent::kRenderToTexture; const TextureDescriptor desc_;