Merge pull request #161 from Kode/fix

Shader model 4/5 style texture sampling
This commit is contained in:
Hans-Kristian Arntzen 2017-04-24 12:21:23 +02:00 committed by GitHub
commit c5a2af365f
5 changed files with 471 additions and 56 deletions

View File

@ -1,4 +1,5 @@
uniform sampler2D uTex; Texture2D<float4> uTex;
SamplerState _uTex_sampler;
static float4 FragColor; static float4 FragColor;
static float4 vColor; static float4 vColor;
@ -17,7 +18,7 @@ struct SPIRV_Cross_Output
void frag_main() void frag_main()
{ {
FragColor = vColor * tex2D(uTex, vTex); FragColor = vColor * uTex.Sample(_uTex_sampler, vTex);
} }
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)

View File

@ -0,0 +1,103 @@
Texture1D<float4> tex1d;
SamplerState _tex1d_sampler;
Texture2D<float4> tex2d;
SamplerState _tex2d_sampler;
Texture3D<float4> tex3d;
SamplerState _tex3d_sampler;
TextureCube<float4> texCube;
SamplerState _texCube_sampler;
Texture1D<float4> tex1dShadow;
SamplerComparisonState _tex1dShadow_sampler;
Texture2D<float4> tex2dShadow;
SamplerComparisonState _tex2dShadow_sampler;
TextureCube<float4> texCubeShadow;
SamplerComparisonState _texCubeShadow_sampler;
Texture1DArray<float4> tex1dArray;
SamplerState _tex1dArray_sampler;
Texture2DArray<float4> tex2dArray;
SamplerState _tex2dArray_sampler;
TextureCubeArray<float4> texCubeArray;
SamplerState _texCubeArray_sampler;
static float texCoord1d;
static float2 texCoord2d;
static float3 texCoord3d;
static float4 texCoord4d;
static float4 FragColor;
struct SPIRV_Cross_Input
{
float texCoord1d : TEXCOORD0;
float2 texCoord2d : TEXCOORD1;
float3 texCoord3d : TEXCOORD2;
float4 texCoord4d : TEXCOORD3;
};
struct SPIRV_Cross_Output
{
float4 FragColor : SV_Target0;
};
float SPIRV_Cross_projectTextureCoordinate(float2 coord)
{
return coord.x / coord.y;
}
float2 SPIRV_Cross_projectTextureCoordinate(float3 coord)
{
return float2(coord.x, coord.y) / coord.z;
}
float3 SPIRV_Cross_projectTextureCoordinate(float4 coord)
{
return float3(coord.x, coord.y, coord.z) / coord.w;
}
void frag_main()
{
float4 texcolor = tex1d.Sample(_tex1d_sampler, texCoord1d);
texcolor += tex1d.Sample(_tex1d_sampler, texCoord1d, 1);
texcolor += tex1d.SampleLevel(_tex1d_sampler, texCoord1d, 2.0f);
texcolor += tex1d.SampleGrad(_tex1d_sampler, texCoord1d, 1.0f, 2.0f);
texcolor += tex1d.Sample(_tex1d_sampler, SPIRV_Cross_projectTextureCoordinate(float2(texCoord1d, 2.0f)));
texcolor += tex1d.SampleBias(_tex1d_sampler, texCoord1d, 1.0f);
texcolor += tex2d.Sample(_tex2d_sampler, texCoord2d);
texcolor += tex2d.Sample(_tex2d_sampler, texCoord2d, int2(1, 2));
texcolor += tex2d.SampleLevel(_tex2d_sampler, texCoord2d, 2.0f);
texcolor += tex2d.SampleGrad(_tex2d_sampler, texCoord2d, float2(1.0f, 2.0f), float2(3.0f, 4.0f));
texcolor += tex2d.Sample(_tex2d_sampler, SPIRV_Cross_projectTextureCoordinate(float3(texCoord2d, 2.0f)));
texcolor += tex2d.SampleBias(_tex2d_sampler, texCoord2d, 1.0f);
texcolor += tex3d.Sample(_tex3d_sampler, texCoord3d);
texcolor += tex3d.Sample(_tex3d_sampler, texCoord3d, int3(1, 2, 3));
texcolor += tex3d.SampleLevel(_tex3d_sampler, texCoord3d, 2.0f);
texcolor += tex3d.SampleGrad(_tex3d_sampler, texCoord3d, float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f));
texcolor += tex3d.Sample(_tex3d_sampler, SPIRV_Cross_projectTextureCoordinate(float4(texCoord3d, 2.0f)));
texcolor += tex3d.SampleBias(_tex3d_sampler, texCoord3d, 1.0f);
texcolor += texCube.Sample(_texCube_sampler, texCoord3d);
texcolor += texCube.SampleLevel(_texCube_sampler, texCoord3d, 2.0f);
texcolor += texCube.SampleBias(_texCube_sampler, texCoord3d, 1.0f);
float3 _170 = float3(texCoord1d, 0.0f, 0.0f);
texcolor.w += tex1dShadow.SampleCmp(_tex1dShadow_sampler, _170.x, _170.z);
float3 _188 = float3(texCoord2d, 0.0f);
texcolor.w += tex2dShadow.SampleCmp(_tex2dShadow_sampler, _188.xy, _188.z);
float4 _204 = float4(texCoord3d, 0.0f);
texcolor.w += texCubeShadow.SampleCmp(_texCubeShadow_sampler, _204.xyz, _204.w);
texcolor += tex1dArray.Sample(_tex1dArray_sampler, texCoord2d);
texcolor += tex2dArray.Sample(_tex2dArray_sampler, texCoord3d);
texcolor += texCubeArray.Sample(_texCubeArray_sampler, texCoord4d);
texcolor += tex2d.Gather(_tex2d_sampler, texCoord2d, 0);
texcolor += tex2d.Load(int3(int2(1, 2), 0));
FragColor = texcolor;
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
texCoord1d = stage_input.texCoord1d;
texCoord2d = stage_input.texCoord2d;
texCoord3d = stage_input.texCoord3d;
texCoord4d = stage_input.texCoord4d;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

View File

@ -0,0 +1,63 @@
#version 450
uniform sampler1D tex1d;
uniform sampler2D tex2d;
uniform sampler3D tex3d;
uniform samplerCube texCube;
uniform sampler1DShadow tex1dShadow;
uniform sampler2DShadow tex2dShadow;
uniform samplerCubeShadow texCubeShadow;
uniform sampler1DArray tex1dArray;
uniform sampler2DArray tex2dArray;
uniform samplerCubeArray texCubeArray;
in float texCoord1d;
in vec2 texCoord2d;
in vec3 texCoord3d;
in vec4 texCoord4d;
out vec4 FragColor;
void main()
{
vec4 texcolor = texture(tex1d, texCoord1d);
texcolor += textureOffset(tex1d, texCoord1d, 1);
texcolor += textureLod(tex1d, texCoord1d, 2);
texcolor += textureGrad(tex1d, texCoord1d, 1.0, 2.0);
texcolor += textureProj(tex1d, vec2(texCoord1d, 2.0));
texcolor += texture(tex1d, texCoord1d, 1.0);
texcolor += texture(tex2d, texCoord2d);
texcolor += textureOffset(tex2d, texCoord2d, ivec2(1, 2));
texcolor += textureLod(tex2d, texCoord2d, 2);
texcolor += textureGrad(tex2d, texCoord2d, vec2(1.0, 2.0), vec2(3.0, 4.0));
texcolor += textureProj(tex2d, vec3(texCoord2d, 2.0));
texcolor += texture(tex2d, texCoord2d, 1.0);
texcolor += texture(tex3d, texCoord3d);
texcolor += textureOffset(tex3d, texCoord3d, ivec3(1, 2, 3));
texcolor += textureLod(tex3d, texCoord3d, 2);
texcolor += textureGrad(tex3d, texCoord3d, vec3(1.0, 2.0, 3.0), vec3(4.0, 5.0, 6.0));
texcolor += textureProj(tex3d, vec4(texCoord3d, 2.0));
texcolor += texture(tex3d, texCoord3d, 1.0);
texcolor += texture(texCube, texCoord3d);
texcolor += textureLod(texCube, texCoord3d, 2);
texcolor += texture(texCube, texCoord3d, 1.0);
texcolor.a += texture(tex1dShadow, vec3(texCoord1d, 0.0, 0.0));
texcolor.a += texture(tex2dShadow, vec3(texCoord2d, 0.0));
texcolor.a += texture(texCubeShadow, vec4(texCoord3d, 0.0));
texcolor += texture(tex1dArray, texCoord2d);
texcolor += texture(tex2dArray, texCoord3d);
texcolor += texture(texCubeArray, texCoord4d);
texcolor += textureGather(tex2d, texCoord2d);
texcolor += texelFetch(tex2d, ivec2(1, 2), 0);
FragColor = texcolor;
}

View File

@ -43,6 +43,79 @@ static bool opcode_is_sign_invariant(Op opcode)
} }
} }
string CompilerHLSL::image_type_hlsl(const SPIRType &type)
{
auto &imagetype = get<SPIRType>(type.image.type);
string res;
switch (imagetype.basetype)
{
case SPIRType::Int:
res = "i";
break;
case SPIRType::UInt:
res = "u";
break;
default:
break;
}
if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
return res + "subpassInput" + (type.image.ms ? "MS" : "");
// If we're emulating subpassInput with samplers, force sampler2D
// so we don't have to specify format.
if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
{
// Sampler buffers are always declared as samplerBuffer even though they might be separate images in the SPIR-V.
if (type.image.dim == DimBuffer && type.image.sampled == 1)
res += "sampler";
else
res += type.image.sampled == 2 ? "image" : "texture";
}
else
res += "sampler";
switch (type.image.dim)
{
case Dim1D:
res += "1D";
break;
case Dim2D:
res += "2D";
break;
case Dim3D:
res += "3D";
break;
case DimCube:
res += "CUBE";
break;
case DimBuffer:
res += "Buffer";
break;
case DimSubpassData:
res += "2D";
break;
default:
SPIRV_CROSS_THROW("Only 1D, 2D, 3D, Buffer, InputTarget and Cube textures supported.");
}
if (type.image.ms)
res += "MS";
if (type.image.arrayed)
{
if (is_legacy_desktop())
require_extension("GL_EXT_texture_array");
res += "Array";
}
if (type.image.depth)
res += "Shadow";
return res;
}
string CompilerHLSL::type_to_glsl(const SPIRType &type) string CompilerHLSL::type_to_glsl(const SPIRType &type)
{ {
// Ignore the pointer type since GLSL doesn't have pointers. // Ignore the pointer type since GLSL doesn't have pointers.
@ -58,7 +131,7 @@ string CompilerHLSL::type_to_glsl(const SPIRType &type)
case SPIRType::Image: case SPIRType::Image:
case SPIRType::SampledImage: case SPIRType::SampledImage:
return image_type_glsl(type); return image_type_hlsl(type);
case SPIRType::Sampler: case SPIRType::Sampler:
return "sampler"; return "sampler";
@ -681,6 +754,50 @@ void CompilerHLSL::emit_resources()
end_scope(); end_scope();
statement(""); statement("");
} }
if (requires_textureProj)
{
if (options.shader_model >= 40)
{
statement("float SPIRV_Cross_projectTextureCoordinate(float2 coord)");
begin_scope();
statement("return coord.x / coord.y;");
end_scope();
statement("");
statement("float2 SPIRV_Cross_projectTextureCoordinate(float3 coord)");
begin_scope();
statement("return float2(coord.x, coord.y) / coord.z;");
end_scope();
statement("");
statement("float3 SPIRV_Cross_projectTextureCoordinate(float4 coord)");
begin_scope();
statement("return float3(coord.x, coord.y, coord.z) / coord.w;");
end_scope();
statement("");
}
else
{
statement("float4 SPIRV_Cross_projectTextureCoordinate(float2 coord)");
begin_scope();
statement("return float4(coord.x, 0.0, 0.0, coord.y);");
end_scope();
statement("");
statement("float4 SPIRV_Cross_projectTextureCoordinate(float3 coord)");
begin_scope();
statement("return float4(coord.x, coord.y, 0.0, coord.z);");
end_scope();
statement("");
statement("float4 SPIRV_Cross_projectTextureCoordinate(float4 coord)");
begin_scope();
statement("return coord;");
end_scope();
statement("");
}
}
} }
string CompilerHLSL::layout_for_member(const SPIRType &, uint32_t) string CompilerHLSL::layout_for_member(const SPIRType &, uint32_t)
@ -1099,29 +1216,90 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
string texop; string texop;
if (op == OpImageFetch) if (op == OpImageFetch)
texop += "texelFetch"; {
if (options.shader_model < 40)
{
SPIRV_CROSS_THROW("texelFetch is not supported in HLSL shader model 2/3.");
}
texop += to_expression(img);
texop += ".Load";
}
else else
{ {
texop += "tex2D"; auto &imgformat = get<SPIRType>(imgtype.image.type);
if (imgformat.basetype != SPIRType::Float)
if (gather) {
texop += "Gather"; SPIRV_CROSS_THROW("Sampling non-float textures is not supported in HLSL.");
if (coffsets)
texop += "Offsets";
if (proj)
texop += "Proj";
if (grad_x || grad_y)
texop += "Grad";
if (lod)
texop += "Lod";
} }
if (coffset || offset) if (options.shader_model >= 40)
texop += "Offset"; {
texop += to_expression(img);
if (imgtype.image.depth)
texop += ".SampleCmp";
else if (gather)
texop += ".Gather";
else if (bias)
texop += ".SampleBias";
else if (grad_x || grad_y)
texop += ".SampleGrad";
else if (lod)
texop += ".SampleLevel";
else
texop += ".Sample";
}
else
{
switch (imgtype.image.dim)
{
case Dim1D:
texop += "tex1D";
break;
case Dim2D:
texop += "tex2D";
break;
case Dim3D:
texop += "tex3D";
break;
case DimCube:
texop += "texCUBE";
break;
case DimRect:
case DimBuffer:
case DimSubpassData:
SPIRV_CROSS_THROW("Buffer texture support is not yet implemented for HLSL"); // TODO
}
if (gather)
SPIRV_CROSS_THROW("textureGather is not supported in HLSL shader model 2/3.");
if (offset || coffset)
SPIRV_CROSS_THROW("textureOffset is not supported in HLSL shader model 2/3.");
if (proj)
texop += "proj";
if (grad_x || grad_y)
texop += "grad";
if (lod)
texop += "lod";
if (bias)
texop += "bias";
}
}
expr += texop; expr += texop;
expr += "("; expr += "(";
if (op != OpImageFetch)
{
if (options.shader_model >= 40)
{
expr += "_";
}
expr += to_expression(img); expr += to_expression(img);
if (options.shader_model >= 40)
{
expr += "_sampler";
}
}
bool swizz_func = backend.swizzle_is_function; bool swizz_func = backend.swizzle_is_function;
auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * { auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
@ -1146,39 +1324,58 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
// The IR can give us more components than we need, so chop them off as needed. // The IR can give us more components than we need, so chop them off as needed.
auto coord_expr = to_expression(coord) + swizzle(coord_components, expression_type(coord).vecsize); auto coord_expr = to_expression(coord) + swizzle(coord_components, expression_type(coord).vecsize);
// TODO: implement rest ... A bit intensive. if (proj)
{
if (!requires_textureProj)
{
requires_textureProj = true;
force_recompile = true;
}
coord_expr = "SPIRV_Cross_projectTextureCoordinate(" + coord_expr + ")";
}
if (options.shader_model < 40 && lod)
{
auto &coordtype = expression_type(coord);
string coord_filler;
for (uint32_t size = coordtype.vecsize; size < 3; ++size)
{
coord_filler += ", 0.0";
}
coord_expr = "float4(" + coord_expr + coord_filler + ", " + to_expression(lod) + ")";
}
if (options.shader_model < 40 && bias)
{
auto &coordtype = expression_type(coord);
string coord_filler;
for (uint32_t size = coordtype.vecsize; size < 3; ++size)
{
coord_filler += ", 0.0";
}
coord_expr = "float4(" + coord_expr + coord_filler + ", " + to_expression(bias) + ")";
}
if (op == OpImageFetch)
{
auto &coordtype = expression_type(coord);
stringstream str;
str << coordtype.vecsize + 1;
coord_expr = "int" + str.str() + "(" + coord_expr + ", " + to_expression(lod) + ")";
}
if (op != OpImageFetch)
{
expr += ", ";
}
expr += coord_expr;
if (dref) if (dref)
{ {
forward = forward && should_forward(dref); forward = forward && should_forward(dref);
// SPIR-V splits dref and coordinate.
if (coord_components == 4) // GLSL also splits the arguments in two.
{
expr += ", ";
expr += to_expression(coord);
expr += ", "; expr += ", ";
expr += to_expression(dref); expr += to_expression(dref);
} }
else
{
// Create a composite which merges coord/dref into a single vector.
auto type = expression_type(coord);
type.vecsize = coord_components + 1;
expr += ", ";
expr += type_to_glsl_constructor(type);
expr += "(";
expr += coord_expr;
expr += ", ";
expr += to_expression(dref);
expr += ")";
}
}
else
{
expr += ", ";
expr += coord_expr;
}
if (grad_x || grad_y) if (grad_x || grad_y)
{ {
@ -1190,13 +1387,20 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
expr += to_expression(grad_y); expr += to_expression(grad_y);
} }
if (lod) if (lod && options.shader_model >= 40 && op != OpImageFetch)
{ {
forward = forward && should_forward(lod); forward = forward && should_forward(lod);
expr += ", "; expr += ", ";
expr += to_expression(lod); expr += to_expression(lod);
} }
if (bias && options.shader_model >= 40)
{
forward = forward && should_forward(bias);
expr += ", ";
expr += to_expression(bias);
}
if (coffset) if (coffset)
{ {
forward = forward && should_forward(coffset); forward = forward && should_forward(coffset);
@ -1210,13 +1414,6 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
expr += to_expression(offset); expr += to_expression(offset);
} }
if (bias)
{
forward = forward && should_forward(bias);
expr += ", ";
expr += to_expression(bias);
}
if (comp) if (comp)
{ {
forward = forward && should_forward(comp); forward = forward && should_forward(comp);
@ -1238,7 +1435,43 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
void CompilerHLSL::emit_uniform(const SPIRVariable &var) void CompilerHLSL::emit_uniform(const SPIRVariable &var)
{ {
add_resource_name(var.self); add_resource_name(var.self);
auto &type = get<SPIRType>(var.basetype);
if (options.shader_model >= 40 && type.basetype == SPIRType::SampledImage)
{
auto &imagetype = get<SPIRType>(type.image.type);
string dim;
switch (type.image.dim)
{
case Dim1D:
dim = "1D";
break;
case Dim2D:
dim = "2D";
break;
case Dim3D:
dim = "3D";
break;
case DimCube:
dim = "Cube";
break;
case DimRect:
case DimBuffer:
case DimSubpassData:
SPIRV_CROSS_THROW("Buffer texture support is not yet implemented for HLSL"); // TODO
}
string arrayed = type.image.arrayed ? "Array" : "";
statement("Texture", dim, arrayed, "<", type_to_glsl(imagetype), "4> ", to_name(var.self), ";");
if (type.image.depth)
statement("SamplerComparisonState _", to_name(var.self), "_sampler;");
else
statement("SamplerState _", to_name(var.self), "_sampler;");
}
else
{
statement(variable_decl(var), ";"); statement(variable_decl(var), ";");
}
// TODO: Separate samplers/images
} }
string CompilerHLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type) string CompilerHLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
@ -1352,12 +1585,25 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
} }
case OpFMod: case OpFMod:
{
if (!requires_op_fmod)
{ {
requires_op_fmod = true; requires_op_fmod = true;
force_recompile = true;
}
CompilerGLSL::emit_instruction(instruction); CompilerGLSL::emit_instruction(instruction);
break; break;
} }
case OpImage:
{
uint32_t result_type = ops[0];
uint32_t id = ops[1];
emit_op(result_type, id, to_expression(ops[2]), true, true);
// TODO: Maybe change this when separate samplers/images are supported
break;
}
case OpDPdx: case OpDPdx:
UFOP(ddx); UFOP(ddx);
break; break;

View File

@ -57,6 +57,7 @@ public:
private: private:
std::string type_to_glsl(const SPIRType &type) override; std::string type_to_glsl(const SPIRType &type) override;
std::string image_type_hlsl(const SPIRType &type);
void emit_function_prototype(SPIRFunction &func, uint64_t return_flags) override; void emit_function_prototype(SPIRFunction &func, uint64_t return_flags) override;
void emit_hlsl_entry_point(); void emit_hlsl_entry_point();
void emit_header() override; void emit_header() override;
@ -80,6 +81,7 @@ private:
Options options; Options options;
bool requires_op_fmod = false; bool requires_op_fmod = false;
bool requires_textureProj = false;
void emit_builtin_variables(); void emit_builtin_variables();
bool require_output = false; bool require_output = false;