Add tests for separate debug info on D3D + Vulkan, and embedding

This commit is contained in:
baldurk committed 2026-10-26 11:47:28 +00:00
1 parent 65b29ca9b4
commit 3ea44b8511
32 files changed
+696 -113

No files matched your search

+1
View File
@@ -166,6 +166,7 @@ set(VULKAN_SRC
vk/vk_simple_triangle.cpp
vk/vk_spec_constants.cpp
vk/vk_spirv_13_shaders.cpp
vk/vk_stripped_shaders.cpp
vk/vk_subgroup_zoo.cpp
vk/vk_structured_buffer_nested.cpp
vk/vk_sync2.cpp
@@ -272,8 +272,9 @@ void main(uint3 threadID : SV_DispatchThreadID)
ID3DBlobPtr vsblob = Compile(D3DDefaultVertex, "main", "vs_4_0");
// can't skip optimising and still have the extensions work, sadly
ID3DBlobPtr psblob = Compile(ags_header + BaryCentricPixel, "main", "ps_5_0", false);
ID3DBlobPtr csblob = Compile(ags_header + MaxCompute, "main", "cs_5_0", false);
ID3DBlobPtr psblob =
Compile(ags_header + BaryCentricPixel, "main", "ps_5_0", CompileOptionFlags::None);
ID3DBlobPtr csblob = Compile(ags_header + MaxCompute, "main", "cs_5_0", CompileOptionFlags::None);
CreateDefaultInputLayout(vsblob);
+1 -1
View File
@@ -163,7 +163,7 @@ void main(uint3 gid : SV_GroupThreadID)
ID3D11UnorderedAccessViewPtr inUAV = MakeUAV(inBuf);
ID3D11UnorderedAccessViewPtr outUAV = MakeUAV(outBuf);
ID3D11ComputeShaderPtr shad = CreateCS(Compile(comp, "main", "cs_5_0", true));
ID3D11ComputeShaderPtr shad = CreateCS(Compile(comp, "main", "cs_5_0"));
int cbufferdata[4];
memset(cbufferdata, 0, sizeof(cbufferdata));
@@ -1072,8 +1072,9 @@ float4 main(v2f IN, uint samp : SV_SampleIndex) : SV_Target0
vsblob->GetBufferSize(), &layout));
ID3D11VertexShaderPtr vs = CreateVS(vsblob);
ID3D11PixelShaderPtr ps = CreatePS(Compile(common + pixel, "main", "ps_5_0", true));
ID3D11PixelShaderPtr psopt = CreatePS(Compile(common + pixel, "main", "ps_5_0", false));
ID3D11PixelShaderPtr ps = CreatePS(Compile(common + pixel, "main", "ps_5_0"));
ID3D11PixelShaderPtr psopt =
CreatePS(Compile(common + pixel, "main", "ps_5_0", CompileOptionFlags::None));
ID3D11PixelShaderPtr flowps = CreatePS(Compile(common + flowPixel, "main", "ps_5_0"));
static const uint32_t texDim = AlignUp(numTests, 64U) * 4;
@@ -35,23 +35,45 @@ RD_TEST(D3D11_Stripped_Shaders, D3D11GraphicsTest)
if(!Init())
return 3;
ID3DBlobPtr vsblob = Compile(D3DDefaultVertex, "main", "vs_5_0");
ID3DBlobPtr psblob = Compile(D3DDefaultPixel, "main", "ps_5_0");
MakeDir((GetCWD() + "/tmp/D3D11_Stripped_Shaders").c_str());
WriteBlob(GetCWD() + "tmp/D3D11_Stripped_Shaders/shader_debug.vs", vsblob, false);
WriteBlob(GetCWD() + "tmp/D3D11_Stripped_Shaders/shader_debug.ps", psblob, true);
// several variables:
//
// legacy whole unstripped blob, or dxc-style just pdb
// (for dxc-style) manual named or auto-named
// (for legacy-style) lz4 compressed or not
// (for legacy-style) PRIV pointed or SetPrivateData
// absolute or relative path
//
// we don't test all possible combinations but check at least one of each
Strip(vsblob);
Strip(psblob);
SetBlobPath(GetCWD() + "tmp/D3D11_Stripped_Shaders/shader_debug.vs", vsblob);
// PRIV will be set with absolute path
ID3DBlobPtr vsblob =
Compile(D3DDefaultVertex + "\n// shader source // vertex", "main", "vs_5_0",
CompileOptionFlags::SeparateDebugLegacy | CompileOptionFlags::SeparateDebugSetPRIV);
// we'll set relative SetPrivateData path below
ID3DBlobPtr psblob =
Compile(D3DDefaultPixel + "\n// shader source // pixel", "main", "ps_5_0",
CompileOptionFlags::SeparateDebugLegacy | CompileOptionFlags::ManualDebugName |
CompileOptionFlags::LZ4Compress);
CreateDefaultInputLayout(vsblob);
ID3D11VertexShaderPtr vs = CreateVS(vsblob);
ID3D11PixelShaderPtr ps = CreatePS(psblob);
SetBlobPath("lz4#tmp/D3D11_Stripped_Shaders/shader_debug.ps", ps);
SetBlobPath("lz4#shader_ps.dbg", ps);
// manual name will be set absolute in a manual ILDN
ID3DBlobPtr vsblob2 =
Compile(D3DDefaultVertex + "\n// shader source 2 // vertex", "main", "vs_5_0",
CompileOptionFlags::SeparateDebug | CompileOptionFlags::ManualDebugName);
// the fxc-generated ILDN will be relative
ID3DBlobPtr psblob2 = Compile(D3DDefaultPixel + "\n// shader source 2 // pixel", "main",
"ps_5_0", CompileOptionFlags::SeparateDebug);
ID3D11VertexShaderPtr vs2 = CreateVS(vsblob2);
ID3D11PixelShaderPtr ps2 = CreatePS(psblob2);
ID3D11BufferPtr vb = MakeBuffer().Vertex().Data(DefaultTri);
@@ -70,6 +92,17 @@ RD_TEST(D3D11_Stripped_Shaders, D3D11GraphicsTest)
ctx->OMSetRenderTargets(1, &bbRTV.GetInterfacePtr(), NULL);
setMarker("test: shader source");
setMarker("vertex auto absolute");
setMarker("pixel manual relative");
ctx->Draw(3, 0);
ctx->VSSetShader(vs2, NULL, 0);
ctx->PSSetShader(ps2, NULL, 0);
setMarker("test: shader source 2");
setMarker("vertex manual absolute");
setMarker("pixel auto relative");
ctx->Draw(3, 0);
Present();
+85 -2
View File
@@ -51,6 +51,7 @@ struct Capabilities
pD3DCompile dyn_D3DCompile = NULL;
pD3DStripShader dyn_D3DStripShader = NULL;
pD3DSetBlobPart dyn_D3DSetBlobPart = NULL;
pD3DGetBlobPart dyn_D3DGetBlobPart = NULL;
PFN_D3D11_CREATE_DEVICE dyn_D3D11CreateDevice = NULL;
PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN dyn_D3D11CreateDeviceAndSwapChain = NULL;
@@ -94,6 +95,7 @@ void D3D11GraphicsTest::Prepare(int argc, char **argv)
dyn_D3DCompile = (pD3DCompile)GetProcAddress(d3dcompiler, "D3DCompile");
dyn_D3DStripShader = (pD3DStripShader)GetProcAddress(d3dcompiler, "D3DStripShader");
dyn_D3DSetBlobPart = (pD3DSetBlobPart)GetProcAddress(d3dcompiler, "D3DSetBlobPart");
dyn_D3DGetBlobPart = (pD3DGetBlobPart)GetProcAddress(d3dcompiler, "D3DGetBlobPart");
}
HRESULT hr = S_OK;
@@ -136,7 +138,7 @@ void D3D11GraphicsTest::Prepare(int argc, char **argv)
else if(!factory)
Avail = "Couldn't create DXGI factory";
else if(!dyn_D3D11CreateDevice || !dyn_D3D11CreateDeviceAndSwapChain || !dyn_D3DCompile ||
!dyn_D3DStripShader || !dyn_D3DSetBlobPart)
!dyn_D3DStripShader || !dyn_D3DSetBlobPart || !dyn_D3DGetBlobPart)
Avail = "Missing required entry point";
}
@@ -643,13 +645,24 @@ void D3D11GraphicsTest::SetStencilRef(UINT ref)
}
ID3DBlobPtr D3D11GraphicsTest::Compile(std::string src, std::string entry, std::string profile,
bool skipoptimise)
uint32_t compileOptions)
{
const bool skipoptimise = ((compileOptions & CompileOptionFlags::SkipOptimise) != 0);
const bool separateDebugLegacy = ((compileOptions & CompileOptionFlags::SeparateDebugLegacy) != 0);
const bool separateDebugSetPRIV =
((compileOptions & CompileOptionFlags::SeparateDebugSetPRIV) != 0);
const bool separateDebug = ((compileOptions & CompileOptionFlags::SeparateDebug) != 0);
const bool manualDebugName = ((compileOptions & CompileOptionFlags::ManualDebugName) != 0);
const bool lz4Compress = ((compileOptions & CompileOptionFlags::LZ4Compress) != 0);
ID3DBlobPtr blob = NULL;
ID3DBlobPtr error = NULL;
UINT flags = D3DCOMPILE_WARNINGS_ARE_ERRORS | D3DCOMPILE_DEBUG;
if((separateDebugLegacy || separateDebug) && !manualDebugName)
flags |= D3DCOMPILE_DEBUG_NAME_FOR_SOURCE;
if(skipoptimise)
flags |= D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_OPTIMIZATION_LEVEL0;
else
@@ -668,6 +681,76 @@ ID3DBlobPtr D3D11GraphicsTest::Compile(std::string src, std::string entry, std::
return NULL;
}
if(separateDebugLegacy || separateDebug)
{
std::string debugName;
if(manualDebugName)
{
debugName = "shader_" + profile.substr(0, 2) + ".dbg";
}
else
{
ID3DBlobPtr nameBlob;
LPVOID bufferPointer = blob->GetBufferPointer();
hr = dyn_D3DGetBlobPart(bufferPointer, blob->GetBufferSize(), D3D_BLOB_DEBUG_NAME, 0,
&nameBlob);
if(SUCCEEDED(hr))
{
const uint16_t *flags_len = (const uint16_t *)nameBlob->GetBufferPointer();
const char *name_str = (const char *)(flags_len + 2);
debugName.assign(name_str, flags_len[1]);
}
else
{
TEST_ERROR("Couldn't get automatic name");
debugName = "shader_" + profile.substr(0, 2) + ".dbg";
}
}
std::string path = tmpPath + "/" + debugName;
if(separateDebug)
{
ID3DBlobPtr debugBlob;
dyn_D3DGetBlobPart(blob->GetBufferPointer(), blob->GetBufferSize(), D3D_BLOB_PDB, 0,
&debugBlob);
WriteBlob(path, debugBlob, lz4Compress);
if(manualDebugName)
{
std::string nameBlob = path;
// pad the blob to multiple of 4
nameBlob.resize((path.size() + 0x3) & ~0x3);
nameBlob.insert(0, 4, '\0');
nameBlob[2] += path.size() & 0xff;
if(path.size() > 255)
TEST_ERROR("tmp path is too long!");
ID3DBlobPtr newBlob;
dyn_D3DSetBlobPart(blob->GetBufferPointer(), blob->GetBufferSize(), D3D_BLOB_DEBUG_NAME, 0,
nameBlob.c_str(), nameBlob.size(), &newBlob);
blob = newBlob;
}
}
else if(separateDebugLegacy)
{
WriteBlob(path, blob, lz4Compress);
if(separateDebugSetPRIV)
SetBlobPath(path, blob);
}
Strip(blob);
}
return blob;
}
+18 -11
View File
@@ -29,16 +29,6 @@
#include "dx/official/dxgi.h"
#include "d3d11_helpers.h"
#include "dx/official/d3dcompiler.h"
typedef HRESULT(WINAPI *pD3DStripShader)(_In_reads_bytes_(BytecodeLength) LPCVOID pShaderBytecode,
_In_ SIZE_T BytecodeLength, _In_ UINT uStripFlags,
_Out_ ID3DBlob **ppStrippedBlob);
typedef HRESULT(WINAPI *pD3DSetBlobPart)(_In_reads_bytes_(SrcDataSize) LPCVOID pSrcData,
_In_ SIZE_T SrcDataSize, _In_ D3D_BLOB_PART Part,
_In_ UINT Flags, _In_reads_bytes_(PartSize) LPCVOID pPart,
_In_ SIZE_T PartSize, _Out_ ID3DBlob **ppNewShader);
struct Win32Window;
struct D3D11GraphicsTest : public GraphicsTest
@@ -74,8 +64,25 @@ struct D3D11GraphicsTest : public GraphicsTest
BufUAVType = 0xf00,
};
enum CompileOptionFlags
{
None = 0,
SkipOptimise = 1 << 0,
// the legacy path, where we write the unstripped blob somewhere and set a path either via PRIV
// name or SetPrivateData
SeparateDebugLegacy = 1 << 1,
SeparateDebugSetPRIV = 1 << 2,
// the 'new' path which is still manual but matches dxc's behaviour, where we pull out the PDB and set an ILDN name
SeparateDebug = 1 << 3,
// don't use the auto-generated name for a debug file, name it custom shader_Xs.dbg (so only one
// per stage per demo allowed)
ManualDebugName = 1 << 4,
// only possible for SeparateDebugLegacy and ManualDebugName, lz4 compress the resulting blob
LZ4Compress = 1 << 5,
};
ID3DBlobPtr Compile(std::string src, std::string entry, std::string profile,
bool skipoptimise = true);
uint32_t compileOptions = CompileOptionFlags::SkipOptimise);
void Strip(ID3DBlobPtr &ptr);
void WriteBlob(std::string name, ID3DBlobPtr blob, bool compress);
@@ -198,8 +198,8 @@ void main(uint3 inGTid : SV_GroupThreadID)
compsizes[i].x, compsizes[i].y, compsizes[i].z);
comppipe_name[i] = fmt::format("{}x{}x{}", compsizes[i].x, compsizes[i].y, compsizes[i].z);
testShaders[i] = CreateCS(Compile(defines + sizedefine + testShader, "main", "cs_5_0", true));
perfShaders[i] = CreateCS(Compile(defines + sizedefine + perfShader, "main", "cs_5_0", true));
testShaders[i] = CreateCS(Compile(defines + sizedefine + testShader, "main", "cs_5_0"));
perfShaders[i] = CreateCS(Compile(defines + sizedefine + perfShader, "main", "cs_5_0"));
}
while(Running())
@@ -0,0 +1,102 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2023-2026 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.
******************************************************************************/
#include "d3d12_test.h"
RD_TEST(D3D12_Stripped_Shaders, D3D12GraphicsTest)
{
static constexpr const char *Description =
"Tests shaders with their debug/reflection info stripped out and stored in separate blobs.";
void Prepare(int argc, char **argv)
{
D3D12GraphicsTest::Prepare(argc, argv);
if(!Avail.empty())
return;
if(!m_DXILSupport)
Avail = "DXIL can't be compiled";
}
int main()
{
// initialise, create window, create device, etc
if(!Init())
return 3;
MakeDir((GetCWD() + "/tmp/D3D12_Stripped_Shaders").c_str());
// only a couple of variables:
//
// auto-named or manual named
// absolute or relative path
// manual debug name will be absolute
ID3DBlobPtr vsblob =
Compile(D3DDefaultVertex + "\n// shader source // vertex", "main", "vs_6_0",
CompileOptionFlags::SeparateDebug | CompileOptionFlags::ManualDebugName);
// auto name will be relative
ID3DBlobPtr psblob = Compile(D3DDefaultPixel + "\n// shader source // pixel", "main", "ps_6_0",
CompileOptionFlags::SeparateDebug);
ID3D12PipelineStatePtr pso = MakePSO().RootSig(DefaultTriSig).InputLayout().VS(vsblob).PS(psblob);
while(Running())
{
ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer();
Reset(cmd);
ID3D12ResourcePtr bb = StartUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET);
ClearRenderTargetView(cmd, BBRTV, {0.2f, 0.2f, 0.2f, 1.0f});
cmd->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
IASetVertexBuffer(cmd, DefaultTriVB, sizeof(DefaultA2V), 0);
cmd->SetPipelineState(pso);
cmd->SetGraphicsRootSignature(DefaultTriSig);
SetMainWindowViewScissor(cmd);
OMSetRenderTargets(cmd, {BBRTV}, {});
setMarker(cmd, "test: shader source");
setMarker(cmd, "vertex manual absolute");
setMarker(cmd, "pixel auto relative");
cmd->DrawInstanced(3, 1, 0, 0);
FinishUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET);
cmd->Close();
SubmitAndPresent({cmd});
}
return 0;
}
};
REGISTER_TEST();
+40 -15
View File
@@ -52,6 +52,7 @@ bool d3d12on7 = false;
pD3DCompile dyn_D3DCompile = NULL;
pD3DStripShader dyn_D3DStripShader = NULL;
pD3DSetBlobPart dyn_D3DSetBlobPart = NULL;
pD3DGetBlobPart dyn_D3DGetBlobPart = NULL;
pD3DCreateBlob dyn_CreateBlob = NULL;
PFN_D3D12_CREATE_DEVICE dyn_D3D12CreateDevice = NULL;
@@ -382,6 +383,7 @@ void D3D12GraphicsTest::Prepare(int argc, char **argv)
dyn_D3DCompile = (pD3DCompile)GetProcAddress(d3dcompiler, "D3DCompile");
dyn_D3DStripShader = (pD3DStripShader)GetProcAddress(d3dcompiler, "D3DStripShader");
dyn_D3DSetBlobPart = (pD3DSetBlobPart)GetProcAddress(d3dcompiler, "D3DSetBlobPart");
dyn_D3DGetBlobPart = (pD3DGetBlobPart)GetProcAddress(d3dcompiler, "D3DGetBlobPart");
dyn_CreateBlob = (pD3DCreateBlob)GetProcAddress(d3dcompiler, "D3DCreateBlob");
}
@@ -441,7 +443,7 @@ void D3D12GraphicsTest::Prepare(int argc, char **argv)
else if(!factory)
Avail = "Couldn't create DXGI factory";
else if(!dyn_D3D12CreateDevice || !dyn_D3DCompile || !dyn_D3DStripShader || !dyn_D3DSetBlobPart ||
!dyn_CreateBlob)
!dyn_D3DGetBlobPart || !dyn_CreateBlob)
Avail = "Missing required entry point";
else if(!dyn_serializeRootSig && !dyn_serializeRootSigOld)
Avail = "Missing required root signature serialize entry point";
@@ -1441,9 +1443,10 @@ ID3DBlobPtr D3D12GraphicsTest::Compile(std::string src, std::string entry, std::
uint32_t compileOptions)
{
ID3DBlobPtr blob = NULL;
bool skipoptimise = ((compileOptions & CompileOptionFlags::SkipOptimise) != 0);
bool enable16BitTypes = ((compileOptions & CompileOptionFlags::Enable16BitTypes) != 0);
bool separateDebug = ((compileOptions & CompileOptionFlags::SeparateDebug) != 0);
const bool skipoptimise = ((compileOptions & CompileOptionFlags::SkipOptimise) != 0);
const bool enable16BitTypes = ((compileOptions & CompileOptionFlags::Enable16BitTypes) != 0);
const bool separateDebug = ((compileOptions & CompileOptionFlags::SeparateDebug) != 0);
const bool manualDebugName = ((compileOptions & CompileOptionFlags::ManualDebugName) != 0);
if(profile[3] >= '6')
{
@@ -1516,6 +1519,10 @@ ID3DBlobPtr D3D12GraphicsTest::Compile(std::string src, std::string entry, std::
argStorage.push_back(L"-select-validator internal");
}
// use source for debug name so we can have just a comment and get different debug info if we want
if(!manualDebugName)
argStorage.push_back(L"-Zss");
// Must be the final option
argStorage.push_back(L"-Qembed_debug");
@@ -1529,6 +1536,8 @@ ID3DBlobPtr D3D12GraphicsTest::Compile(std::string src, std::string entry, std::
IDxcOperationResultPtr result;
HRESULT hrStatus = E_NOINTERFACE;
std::string debugBlobPath;
if(separateDebug)
{
IDxcCompiler2Ptr compiler2 = compiler;
@@ -1554,20 +1563,16 @@ ID3DBlobPtr D3D12GraphicsTest::Compile(std::string src, std::string entry, std::
CoTaskMemFree(debugBlobWideName);
}
if(manualDebugName)
{
debugBlobName = "shader_" + profile.substr(0, 2) + ".dbg";
}
if(debugBlob)
{
std::string path = GetExecutableName();
path.erase(path.find_last_of("/\\"));
path += "/tmp/";
MakeDir(path.c_str());
path += demoName;
path += "/";
MakeDir(path.c_str());
path += "dxcDebugBlobs/";
MakeDir(path.c_str());
debugBlobPath = tmpPath + "/" + debugBlobName;
WriteBlob(path + debugBlobName, debugBlob->GetBufferPointer(), debugBlob->GetBufferSize(),
false);
WriteBlob(debugBlobPath, debugBlob->GetBufferPointer(), debugBlob->GetBufferSize(), false);
}
if(result)
@@ -1629,6 +1634,26 @@ ID3DBlobPtr D3D12GraphicsTest::Compile(std::string src, std::string entry, std::
TEST_ERROR("No compilation result found from DXC compile: %x", hr);
}
}
if(manualDebugName)
{
std::string nameBlob = debugBlobPath;
// pad the blob to multiple of 4
nameBlob.resize((debugBlobPath.size() + 0x3) & ~0x3);
nameBlob.insert(0, 4, '\0');
nameBlob[2] += debugBlobPath.size() & 0xff;
if(debugBlobPath.size() > 255)
TEST_ERROR("tmp path is too long!");
ID3DBlobPtr newBlob;
hr = dyn_D3DSetBlobPart(blob->GetBufferPointer(), blob->GetBufferSize(), D3D_BLOB_DEBUG_NAME,
0, nameBlob.c_str(), nameBlob.size(), &newBlob);
blob = newBlob;
}
}
else
{
+1 -11
View File
@@ -30,17 +30,6 @@
#include "dx/official/dxgi.h"
#include "d3d12_helpers.h"
#include "dx/official/d3dcompiler.h"
typedef HRESULT(WINAPI *pD3DStripShader)(_In_reads_bytes_(BytecodeLength) LPCVOID pShaderBytecode,
_In_ SIZE_T BytecodeLength, _In_ UINT uStripFlags,
_Out_ ID3DBlob **ppStrippedBlob);
typedef HRESULT(WINAPI *pD3DSetBlobPart)(_In_reads_bytes_(SrcDataSize) LPCVOID pSrcData,
_In_ SIZE_T SrcDataSize, _In_ D3D_BLOB_PART Part,
_In_ UINT Flags, _In_reads_bytes_(PartSize) LPCVOID pPart,
_In_ SIZE_T PartSize, _Out_ ID3DBlob **ppNewShader);
typedef HRESULT(WINAPI *pD3DCreateBlob)(SIZE_T Size, ID3DBlob **ppBlob);
struct Win32Window;
struct D3D12GraphicsTest : public GraphicsTest
@@ -83,6 +72,7 @@ struct D3D12GraphicsTest : public GraphicsTest
SkipOptimise = 1 << 0,
Enable16BitTypes = 1 << 1,
SeparateDebug = 1 << 2,
ManualDebugName = 1 << 3,
};
ID3DBlobPtr Compile(std::string src, std::string entry, std::string profile,
+2
View File
@@ -214,6 +214,7 @@
<ClCompile Include="d3d12\d3d12_sharing.cpp" />
<ClCompile Include="d3d12\d3d12_simple_dispatch.cpp" />
<ClCompile Include="d3d12\d3d12_simple_triangle.cpp" />
<ClCompile Include="d3d12\d3d12_stripped_shaders.cpp" />
<ClCompile Include="d3d12\d3d12_subgroup_zoo.cpp" />
<ClCompile Include="d3d12\d3d12_swapchain_zoo.cpp" />
<ClCompile Include="d3d12\d3d12_template.cpp" />
@@ -348,6 +349,7 @@
<ClCompile Include="vk\vk_shader_printf.cpp" />
<ClCompile Include="vk\vk_spec_constants.cpp" />
<ClCompile Include="vk\vk_spirv_13_shaders.cpp" />
<ClCompile Include="vk\vk_stripped_shaders.cpp" />
<ClCompile Include="vk\vk_subgroup_zoo.cpp" />
<ClCompile Include="vk\vk_sync2.cpp" />
<ClCompile Include="vk\vk_template.cpp" />
+6
View File
@@ -769,6 +769,12 @@
<ClCompile Include="vk\vk_device_address_commands.cpp">
<Filter>Vulkan\demos</Filter>
</ClCompile>
<ClCompile Include="d3d12\d3d12_stripped_shaders.cpp">
<Filter>D3D12\demos</Filter>
</ClCompile>
<ClCompile Include="vk\vk_stripped_shaders.cpp">
<Filter>Vulkan\demos</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="D3D11">
+14
View File
@@ -29,10 +29,24 @@
#include <vector>
#include "dx/official/dxgi1_4.h"
#include "dx/official/d3dcompiler.h"
extern std::string D3DFullscreenQuadVertex;
extern std::string D3DDefaultVertex;
extern std::string D3DDefaultPixel;
typedef HRESULT(WINAPI *pD3DStripShader)(_In_reads_bytes_(BytecodeLength) LPCVOID pShaderBytecode,
_In_ SIZE_T BytecodeLength, _In_ UINT uStripFlags,
_Out_ ID3DBlob **ppStrippedBlob);
typedef HRESULT(WINAPI *pD3DSetBlobPart)(_In_reads_bytes_(SrcDataSize) LPCVOID pSrcData,
_In_ SIZE_T SrcDataSize, _In_ D3D_BLOB_PART Part,
_In_ UINT Flags, _In_reads_bytes_(PartSize) LPCVOID pPart,
_In_ SIZE_T PartSize, _Out_ ID3DBlob **ppNewShader);
typedef HRESULT(WINAPI *pD3DGetBlobPart)(_In_reads_bytes_(SrcDataSize) LPCVOID pSrcData,
_In_ SIZE_T SrcDataSize, _In_ D3D_BLOB_PART Part,
_In_ UINT Flags, _Out_ ID3DBlob **ppPart);
typedef HRESULT(WINAPI *pD3DCreateBlob)(SIZE_T Size, ID3DBlob **ppBlob);
#define COM_SMARTPTR(classname) _COM_SMARTPTR_TYPEDEF(classname, __uuidof(classname))
COM_SMARTPTR(IDXGISwapChain);
+1 -1
View File
@@ -691,8 +691,8 @@ Usage: %s Test_Name [test_options]
if(testchoice == name)
{
TEST_LOG("Running '%s'", test.Name);
test.test->Prepare(argc, argv);
test.test->SetName(test.Name);
test.test->Prepare(argc, argv);
if(!test.IsAvailable())
{
+22 -3
View File
@@ -284,7 +284,8 @@ bool SpvCompilationSupported()
std::vector<uint32_t> CompileShaderToSpv(const char *demo_name, const std::string &source_text,
SPIRVTarget target, ShaderLang lang, ShaderStage stage,
const char *entry_point,
const std::map<std::string, std::string> &macros)
const std::map<std::string, std::string> &macros,
bool debug_info)
{
std::vector<uint32_t> ret;
@@ -303,7 +304,9 @@ std::vector<uint32_t> CompileShaderToSpv(const char *demo_name, const std::strin
if(externalCompiler == "glslc")
{
command_line = "glslc" EXECUTABLE_SUFFIX " -g -O0";
command_line = "glslc" EXECUTABLE_SUFFIX;
if(debug_info)
command_line += " -g -O0";
command_line += " -fentry-point=";
command_line += entry_point;
@@ -349,7 +352,9 @@ std::vector<uint32_t> CompileShaderToSpv(const char *demo_name, const std::strin
}
else if(externalCompiler == "glslangValidator")
{
command_line = "glslangValidator" EXECUTABLE_SUFFIX " -g ";
command_line = "glslangValidator" EXECUTABLE_SUFFIX;
if(debug_info)
command_line += " -g ";
command_line += " --entry-point ";
command_line += entry_point;
@@ -458,6 +463,11 @@ void GraphicsTest::Prepare(int argc, char **argv)
if(dataRoot.empty())
dataRoot = GetCWD() + "/data/demos/";
tmpPath = GetExecutableName();
tmpPath.erase(tmpPath.find_last_of("/\\"));
tmpPath += "/tmp";
MakeDir(tmpPath.c_str());
// parse parameters
for(int i = 0; i < argc; i++)
{
@@ -477,6 +487,11 @@ void GraphicsTest::Prepare(int argc, char **argv)
logFile = fopen(argv[i + 1], "w");
}
if(i + 1 < argc && !strcmp(argv[i], "--tmp"))
{
tmpPath = argv[i + 1];
}
if(i + 1 < argc && (!strcmp(argv[i], "--width") || !strcmp(argv[i], "-w")))
{
screenWidth = atoi(argv[i + 1]);
@@ -506,6 +521,10 @@ void GraphicsTest::Prepare(int argc, char **argv)
}
}
tmpPath += "/";
tmpPath += demoName;
MakeDir(tmpPath.c_str());
pRENDERDOC_GetAPI RENDERDOC_GetAPI = NULL;
#if defined(WIN32)
+4 -1
View File
@@ -87,7 +87,8 @@ bool SpvCompilationSupported();
std::vector<uint32_t> CompileShaderToSpv(const char *demo_name, const std::string &source_text,
SPIRVTarget target, ShaderLang lang, ShaderStage stage,
const char *entry_point,
const std::map<std::string, std::string> &macros = {});
const std::map<std::string, std::string> &macros = {},
bool debug_info = true);
struct Vec2f
{
@@ -224,6 +225,8 @@ struct GraphicsTest
RENDERDOC_API_1_7_0 *rdoc = NULL;
std::string tmpPath;
// shared parameters
static int maxFrameCount;
static std::string dataRoot;
@@ -0,0 +1,97 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2023-2026 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.
******************************************************************************/
#include "vk_test.h"
RD_TEST(VK_Stripped_Shaders, VulkanGraphicsTest)
{
static constexpr const char *Description =
"Tests shaders with their debug/reflection info stripped out and stored in separate blobs.";
int main()
{
// initialise, create window, create context, etc
if(!Init())
return 3;
vkh::GraphicsPipelineCreateInfo pipeCreateInfo;
VkPipelineLayout layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo());
pipeCreateInfo.layout = layout;
pipeCreateInfo.renderPass = mainWindow->rp;
pipeCreateInfo.vertexInputState.vertexBindingDescriptions = {vkh::vertexBind(0, DefaultA2V)};
pipeCreateInfo.vertexInputState.vertexAttributeDescriptions = {
vkh::vertexAttr(0, 0, DefaultA2V, pos),
vkh::vertexAttr(1, 0, DefaultA2V, col),
vkh::vertexAttr(2, 0, DefaultA2V, uv),
};
pipeCreateInfo.stages = {
CompileShaderModule(VKDefaultVertex + "\n// shader source // vertex", ShaderLang::glsl,
ShaderStage::vert, "main", {}, SPIRVTarget::vulkan,
CompileOptionFlags::SeparateDebug),
CompileShaderModule(VKDefaultPixel + "\n// shader source // pixel", ShaderLang::glsl,
ShaderStage::frag, "main", {}, SPIRVTarget::vulkan,
CompileOptionFlags::SeparateDebug | CompileOptionFlags::RelativeDebugName),
};
VkPipeline pipe = createGraphicsPipeline(pipeCreateInfo);
while(Running())
{
VkCommandBuffer cmd = GetCommandBuffer();
vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo());
VkImage swapimg = StartUsingBackbuffer(cmd);
vkh::cmdClearImage(cmd, swapimg, vkh::ClearColorValue(0.2f, 0.2f, 0.2f, 1.0f));
vkCmdBeginRenderPass(cmd, mainWindow->beginRP(), VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
mainWindow->setViewScissor(cmd);
vkh::cmdBindVertexBuffers(cmd, {DefaultTriVB.buffer});
setMarker(cmd, "test: shader source");
setMarker(cmd, "vertex manual absolute");
setMarker(cmd, "pixel manual relative");
vkCmdDraw(cmd, 3, 1, 0, 0);
vkCmdEndRenderPass(cmd);
FinishUsingBackbuffer(cmd);
vkEndCommandBuffer(cmd);
SubmitAndPresent({cmd});
}
return 0;
}
};
REGISTER_TEST();
+46 -1
View File
@@ -1009,18 +1009,63 @@ VkPipelineShaderStageCreateInfo VulkanGraphicsTest::LoadShaderModule(const std::
VkPipelineShaderStageCreateInfo VulkanGraphicsTest::CompileShaderModule(
const std::string &source_text, ShaderLang lang, ShaderStage stage, const char *entry_point,
const std::map<std::string, std::string> &macros, SPIRVTarget target)
const std::map<std::string, std::string> &macros, SPIRVTarget target, uint32_t compileOptions)
{
VkShaderModule ret = VK_NULL_HANDLE;
const bool separateDebug = ((compileOptions & CompileOptionFlags::SeparateDebug) != 0);
const bool relativeDebugName = ((compileOptions & CompileOptionFlags::RelativeDebugName) != 0);
std::vector<uint32_t> spirv =
::CompileShaderToSpv(demoName, source_text, target, lang, stage, entry_point, macros);
if(spirv.empty())
return {};
std::string path;
if(separateDebug)
{
path = tmpPath + "/";
std::string filenames[] = {
"shader_vs.dbg", "shader_hs.dbg", "shader_ds.dbg", "shader_gs.dbg",
"shader_ps.dbg", "shader_cs.dbg", "shader_ms.dbg", "shader_as.dbg",
};
path += filenames[(int)stage];
FILE *f = fopen(path.c_str(), "wb");
if(f)
{
fwrite(spirv.data(), 1, spirv.size() * sizeof(uint32_t), f);
fclose(f);
}
spirv =
::CompileShaderToSpv(demoName, source_text, target, lang, stage, entry_point, macros, false);
}
CHECK_VKR(vkCreateShaderModule(device, vkh::ShaderModuleCreateInfo(spirv), NULL, &ret));
if(relativeDebugName)
{
path.erase(0, path.find_last_of("/\\") + 1);
// keep the demo name so we don't have to set up tons of search paths
path = std::string(demoName) + "/" + path;
}
if(vkSetDebugUtilsObjectTagEXT)
{
VkDebugUtilsObjectTagInfoEXT info = {};
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT;
info.objectType = VK_OBJECT_TYPE_SHADER_MODULE;
info.objectHandle = (uint64_t)ret;
info.pTag = path.c_str();
info.tagSize = path.size();
info.tagName = RENDERDOC_ShaderDebugMagicValue_truncated;
vkSetDebugUtilsObjectTagEXT(device, &info);
}
shaders.push_back(ret);
VkShaderStageFlagBits vkstage[] = {
+8 -1
View File
@@ -194,6 +194,13 @@ struct VulkanGraphicsTest : public GraphicsTest
{
static const TestAPI API = TestAPI::Vulkan;
enum CompileOptionFlags
{
None = 0,
SeparateDebug = 1 << 0,
RelativeDebugName = 1 << 1,
};
VulkanGraphicsTest();
void Prepare(int argc, char **argv);
@@ -222,7 +229,7 @@ struct VulkanGraphicsTest : public GraphicsTest
VkPipelineShaderStageCreateInfo CompileShaderModule(
const std::string &source_text, ShaderLang lang, ShaderStage stage,
const char *entry_point = "main", const std::map<std::string, std::string> &macros = {},
SPIRVTarget target = SPIRVTarget::vulkan);
SPIRVTarget target = SPIRVTarget::vulkan, uint32_t compileOptions = CompileOptionFlags::None);
VkCommandBuffer GetCommandBuffer(VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
VulkanWindow *window = NULL);
+1
View File
@@ -14,3 +14,4 @@ from .shared.Pixel_History import *
from .shared.Workgroup_Zoo import *
from .shared.Groupshared import *
from .shared.Annotations import *
from .shared.Stripped_Shaders import *
+15 -22
View File
@@ -6,7 +6,7 @@ from . import util
def open_capture(
filename="", cap: rd.CaptureFile | None = None, opts: rd.ReplayOptions | None = None
filename="", opts: rd.ReplayOptions | None = None
):
"""
Opens a capture file and begins a replay.
@@ -21,32 +21,28 @@ def open_capture(
if opts is None:
opts = rd.ReplayOptions()
# Open a capture file handle
own_cap = False
cap = None
api = "Unknown"
result = None
controller = None
if util.get_remote_server() is None:
if cap is None:
own_cap = True
cap = rd.OpenCaptureFile()
cap = rd.OpenCaptureFile()
# Open a particular file
result = cap.OpenFile(filename, '', None)
# Open a particular file
result = cap.OpenFile(filename, '', None)
# Make sure the file opened successfully
if not result:
cap.Shutdown()
raise RuntimeError(f"Couldn't open '{filename}': {result!s}")
# Make sure the file opened successfully
if not result:
cap.Shutdown()
raise RuntimeError(f"Couldn't open '{filename}': {result!s}")
api = cap.DriverName()
api = cap.DriverName()
# Make sure we can replay
if not cap.LocalReplaySupport():
cap.Shutdown()
raise RuntimeError(f"{api} capture cannot be replayed")
# Make sure we can replay
if not cap.LocalReplaySupport():
cap.Shutdown()
raise RuntimeError(f"{api} capture cannot be replayed")
result, controller = cap.OpenCapture(opts, None)
else:
@@ -58,13 +54,10 @@ def open_capture(
if result:
api = util.get_remote_server().remote.DriverName()
if own_cap:
cap.Shutdown()
if not result:
raise RuntimeError(f"Couldn't initialise replay for {api}: {result!s}")
return controller
return cap, controller
def fetch_indices(controller: rd.ReplayController, action: rd.ActionDescription, mesh: rd.MeshFormat, index_offset: int, first_index: int, num_indices: int) -> List[int | None]:
+140
View File
@@ -0,0 +1,140 @@
import rdtest
import shutil
import renderdoc as rd
import re
# Not a real test, re-used by API-specific tests
class Stripped_Shaders(rdtest.TestCase):
internal = True
demos_test_name = None
def get_capture_options(self):
# We don't actually need to set any capture-time options but we'll use this to change the search dir paths
paths = rd.SetConfigSetting("DXBC.Debug.SearchDirPaths")
paths.DeleteChildren()
paths.AddChild(rd.makeSDString("path", rdtest.get_tmp_dir()))
# this won't automatically save and we won't call SaveConfigSettings()
return rd.CaptureOptions()
def check_capture(self):
self.check_debug_symbols(False)
filename = self.retrieve_capture()
embed_path = rdtest.get_tmp_path("embedded.rdc")
shutil.copy(filename, embed_path)
# shut down the controller that is for the old file, to keep it the same
self.controller.Shutdown()
self.controller = None
if self.cap is not None:
self.cap.Shutdown()
self.cap = None
# open the version we're going to embed into
self.cap, self.controller = rdtest.open_capture(embed_path)
assert self.cap is not None
assert len(self.cap.GetPendingDependenciesNicknames()) > 0
# embed the dependencies
assert self.cap.EmbedDependenciesIntoCapture().OK()
self.controller.Shutdown()
self.cap.Shutdown()
# now clear the search paths, this should make at least one fail
rd.SetConfigSetting("DXBC.Debug.SearchDirPaths").DeleteChildren()
self.cap, self.controller = rdtest.open_capture(embed_path)
self.sdfile = self.controller.GetStructuredFile()
# check everything is still OK
self.check_debug_symbols(True)
def check_debug_symbols(self, embedded: bool):
test = self.find_action("test:", 0)
while test is not None:
pix_cfg = self.get_action(test.eventId + 2)
assert pix_cfg is not None
draw = self.get_action(test.eventId + 3)
assert draw is not None
search_text = test.customName.replace("test: ", "")
assert "pixel" in pix_cfg.customName
self.set_event(draw.eventId, False)
pipe = self.controller.GetPipelineState()
stages = [
(1, rd.ShaderStage.Vertex, "vertex", "shader_vs.dbg"),
(2, rd.ShaderStage.Pixel, "pixel", "shader_ps.dbg"),
]
for offs, stage, name, manual_filename in stages:
cfg = self.get_action(test.eventId + offs)
assert cfg is not None
assert name in cfg.customName
refl = pipe.GetShaderReflection(stage)
assert len(refl.debugInfo.files) == 1
src = refl.debugInfo.files[0].contents
assert f"// {search_text} // {name}" in src
log = refl.debugInfo.debugInfoLoadingLog
assert re.match("Found ", log, re.IGNORECASE)
if "auto" in cfg.customName:
assert re.search("[a-f0-9]{32}.pdb", log) is not None
elif "manual" in cfg.customName:
assert f"{manual_filename}'" in log
else:
raise rdtest.TestFailureException(
f"Unexpected {name} config {cfg.customName}"
)
filepath = re.search("Shader filepath '([^']*)'", log)
assert filepath is not None
filepath = filepath[1].replace("\\", "/")
tmp_dir = rdtest.get_tmp_dir().replace("\\", "/")
if "absolute" in cfg.customName:
assert tmp_dir in filepath
assert "File found using filepath" in log
assert "File found in search directory" not in log
assert "File found in recursive directory search" not in log
assert "embedded in the capture using nickname" not in log
elif "relative" in cfg.customName:
assert tmp_dir not in filepath
assert "File found using filepath" not in log
if embedded:
assert "embedded in the capture using nickname" in log
assert "File found in search directory" not in log
assert "File found in recursive directory search" not in log
else:
assert (
"File found in search directory" in log
or "File found in recursive directory search" in log
)
else:
raise rdtest.TestFailureException(
f"Unexpected {name} config {cfg.customName}"
)
rdtest.log.success(f"{name} shader debug info and loading log looks OK")
test = self.find_action("test:", draw.eventId)
rdtest.log.success("All draws had proper shader debug info")
+6 -2
View File
@@ -263,6 +263,7 @@ class TestCase:
self.capture_filename = ""
self.worker_thread = 0
self.controller: rd.ReplayController | None = None
self.cap: rd.CaptureFile | None = None
self.sdfile: rd.SDFile | None = None
self.contexts: List[ScopedContext] = []
self.cur_event = 0
@@ -319,7 +320,7 @@ class TestCase:
if timeout is None:
timeout = util.get_demos_timeout()
return capture.run_and_capture(exe,
self.demos_test_name + " --log " + remote_logfile,
f"{self.demos_test_name} --log {remote_logfile} --tmp {util.get_tmp_dir()}",
self.demos_frame_cap, frame_count=self.demos_frame_count,
captures_expected=self.demos_captures_expected, logfile=logfile,
opts=self.get_capture_options(), timeout=timeout)
@@ -761,7 +762,7 @@ class TestCase:
log.print("Loading capture")
self.controller = analyse.open_capture(self.capture_filename, opts=self.get_replay_options())
self.cap, self.controller = analyse.open_capture(self.capture_filename, opts=self.get_replay_options())
self.sdfile = self.controller.GetStructuredFile()
if not self.validate_eventids(self.controller):
@@ -782,6 +783,9 @@ class TestCase:
else:
self.controller.Shutdown()
if self.cap is not None:
self.cap.Shutdown()
def invoketest(self, debugMode: bool):
start_time = self.get_time()
self.run()
@@ -0,0 +1,6 @@
import rdtest
class D3D11_Stripped_Shaders(rdtest.Stripped_Shaders):
demos_test_name = 'D3D11_Stripped_Shaders'
internal = False
@@ -0,0 +1,6 @@
import rdtest
class D3D12_Stripped_Shaders(rdtest.Stripped_Shaders):
demos_test_name = 'D3D12_Stripped_Shaders'
internal = False
+4 -11
View File
@@ -30,19 +30,12 @@ class GL_Buffer_Updates(rdtest.TestCase):
rdtest.log.success("Draws are all green")
# Open the capture and grab the thumbnail, check that it is all green too (dirty way of verifying we didn't
# grab the thumbnail, check that it is all green too (dirty way of verifying we didn't
# break in-app updates but somehow end up with the right data)
cap = rd.OpenCaptureFile()
if self.cap is None:
raise rdtest.TestFailureException(f"Don't have open capture {self.capture_filename}")
# Open a particular file
result = cap.OpenFile(self.capture_filename, '', None)
# Make sure the file opened successfully
if not result:
cap.Shutdown()
raise rdtest.TestFailureException(f"Couldn't open '{self.capture_filename}': {result!s}")
thumb = cap.GetThumbnail(rd.FileType.PNG, 0)
thumb = self.cap.GetThumbnail(rd.FileType.PNG, 0)
tmp_path = rdtest.get_tmp_path('thumbnail.png')
+5 -13
View File
@@ -21,21 +21,13 @@ class GL_Callstacks(rdtest.TestCase):
return ret
def check_capture(self):
# Need capture access. Rather than trying to keep the original around, we just open a new one
cap = rd.OpenCaptureFile()
if self.cap is None:
raise rdtest.TestFailureException(f"Don't have open capture {self.capture_filename}")
# Open a particular file
result = cap.OpenFile(self.capture_filename, '', None)
# Make sure the file opened successfully
if not result:
cap.Shutdown()
raise rdtest.TestFailureException(f"Couldn't open capture {self.capture_filename} for access: {result!s}")
if not cap.HasCallstacks():
if not self.cap.HasCallstacks():
raise rdtest.TestFailureException("Capture does not report having callstacks")
if not cap.InitResolver(False, resolve_progress):
if not self.cap.InitResolver(False, resolve_progress):
raise rdtest.TestFailureException("Failed to initialise callstack resolver")
action = self.find_action("Draw")
@@ -59,7 +51,7 @@ class GL_Callstacks(rdtest.TestCase):
chunk = sdfile.chunks[event.chunkIndex]
callstack = cap.GetResolve(list(chunk.metadata.callstack))
callstack = self.cap.GetResolve(list(chunk.metadata.callstack))
if len(callstack) < len(expected_funcs):
raise rdtest.TestFailureException(f"Resolved callstack isn't long enough ({len(callstack)} stack frames), expected at least {len(expected_funcs)}")
+3 -1
View File
@@ -436,7 +436,7 @@ class Iter_Test(rdtest.TestCase):
rdtest.log.print(f"Opening '{file.name}'.")
try:
self.controller = rdtest.open_capture(file.path)
self.cap, self.controller = rdtest.open_capture(file.path)
except RuntimeError as err:
rdtest.log.print(f"Skipping. Can't open {file.path}: {err}")
continue
@@ -450,6 +450,8 @@ class Iter_Test(rdtest.TestCase):
rdtest.log.end_section(section_name)
self.controller.Shutdown()
if self.cap is not None:
self.cap.Shutdown()
rdtest.log.success("Iterated all files")
+3 -1
View File
@@ -13,7 +13,7 @@ class Repeat_Load(rdtest.TestCase):
rdtest.log.print(f"Loading for iteration {i + 1}")
try:
controller = rdtest.open_capture(path)
cap, controller = rdtest.open_capture(path)
except RuntimeError as err:
rdtest.log.print(f"Skipping. Can't open {path}: {err}")
return
@@ -31,6 +31,8 @@ class Repeat_Load(rdtest.TestCase):
memory_baseline = memory_usage
controller.Shutdown()
if cap is not None:
cap.Shutdown()
pct_over = 'N/A'
@@ -15,7 +15,7 @@ class VK_Large_Descriptor_Sets(rdtest.TestCase):
memory_before = rd.GetCurrentProcessMemoryUsage()
start_time = self.get_time()
self.controller = rdtest.open_capture(self.capture_filename, opts=self.get_replay_options())
self.cap, self.controller = rdtest.open_capture(self.capture_filename, opts=self.get_replay_options())
duration = self.get_time() - start_time
memory_after = rd.GetCurrentProcessMemoryUsage()
@@ -37,3 +37,5 @@ class VK_Large_Descriptor_Sets(rdtest.TestCase):
rdtest.log.print("Not checking time to load in non-release build")
self.controller.Shutdown()
if self.cap is not None:
self.cap.Shutdown()
@@ -0,0 +1,6 @@
import rdtest
class VK_Stripped_Shaders(rdtest.Stripped_Shaders):
demos_test_name = 'VK_Stripped_Shaders'
internal = False