Implement OpImageQueryLod by faking derivatives on sample quad

This commit is contained in:
baldurk
2020-04-23 16:15:22 +01:00
parent 0a78a65ec2
commit 18713f644e
12 changed files with 141 additions and 17 deletions
+1
View File
@@ -386,6 +386,7 @@ set(data
data/glsl/quadresolve.frag
data/glsl/quadwrite.frag
data/glsl/pixelhistory_primid.frag
data/glsl/shaderdebug_sample.vert
data/glsl/texdisplay.frag
data/glsl/texremap.frag
data/glsl/gl_texsample.h
+1
View File
@@ -64,6 +64,7 @@ DECLARE_EMBED(glsl_deptharr2ms_frag);
DECLARE_EMBED(glsl_depthms2arr_frag);
DECLARE_EMBED(glsl_gles_texsample_h);
DECLARE_EMBED(glsl_pixelhistory_primid_frag);
DECLARE_EMBED(glsl_shaderdebug_sample_vert);
DECLARE_EMBED(glsl_texremap_frag);
#undef DECLARE_EMBED
@@ -0,0 +1,46 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2020 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
layout(location = 0) out vec3 uvw;
layout(push_constant) uniform PushData
{
vec4 uvw;
vec4 ddx;
vec4 ddy;
}
push;
void main(void)
{
const vec4 verts[3] = vec4[3](vec4(-0.75, -0.75, 0.5, 1.0), vec4(1.25, -0.75, 0.5, 1.0),
vec4(-0.75, 1.25, 0.5, 1.0));
gl_Position = verts[gl_VertexIndex];
uvw = push.uvw.xyz;
if(gl_VertexIndex == 1)
uvw += push.ddx.xyz;
else if(gl_VertexIndex == 2)
uvw += push.ddy.xyz;
}
+1
View File
@@ -146,6 +146,7 @@ RESOURCE_glsl_gltext_vert TYPE_EMBED "glsl/gltext.vert"
RESOURCE_glsl_gltext_frag TYPE_EMBED "glsl/gltext.frag"
RESOURCE_glsl_glsl_globals_h TYPE_EMBED "glsl/glsl_globals.h"
RESOURCE_glsl_texremap_frag TYPE_EMBED "glsl/texremap.frag"
RESOURCE_glsl_shaderdebug_sample_vert TYPE_EMBED "glsl/shaderdebug_sample.vert"
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
+1
View File
@@ -49,6 +49,7 @@
#define RESOURCE_glsl_glsl_globals_h 440
#define RESOURCE_glsl_texremap_frag 441
#define RESOURCE_glsl_pixelhistory_primid_frag 442
#define RESOURCE_glsl_shaderdebug_sample_vert 443
// Next default values for new objects
//
+10 -12
View File
@@ -1986,6 +1986,7 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray<ThreadState>
case Op::ImageFetch:
case Op::ImageGather:
case Op::ImageDrefGather:
case Op::ImageQueryLod:
case Op::ImageSampleExplicitLod:
case Op::ImageSampleImplicitLod:
case Op::ImageSampleDrefExplicitLod:
@@ -2033,6 +2034,15 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray<ThreadState>
gather = GatherChannel::Red;
compare = GetSrc(image.dref);
}
else if(opdata.op == Op::ImageQueryLod)
{
OpImageQueryLod image(it);
sampler = img = GetSrc(image.sampledImage);
uv = GetSrc(image.coordinate);
derivId = image.coordinate;
}
else if(opdata.op == Op::ImageSampleExplicitLod)
{
OpImageSampleExplicitLod image(it);
@@ -2420,18 +2430,6 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray<ThreadState>
break;
}
// TODO image lod query (from implicit lod)
case Op::ImageQueryLod:
{
RDCERR("Image lod query not yet implemented.");
ShaderVariable var("", 0U, 0U, 0U, 0U);
var.columns = 1;
SetDst(opdata.result, var);
break;
}
// TODO image load/store
case Op::ImageRead:
case Op::ImageWrite:
@@ -93,6 +93,8 @@ static const BuiltinShaderConfig builtinShaders[] = {
rdcspv::ShaderStage::Fragment, FeatureCheck::NoCheck, true},
{BuiltinShader::PixelHistoryPrimIDFS, EmbeddedResource(glsl_pixelhistory_primid_frag),
rdcspv::ShaderStage::Fragment, FeatureCheck::NoCheck, true},
{BuiltinShader::ShaderDebugSampleVS, EmbeddedResource(glsl_shaderdebug_sample_vert),
rdcspv::ShaderStage::Vertex, FeatureCheck::NoCheck, true},
};
RDCCOMPILE_ASSERT(ARRAY_COUNT(builtinShaders) == arraydim<BuiltinShader>(),
@@ -55,6 +55,7 @@ enum class BuiltinShader
TexRemapUInt,
TexRemapSInt,
PixelHistoryPrimIDFS,
ShaderDebugSampleVS,
Count,
};
+68 -5
View File
@@ -755,6 +755,7 @@ public:
break;
}
case rdcspv::Op::ImageQueryLod:
case rdcspv::Op::ImageSampleExplicitLod:
case rdcspv::Op::ImageSampleImplicitLod:
case rdcspv::Op::ImageSampleProjExplicitLod:
@@ -812,7 +813,7 @@ public:
}
if(opcode == rdcspv::Op::ImageSampleImplicitLod ||
opcode == rdcspv::Op::ImageSampleProjImplicitLod)
opcode == rdcspv::Op::ImageSampleProjImplicitLod || opcode == rdcspv::Op::ImageQueryLod)
{
// use grad to sub in for the implicit lod
constParams.useGradOrGatherOffsets = VK_TRUE;
@@ -941,6 +942,14 @@ public:
Unwrap(m_DebugData.PipeLayout), 0, 1,
UnwrapPtr(m_DebugData.DescSet), 0, NULL);
// push uvw/ddx/ddy for the vertex shader
ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_DebugData.PipeLayout), VK_SHADER_STAGE_ALL,
sizeof(Vec4f) * 0, sizeof(Vec3f), &uniformParams.uvw);
ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_DebugData.PipeLayout), VK_SHADER_STAGE_ALL,
sizeof(Vec4f) * 1, sizeof(Vec3f), &uniformParams.ddx);
ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_DebugData.PipeLayout), VK_SHADER_STAGE_ALL,
sizeof(Vec4f) * 2, sizeof(Vec3f), &uniformParams.ddy);
ObjDisp(cmd)->CmdDraw(Unwrap(cmd), 4, 1, 0, 0);
ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd));
@@ -1230,7 +1239,8 @@ private:
const VkPipelineShaderStageCreateInfo shaderStages[2] = {
{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_VERTEX_BIT,
m_pDriver->GetShaderCache()->GetBuiltinModule(BuiltinShader::BlitVS), "main", NULL},
m_pDriver->GetShaderCache()->GetBuiltinModule(BuiltinShader::ShaderDebugSampleVS), "main",
NULL},
{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_FRAGMENT_BIT,
m_DebugData.Module[shaderIndex], "main", &specInfo},
};
@@ -1545,6 +1555,7 @@ private:
editor.CreateEmpty(1, 0);
editor.AddCapability(rdcspv::Capability::Shader);
editor.AddCapability(rdcspv::Capability::ImageQuery);
editor.AddCapability(rdcspv::Capability::Sampled1D);
editor.AddCapability(rdcspv::Capability::SampledBuffer);
@@ -1567,6 +1578,7 @@ private:
rdcspv::Id v3i32 = editor.DeclareType(rdcspv::Vector(rdcspv::scalar<int32_t>(), 3));
rdcspv::Id v2f32 = editor.DeclareType(rdcspv::Vector(rdcspv::scalar<float>(), 2));
rdcspv::Id v3f32 = editor.DeclareType(rdcspv::Vector(rdcspv::scalar<float>(), 3));
rdcspv::Id v4f32 = editor.DeclareType(rdcspv::Vector(rdcspv::scalar<float>(), 4));
// int2[4]
rdcspv::Id a4v2i32 = editor.AddType(
@@ -1734,10 +1746,18 @@ private:
editor.SetName(bindVars[(size_t)ShaderDebugBind::Sampler], "Sampler");
editor.SetName(bindVars[(size_t)ShaderDebugBind::Constants], "CBuffer");
rdcspv::Id uvw_ptr = editor.DeclareType(rdcspv::Pointer(v3f32, rdcspv::StorageClass::Input));
rdcspv::Id input_uvw_var =
editor.AddVariable(rdcspv::OpVariable(uvw_ptr, editor.MakeId(), rdcspv::StorageClass::Input));
editor.AddDecoration(rdcspv::OpDecorate(
input_uvw_var, rdcspv::DecorationParam<rdcspv::Decoration::Location>(0)));
editor.SetName(input_uvw_var, "uvw");
// register the entry point
editor.AddOperation(
editor.Begin(rdcspv::Section::EntryPoints),
rdcspv::OpEntryPoint(rdcspv::ExecutionModel::Fragment, entryId, "main", {outVar}));
editor.AddOperation(editor.Begin(rdcspv::Section::EntryPoints),
rdcspv::OpEntryPoint(rdcspv::ExecutionModel::Fragment, entryId, "main",
{input_uvw_var, outVar}));
editor.AddOperation(editor.Begin(rdcspv::Section::ExecutionMode),
rdcspv::OpExecutionMode(entryId, rdcspv::ExecutionMode::OriginUpperLeft));
@@ -1794,6 +1814,10 @@ private:
editor.SetName(offset_xy, "offset_xy");
editor.SetName(offset_xyz, "offset_xyz");
rdcspv::Id input_uvw = func.add(rdcspv::OpLoad(v3f32, editor.MakeId(), input_uvw_var));
rdcspv::Id input_uv =
func.add(rdcspv::OpVectorShuffle(v2f32, editor.MakeId(), input_uvw, input_uvw, {0, 1}));
// first store NULL data in, so the output is always initialised
rdcspv::Id breakLabel = editor.MakeId();
@@ -1820,6 +1844,16 @@ private:
texel_u, // Buffer - u
};
// only used for QueryLod, so we can ignore MSAA/Buffer
rdcspv::Id input_coord[(uint32_t)ShaderDebugBind::Count] = {
rdcspv::Id(),
input_uv, // 1D - u and array
input_uvw, // 2D - u,v and array
input_uvw, // 3D - u,v,w
rdcspv::Id(), // 2DMS
rdcspv::Id(), // Buffer
};
rdcspv::Id coord[(uint32_t)ShaderDebugBind::Count] = {
rdcspv::Id(),
uv, // 1D - u and array
@@ -1892,6 +1926,35 @@ private:
if(i == (uint32_t)ShaderDebugBind::Buffer || i == (uint32_t)ShaderDebugBind::Tex2DMS)
continue;
{
rdcspv::Op op = rdcspv::Op::ImageQueryLod;
rdcspv::Id label = editor.MakeId();
targets.push_back({(uint32_t)op * 10 + i, label});
cases.add(rdcspv::OpLabel(label));
rdcspv::Id loadedImage =
cases.add(rdcspv::OpLoad(texSampTypes[i], editor.MakeId(), bindVars[i]));
rdcspv::Id loadedSampler =
cases.add(rdcspv::OpLoad(texSampTypes[sampIdx], editor.MakeId(), bindVars[sampIdx]));
rdcspv::Id combined = cases.add(rdcspv::OpSampledImage(
texSampCombinedTypes[i], editor.MakeId(), loadedImage, loadedSampler));
rdcspv::Id sampleResult =
cases.add(rdcspv::OpImageQueryLod(v2f32, editor.MakeId(), combined, input_coord[i]));
sampleResult = cases.add(rdcspv::OpVectorShuffle(v4f32, editor.MakeId(), sampleResult,
sampleResult, {0, 1, 0, 1}));
// if we're sampling from an integer texture the output variable will be the same type.
// Just bitcast the float bits into it, which will come out the other side the right type.
if(uintTex || sintTex)
sampleResult = cases.add(rdcspv::OpBitcast(resultType, editor.MakeId(), sampleResult));
cases.add(rdcspv::OpStore(outVar, sampleResult));
cases.add(rdcspv::OpBranch(breakLabel));
}
for(rdcspv::Op op : {rdcspv::Op::ImageSampleExplicitLod, rdcspv::Op::ImageSampleImplicitLod})
{
rdcspv::Id label = editor.MakeId();
+1
View File
@@ -602,6 +602,7 @@
<None Include="data\glsl\pixelhistory_primid.frag" />
<None Include="data\glsl\quadresolve.frag" />
<None Include="data\glsl\quadwrite.frag" />
<None Include="data\glsl\shaderdebug_sample.vert" />
<None Include="data\glsl\texdisplay.frag" />
<None Include="data\glsl\texremap.frag" />
<None Include="data\glsl\vktext.frag" />
+3
View File
@@ -1069,6 +1069,9 @@
<None Include="data\hlsl\texremap.hlsl">
<Filter>Resources\hlsl</Filter>
</None>
<None Include="data\glsl\shaderdebug_sample.vert">
<Filter>Resources\glsl</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="data\renderdoc.rc">
@@ -1074,6 +1074,12 @@ void main()
Color = textureProj(linearSampledImage, vec3(inpos, 0.5f));
break;
}
case 130:
{
Color.xy = textureQueryLod(linearSampledImage, inpos);
Color.zw = textureQueryLod(linearSampledImage, vec2(1.0f, 1.0f)/inpos);
break;
}
default: break;
}
}