Merge pull request #803 from KhronosGroup/fix-796

MSL: Workaround missing gradient2d() on macOS for typical cascaded shadow mapping
This commit is contained in:
Hans-Kristian Arntzen 2019-01-07 10:53:11 +01:00 committed by GitHub
commit e6cce63679
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 181 additions and 13 deletions

View File

@ -0,0 +1,22 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float FragColor [[color(0)]];
};
struct main0_in
{
float4 vUV [[user(locn0)]];
};
fragment main0_out main0(main0_in in [[stage_in]], depth2d_array<float> uTex [[texture(0)]], sampler uShadow [[sampler(1)]])
{
main0_out out = {};
out.FragColor = uTex.sample_compare(uShadow, in.vUV.xy, uint(round(in.vUV.z)), in.vUV.w, level(0));
return out;
}

View File

@ -0,0 +1,22 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float FragColor [[color(0)]];
};
struct main0_in
{
float4 vUV [[user(locn0)]];
};
fragment main0_out main0(main0_in in [[stage_in]], depth2d_array<float> uTex [[texture(0)]], sampler uShadow [[sampler(1)]])
{
main0_out out = {};
out.FragColor = uTex.sample_compare(uShadow, in.vUV.xy, uint(round(in.vUV.z)), in.vUV.w, gradient2d(float2(0.0), float2(0.0)));
return out;
}

View File

@ -0,0 +1,22 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float FragColor [[color(0)]];
};
struct main0_in
{
float4 vUV [[user(locn0)]];
};
fragment main0_out main0(main0_in in [[stage_in]], depth2d_array<float> uTex [[texture(0)]], sampler uShadow [[sampler(1)]])
{
main0_out out = {};
out.FragColor = uTex.sample_compare(uShadow, in.vUV.xy, uint(round(in.vUV.z)), in.vUV.w, level(0));
return out;
}

View File

@ -0,0 +1,22 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float FragColor [[color(0)]];
};
struct main0_in
{
float4 vUV [[user(locn0)]];
};
fragment main0_out main0(main0_in in [[stage_in]], depth2d_array<float> uTex [[texture(0)]], sampler uShadow [[sampler(1)]])
{
main0_out out = {};
out.FragColor = uTex.sample_compare(uShadow, in.vUV.xy, uint(round(in.vUV.z)), in.vUV.w, gradient2d(float2(0.0), float2(0.0)));
return out;
}

View File

@ -0,0 +1,11 @@
#version 450
layout(binding = 0) uniform texture2DArray uTex;
layout(binding = 1) uniform samplerShadow uShadow;
layout(location = 0) in vec4 vUV;
layout(location = 0) out float FragColor;
void main()
{
FragColor = textureGrad(sampler2DArrayShadow(uTex, uShadow), vUV, vec2(0.0), vec2(0.0));
}

View File

@ -0,0 +1,11 @@
#version 450
layout(binding = 0) uniform texture2DArray uTex;
layout(binding = 1) uniform samplerShadow uShadow;
layout(location = 0) in vec4 vUV;
layout(location = 0) out float FragColor;
void main()
{
FragColor = textureGrad(sampler2DArrayShadow(uTex, uShadow), vUV, vec2(0.0), vec2(0.0));
}

View File

@ -1088,6 +1088,21 @@ struct SPIRConstant : IVariant
c.vecsize = constant_type_.vecsize;
}
inline bool constant_is_null() const
{
if (specialization)
return false;
if (!subconstants.empty())
return false;
for (uint32_t col = 0; col < columns(); col++)
for (uint32_t row = 0; row < vector_size(); row++)
if (scalar_u64(col, row) != 0)
return false;
return true;
}
explicit SPIRConstant(uint32_t constant_type_)
: constant_type(constant_type_)
{

View File

@ -901,8 +901,8 @@ void Compiler::flatten_interface_block(uint32_t id)
var.storage = storage;
}
void Compiler::update_name_cache(unordered_set<string> &cache_primary,
const unordered_set<string> &cache_secondary, string &name)
void Compiler::update_name_cache(unordered_set<string> &cache_primary, const unordered_set<string> &cache_secondary,
string &name)
{
if (name.empty())
return;
@ -918,9 +918,7 @@ void Compiler::update_name_cache(unordered_set<string> &cache_primary,
return false;
};
const auto insert_name = [&](const string &n) {
cache_primary.insert(n);
};
const auto insert_name = [&](const string &n) { cache_primary.insert(n); };
if (!find_name(name))
{

View File

@ -653,8 +653,7 @@ protected:
// but the set is not updated when we have found a new name.
// Used primarily when adding block interface names.
void update_name_cache(std::unordered_set<std::string> &cache_primary,
const std::unordered_set<std::string> &cache_secondary,
std::string &name);
const std::unordered_set<std::string> &cache_secondary, std::string &name);
bool function_is_pure(const SPIRFunction &func);
bool block_is_pure(const SPIRBlock &block);

View File

@ -1546,8 +1546,7 @@ void CompilerGLSL::emit_buffer_block_native(const SPIRVariable &var)
// Shaders never use the block by interface name, so we don't
// have to track this other than updating name caches.
// If we have a collision for any reason, just fallback immediately.
if (ir.meta[type.self].decoration.alias.empty() ||
block_namespace.find(buffer_name) != end(block_namespace) ||
if (ir.meta[type.self].decoration.alias.empty() || block_namespace.find(buffer_name) != end(block_namespace) ||
resource_names.find(buffer_name) != end(resource_names))
{
buffer_name = get_block_fallback_name(var.self);
@ -4231,6 +4230,14 @@ void CompilerGLSL::emit_texture_op(const Instruction &i)
}
}
bool CompilerGLSL::expression_is_constant_null(uint32_t id) const
{
auto *c = maybe_get<SPIRConstant>(id);
if (!c)
return false;
return c->constant_is_null();
}
// Returns the function name for a texture sampling function for the specified image and sampling characteristics.
// For some subclasses, the function is a method on the specified image.
string CompilerGLSL::to_function_name(uint32_t tex, const SPIRType &imgtype, bool is_fetch, bool is_gather,
@ -4247,10 +4254,11 @@ string CompilerGLSL::to_function_name(uint32_t tex, const SPIRType &imgtype, boo
if (((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
image_is_comparison(imgtype, tex) && lod)
{
auto *constant_lod = maybe_get<SPIRConstant>(lod);
if (!constant_lod || constant_lod->scalar_f32() != 0.0f)
if (!expression_is_constant_null(lod))
{
SPIRV_CROSS_THROW(
"textureLod on sampler2DArrayShadow is not constant 0.0. This cannot be expressed in GLSL.");
}
workaround_lod_array_shadow_as_grad = true;
}

View File

@ -577,8 +577,7 @@ protected:
// but the set is not updated when we have found a new name.
// Used primarily when adding block interface names.
void add_variable(std::unordered_set<std::string> &variables_primary,
const std::unordered_set<std::string> &variables_secondary,
std::string &name);
const std::unordered_set<std::string> &variables_secondary, std::string &name);
void check_function_call_constraints(const uint32_t *args, uint32_t length);
void handle_invalid_expression(uint32_t id);
@ -615,6 +614,8 @@ protected:
void handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id);
void disallow_forwarding_in_expression_chain(const SPIRExpression &expr);
bool expression_is_constant_null(uint32_t id) const;
private:
void init()
{

View File

@ -3321,6 +3321,43 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool
forward = forward && should_forward(dref);
farg_str += ", ";
farg_str += to_expression(dref);
if (msl_options.is_macos() && (grad_x || grad_y))
{
// For sample compare, MSL does not support gradient2d for all targets (only iOS apparently according to docs).
// However, the most common case here is to have a constant gradient of 0, as that is the only way to express
// LOD == 0 in GLSL with sampler2DArrayShadow (cascaded shadow mapping).
// We will detect a compile-time constant 0 value for gradient and promote that to level(0) on MSL.
bool constant_zero_x = !grad_x || expression_is_constant_null(grad_x);
bool constant_zero_y = !grad_y || expression_is_constant_null(grad_y);
if (constant_zero_x && constant_zero_y)
{
lod = 0;
grad_x = 0;
grad_y = 0;
farg_str += ", level(0)";
}
else
{
SPIRV_CROSS_THROW("Using non-constant 0.0 gradient() qualifier for sample_compare. This is not "
"supported in MSL macOS.");
}
}
if (msl_options.is_macos() && bias)
{
// Bias is not supported either on macOS with sample_compare.
// Verify it is compile-time zero, and drop the argument.
if (expression_is_constant_null(bias))
{
bias = 0;
}
else
{
SPIRV_CROSS_THROW(
"Using non-constant 0.0 bias() qualifier for sample_compare. This is not supported in MSL macOS.");
}
}
}
// LOD Options