mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 10:03:23 +09:00
[Fix, Test] (ShaderTranspiler, GLImpl, ProgramState, DirectVulkan): keep fp64 where the backend consumes it natively
This commit is contained in:
@@ -562,12 +562,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
if (MG_Util::Async::AsyncShaderCompileEnabled()) {
|
||||
extensions.push_back(E_GL_KHR_parallel_shader_compile);
|
||||
}
|
||||
// GL_ARB_gpu_shader_fp64 is opt-in (MOBILEGL_ADVERTISE_FP64). Every `double` in a
|
||||
// shader compiles and runs already - it is narrowed to 32 bits before the module
|
||||
// reaches this backend - so an application that simply uses doubles needs nothing
|
||||
// advertised. What the extension additionally promises is 64-bit PRECISION, which no
|
||||
// mobile GPU has and the narrowing cannot fake, so advertising it by default would
|
||||
// make an application that checks the string take a path MobileGL cannot honour.
|
||||
// GL_ARB_gpu_shader_fp64 is opt-in (MOBILEGL_ADVERTISE_FP64), and stays opt-in even on a
|
||||
// device that HAS shaderFloat64. Every `double` in a shader compiles and runs either way
|
||||
// - narrowed to 32 bits where the device has no 64-bit floats, kept whole where it does -
|
||||
// so an application that simply uses doubles needs nothing advertised. What the extension
|
||||
// additionally promises is the whole GL_ARB_gpu_shader_fp64 SURFACE (glUniform*d
|
||||
// conformance, the fp64 built-ins, the state queries), and turning the string on is a
|
||||
// decision about all of it rather than about the shader path alone.
|
||||
if (MG_Config::Features.AdvertiseFp64) {
|
||||
extensions.push_back(E_GL_ARB_gpu_shader_fp64);
|
||||
}
|
||||
@@ -965,26 +966,34 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
DynParams::PerLayerFramebufferAttachmentBit(TextureTarget::TextureCubeMapArray);
|
||||
}
|
||||
}
|
||||
// Never, on any device, and no longer for the reason it used to be. It used to track
|
||||
// shaderFloat64 because a `dvec3` input needed the Float64 capability to exist in the
|
||||
// module at all; a 64-bit vertex FETCH was already impossible (VK_FORMAT_R64*_SFLOAT is
|
||||
// optional and lavapipe reports zero bufferFeatures for all four), so the attribute
|
||||
// arrived as its 32-bit word pair and PackDoubleVertexInputsPass bitcast it back.
|
||||
// The device feature the whole fp64 story hangs off. With it, a module keeps its
|
||||
// OpCapability Float64 and real doubles reach the driver; without it the transpile
|
||||
// narrows every 64-bit float to 32 (ShaderTranspiler::DemoteFloat64Pass), because
|
||||
// VUID-VkShaderModuleCreateInfo-pCode-08740 forbids the capability outright and no
|
||||
// pipeline could be built from such a module. lavapipe reports it; Adreno and Mali both
|
||||
// report VK_FALSE, so on every real mobile device this is false and the demotion runs
|
||||
// exactly as it always has.
|
||||
m_dynamicParameters.SupportsShaderFloat64 = m_vulkanCaps.SupportsShaderFloat64;
|
||||
// Never, on any device, and DELIBERATELY NOT COUPLED to the line above even though it
|
||||
// once tracked the same feature. It used to, because a `dvec` input needed Float64 to
|
||||
// exist in the module at all; a 64-bit vertex FETCH was already impossible
|
||||
// (VK_FORMAT_R64*_SFLOAT is optional and lavapipe reports zero bufferFeatures for all
|
||||
// four), so the attribute arrived as its 32-bit word pair and PackDoubleVertexInputsPass
|
||||
// bitcast it back.
|
||||
//
|
||||
// The shader half of that is gone: every 64-bit float is narrowed before any module
|
||||
// reaches a backend (ShaderTranspiler::DemoteFloat64Pass), so there is no `double` input
|
||||
// left to bitcast INTO, and feeding a UINT-formatted attribute to what is now a `float`
|
||||
// input would be silent garbage. Reconstructing the value would mean decoding the
|
||||
// IEEE-754 double bit pattern in the shader - software fp64, which is precisely what the
|
||||
// demotion exists to avoid - and on Espryt it would additionally need the ES driver to
|
||||
// fetch 2N uint components where the application declared N doubles, which a dvec3 or
|
||||
// dvec4 cannot even express within one attribute location.
|
||||
// Re-coupling it does not work, and the reason is worth recording because it is not
|
||||
// obvious: this flag decides the VkFormat from the VAO ATTRIBUTE alone, and the attribute
|
||||
// does not know what the shader declared. glVertexAttribFormat(GL_DOUBLE) against a plain
|
||||
// `in vec4` is not only legal but the common case
|
||||
// (KHR-GL43.vertex_attrib_binding.basic-input-case4 does exactly that, and case5 adds
|
||||
// normalized=GL_TRUE), and advanced-bindingUpdate feeds a dvec3 the same way - GL defines
|
||||
// all of them as "doubles in memory, converted to float". Turning the flag on turns the
|
||||
// narrowing OFF for every one of them and the attributes come back unfetched.
|
||||
//
|
||||
// So glVertexAttribLFormat / glVertexAttribLPointer are declined here exactly as they
|
||||
// already were on Espryt and on every real mobile device (Adreno and Mali both report
|
||||
// shaderFloat64 == VK_FALSE), and for the same visible reason. A `dvec3` INPUT still
|
||||
// compiles and draws - it is a `vec3` after demotion - as long as the application feeds
|
||||
// it with glVertexAttribPointer(GL_FLOAT) rather than 64-bit data.
|
||||
// What keeps the two halves honest instead is a per-MODULE decision: a vertex module that
|
||||
// declares a 64-bit float INPUT is demoted whole, even where the backend has native fp64,
|
||||
// so `dvec` inputs are `vec` inputs on this backend exactly as they always were. See
|
||||
// ShaderCompiler::SanitizeAndOptimizeBinary.
|
||||
m_dynamicParameters.SupportsFloat64VertexAttributes = false;
|
||||
m_dynamicParameters.MaxShaderStorageBlockSize =
|
||||
std::min(m_vulkanCaps.MaxShaderStorageBlockSize, kMaxAdvertisedShaderStorageBlockSize);
|
||||
|
||||
Reference in New Issue
Block a user