mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
p5f fm: build Vulkan samplers from server-owned values
This commit is contained in:
@@ -15,7 +15,37 @@
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
namespace {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// An accessor view over the wire's POD values, not a GL object with constructor,
|
||||
// lifetime ID, allocator hooks or mutation callbacks. Both sources below use
|
||||
// one sampler policy, including format-sensitive border-color conversion.
|
||||
struct SamplerParametersSource {
|
||||
const SamplerParameters& Params;
|
||||
SamplerWrapMode GetWrapS() const { return Params.wrapS; }
|
||||
SamplerWrapMode GetWrapT() const { return Params.wrapT; }
|
||||
SamplerWrapMode GetWrapR() const { return Params.wrapR; }
|
||||
SamplerFilterMode GetMinFilter() const { return Params.minFilter; }
|
||||
SamplerFilterMode GetMagFilter() const { return Params.magFilter; }
|
||||
SamplerMipmapMode GetMipmapMode() const { return Params.mipmapMode; }
|
||||
Float GetMinLod() const { return Params.minLod; }
|
||||
Float GetMaxLod() const { return Params.maxLod; }
|
||||
Float GetLodBias() const { return Params.lodBias; }
|
||||
Float GetMaxAnisotropy() const { return Params.maxAnisotropy; }
|
||||
SamplerCompareMode GetCompareMode() const { return Params.compareMode; }
|
||||
SamplerCompareFunc GetSamplerCompareFunc() const { return Params.compareFunc; }
|
||||
const FloatVec4& GetBorderColor() const { return Params.borderColor; }
|
||||
const IntVec4& GetBorderColorI() const { return Params.borderColorI; }
|
||||
const UintVec4& GetBorderColorUI() const { return Params.borderColorUI; }
|
||||
// Cache identity is entirely content-based; these fields are diagnostics.
|
||||
Uint GetExternalIndex() const { return 0; }
|
||||
Uint16 GetVersion() const { return 0; }
|
||||
};
|
||||
|
||||
template <class SamplerSource>
|
||||
Bool UsesBorderColor(const SamplerSource& sampler) {
|
||||
#else
|
||||
Bool UsesBorderColor(const MG_State::GLState::SamplerObject& sampler) {
|
||||
#endif
|
||||
return sampler.GetWrapS() == SamplerWrapMode::ClampToBorder ||
|
||||
sampler.GetWrapT() == SamplerWrapMode::ClampToBorder ||
|
||||
sampler.GetWrapR() == SamplerWrapMode::ClampToBorder;
|
||||
@@ -191,14 +221,24 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return std::fabs(lhs - rhs) <= 1e-6f;
|
||||
}
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
template <class SamplerSource>
|
||||
Float ResolveEffectiveMaxLod(const SamplerSource& sampler) {
|
||||
#else
|
||||
Float ResolveEffectiveMaxLod(const MG_State::GLState::SamplerObject& sampler) {
|
||||
#endif
|
||||
if (sampler.GetMipmapMode() == SamplerMipmapMode::None) {
|
||||
return 0.0f;
|
||||
}
|
||||
return sampler.GetMaxLod();
|
||||
}
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
template <class SamplerSource>
|
||||
Float ResolveEffectiveMinLod(const SamplerSource& sampler, Float effectiveMaxLod) {
|
||||
#else
|
||||
Float ResolveEffectiveMinLod(const MG_State::GLState::SamplerObject& sampler, Float effectiveMaxLod) {
|
||||
#endif
|
||||
return std::min(sampler.GetMinLod(), effectiveMaxLod);
|
||||
}
|
||||
|
||||
@@ -209,7 +249,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// GL's non-mipmapped minification - large enough for lambda to stay positive, small enough
|
||||
// that a NEAREST mip mode still rounds down to level 0. Clamped rather than assigned, so a
|
||||
// texture whose GL_TEXTURE_MAX_LOD really is 0 keeps magnifying as GL says it must.
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
template <class SamplerSource>
|
||||
Float ResolveSingleLevelMaxLod(const SamplerSource& sampler, Bool singleLevelView) {
|
||||
#else
|
||||
Float ResolveSingleLevelMaxLod(const MG_State::GLState::SamplerObject& sampler, Bool singleLevelView) {
|
||||
#endif
|
||||
const Float maxLod = ResolveEffectiveMaxLod(sampler);
|
||||
return singleLevelView ? std::min(maxLod, 0.25f) : maxLod;
|
||||
}
|
||||
@@ -230,7 +275,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
template <class SamplerSource>
|
||||
Float VkSamplerManager::ResolveEffectiveMaxAnisotropy(const SamplerSource& sampler,
|
||||
#else
|
||||
Float VkSamplerManager::ResolveEffectiveMaxAnisotropy(const MG_State::GLState::SamplerObject& sampler,
|
||||
#endif
|
||||
Bool forceNearestFiltering) const {
|
||||
if (!m_samplerAnisotropySupported) return 1.0f;
|
||||
if (forceNearestFiltering) return 1.0f;
|
||||
@@ -289,7 +339,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
}
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
template <class SamplerSource>
|
||||
Uint64 VkSamplerManager::BuildSamplerKey(const SamplerSource& sampler,
|
||||
#else
|
||||
Uint64 VkSamplerManager::BuildSamplerKey(const MG_State::GLState::SamplerObject& sampler,
|
||||
#endif
|
||||
Bool forceNearestFiltering, Bool singleLevelView,
|
||||
const ResolvedBorderColor& borderColor) const {
|
||||
MOBILEGL_ASSERT(m_config != nullptr, "VkSamplerManager::BuildSamplerKey: m_config is null");
|
||||
@@ -335,8 +390,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return XXH64_digest(m_hashState);
|
||||
}
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
template <class SamplerSource>
|
||||
VkSampler VkSamplerManager::GetOrCreateSamplerImpl(const SamplerSource& sampler,
|
||||
TextureInternalFormat format,
|
||||
#else
|
||||
VkSampler VkSamplerManager::GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler,
|
||||
const MG_State::GLState::ITextureObject& texture,
|
||||
#endif
|
||||
Bool forceNearestFiltering, Uint32 viewLevelCount) {
|
||||
// A view that exposes a single mip level has no second level to blend with, so GL's
|
||||
// *_MIPMAP_* minification filters degenerate to plain filtering on the base level -
|
||||
@@ -348,7 +409,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// the default-framebuffer blit shader had to work around with an explicit-LOD sample.
|
||||
const Bool singleLevelView = viewLevelCount == 1;
|
||||
// Resolved once and used for both the key and the create-info; see ResolvedBorderColor.
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
const ResolvedBorderColor borderColor = ResolveBorderColor(sampler, format);
|
||||
#else
|
||||
const ResolvedBorderColor borderColor = ResolveBorderColor(sampler, texture);
|
||||
#endif
|
||||
const Uint64 key = BuildSamplerKey(sampler, forceNearestFiltering, singleLevelView, borderColor);
|
||||
auto it = m_samplers.find(key);
|
||||
if (it != m_samplers.end()) {
|
||||
@@ -408,6 +473,20 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return vkSampler;
|
||||
}
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
VkSampler VkSamplerManager::GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler,
|
||||
const MG_State::GLState::ITextureObject& texture,
|
||||
Bool forceNearestFiltering, Uint32 viewLevelCount) {
|
||||
return GetOrCreateSamplerImpl(sampler, texture.GetFormat(), forceNearestFiltering, viewLevelCount);
|
||||
}
|
||||
|
||||
VkSampler VkSamplerManager::GetOrCreateSamplerFromParameters(const SamplerParameters& parameters,
|
||||
TextureInternalFormat format, Bool forceNearestFiltering, Uint32 viewLevelCount) {
|
||||
return GetOrCreateSamplerImpl(SamplerParametersSource{parameters}, format,
|
||||
forceNearestFiltering, viewLevelCount);
|
||||
}
|
||||
#endif
|
||||
|
||||
VkFilter VkSamplerManager::ToVkFilter(SamplerFilterMode mode) {
|
||||
return mode == SamplerFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
|
||||
}
|
||||
@@ -463,8 +542,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
}
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
template <class SamplerSource>
|
||||
VkSamplerManager::ResolvedBorderColor VkSamplerManager::ResolveBorderColor(
|
||||
const SamplerSource& sampler, TextureInternalFormat format) const {
|
||||
#else
|
||||
VkSamplerManager::ResolvedBorderColor VkSamplerManager::ResolveBorderColor(
|
||||
const MG_State::GLState::SamplerObject& sampler, const MG_State::GLState::ITextureObject& texture) const {
|
||||
#endif
|
||||
ResolvedBorderColor resolved{};
|
||||
if (!UsesBorderColor(sampler)) {
|
||||
return resolved; // FLOAT_TRANSPARENT_BLACK, never sampled
|
||||
@@ -472,7 +557,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
// Border colour is sampler state: a bound sampler object supplies its own, and a texture
|
||||
// with none reaches the very same value through the sampler object it owns.
|
||||
#if !MOBILEGL_BUILD_DISAGGREGATED
|
||||
const auto format = texture.GetFormat();
|
||||
#endif
|
||||
const auto domain = ResolveBorderColorDomain(format);
|
||||
const Bool canUseCustom = m_customBorderColorSupported && m_maxCustomBorderColorSamplers > 0 &&
|
||||
m_customBorderColorSamplerCount < m_maxCustomBorderColorSamplers;
|
||||
|
||||
@@ -46,6 +46,12 @@ public:
|
||||
const MG_State::GLState::ITextureObject& texture,
|
||||
Bool forceNearestFiltering = false,
|
||||
Uint32 viewLevelCount = 0);
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// The applier owns these values: effective bound/builtin sampler parameters and
|
||||
// the sampled texture view's format/range. No frontend object is constructed.
|
||||
VkSampler GetOrCreateSamplerFromParameters(const SamplerParameters& parameters,
|
||||
TextureInternalFormat format, Bool forceNearestFiltering = false, Uint32 viewLevelCount = 0);
|
||||
#endif
|
||||
// Frame boundary hook: ages the sampler cache and destroys samplers not used
|
||||
// for many frames. The key hashes continuous float state (lodBias, LOD clamps,
|
||||
// anisotropy), so an app animating those would otherwise mint an unbounded
|
||||
@@ -86,19 +92,37 @@ private:
|
||||
Bool usesCustomBorderColor = false;
|
||||
};
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
template <class SamplerSource>
|
||||
VkSampler GetOrCreateSamplerImpl(const SamplerSource& sampler, TextureInternalFormat format,
|
||||
Bool forceNearestFiltering, Uint32 viewLevelCount);
|
||||
template <class SamplerSource>
|
||||
Uint64 BuildSamplerKey(const SamplerSource& sampler, Bool forceNearestFiltering,
|
||||
#else
|
||||
Uint64 BuildSamplerKey(const MG_State::GLState::SamplerObject& sampler, Bool forceNearestFiltering,
|
||||
#endif
|
||||
Bool singleLevelView, const ResolvedBorderColor& borderColor) const;
|
||||
static VkFilter ToVkFilter(SamplerFilterMode mode);
|
||||
static VkSamplerMipmapMode ToVkMipmapMode(SamplerMipmapMode mode);
|
||||
static VkSamplerAddressMode ToVkAddressMode(SamplerWrapMode mode);
|
||||
static VkCompareOp ToVkCompareOp(SamplerCompareFunc func);
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
template <class SamplerSource>
|
||||
ResolvedBorderColor ResolveBorderColor(const SamplerSource& sampler, TextureInternalFormat format) const;
|
||||
#else
|
||||
ResolvedBorderColor ResolveBorderColor(const MG_State::GLState::SamplerObject& sampler,
|
||||
const MG_State::GLState::ITextureObject& texture) const;
|
||||
#endif
|
||||
// The anisotropy Vulkan will actually apply: 1.0 (i.e. disabled) unless the feature is on and
|
||||
// the sampler filters linearly both ways, otherwise the GL request clamped to the device limit.
|
||||
// GL happily carries GL_TEXTURE_MAX_ANISOTROPY on a NEAREST sampler (Blaze3D's blocks do exactly
|
||||
// that) while Vulkan forbids anisotropyEnable there, so the GL value must never be forwarded raw.
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
template <class SamplerSource>
|
||||
Float ResolveEffectiveMaxAnisotropy(const SamplerSource& sampler,
|
||||
#else
|
||||
Float ResolveEffectiveMaxAnisotropy(const MG_State::GLState::SamplerObject& sampler,
|
||||
#endif
|
||||
Bool forceNearestFiltering) const;
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
|
||||
Reference in New Issue
Block a user