Add a structure and query for reporting descriptor accesses

This commit is contained in:
baldurk
2024-02-21 17:07:06 +00:00
parent c1d07f6bc3
commit 227842a295
25 changed files with 244 additions and 5 deletions
+2 -1
View File
@@ -412,9 +412,10 @@ TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderChangeStats)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ResourceBindStats)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, SamplerBindStats)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ConstantBindStats)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, Descriptor)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, DescriptorRange)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, Descriptor)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, SamplerDescriptor)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, DescriptorAccess)
TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, Attachment)
TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, BindingElement)
TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, DescriptorBinding)
+103
View File
@@ -25,6 +25,7 @@
#pragma once
#include "apidefs.h"
#include "data_types.h"
#include "rdcarray.h"
#include "shader_types.h"
#include "stringise.h"
@@ -746,6 +747,108 @@ this sampler.
DECLARE_REFLECTION_STRUCT(SamplerDescriptor);
DOCUMENT(R"(The details of a single accessed descriptor as fetched by a shader and which descriptor
in the descriptor store was fetched.
This may be a somewhat conservative access, reported as possible but not actually executed on the
GPU itself.
.. data:: NoShaderBinding
No shader binding corresponds to this descriptor access, it happened directly without going
through any kind of binding.
)");
struct DescriptorAccess
{
DOCUMENT("");
DescriptorAccess() = default;
DescriptorAccess(const DescriptorAccess &) = default;
DescriptorAccess &operator=(const DescriptorAccess &) = default;
bool operator==(const DescriptorAccess &o) const
{
return stage == o.stage && type == o.type && index == o.index &&
arrayElement == o.arrayElement && descriptorStore == o.descriptorStore &&
byteOffset == o.byteOffset && byteSize == o.byteSize;
}
bool operator<(const DescriptorAccess &o) const
{
if(stage != o.stage)
return stage < o.stage;
if(type != o.type)
return type < o.type;
if(index != o.index)
return index < o.index;
if(arrayElement != o.arrayElement)
return arrayElement < o.arrayElement;
if(descriptorStore != o.descriptorStore)
return descriptorStore < o.descriptorStore;
if(byteOffset != o.byteOffset)
return byteOffset < o.byteOffset;
if(byteSize != o.byteSize)
return byteSize < o.byteSize;
return false;
}
DOCUMENT(R"(The shader stage that this descriptor access came from.
:type: ShaderStage
)");
ShaderStage stage = ShaderStage::Count;
DOCUMENT(R"(The type of the descriptor being accessed.
:type: DescriptorType
)");
DescriptorType type = DescriptorType::Unknown;
DOCUMENT(R"(The index within the shader's reflection list corresponding to :data:`type` of the
accessing resource.
If this value is set to :data:`NoShaderBinding` then the shader synthesised a direct access into
descriptor storage without passing through a declared binding.
:type: int
)");
uint16_t index = 0;
static const uint16_t NoShaderBinding = 0xFFFF;
DOCUMENT(R"(For an arrayed resource declared in a shader, the array element used.
:type: int
)");
uint32_t arrayElement = 0;
DOCUMENT(R"(The backing storage of the descriptor.
:type: ResourceId
)");
ResourceId descriptorStore;
DOCUMENT(R"(The offset in bytes to the descriptor in the descriptor store.
:type: int
)");
uint32_t byteOffset = 0;
DOCUMENT(R"(The size in bytes of the descriptor.
:type: int
)");
uint32_t byteSize = 0;
DOCUMENT(R"(For informational purposes, some descriptors that are declared in the shader
interface but are provably unused may still be reported as descriptor accesses. This flag will be
set to ``True`` to indicate that the descriptor was definitely not used.
This flag only states that a descriptor is definitely unused on all paths. If set to ``False`` this
does not necessarily guarantee that the descriptor was accessed on the GPU during execution.
:type: bool
)");
bool staticallyUnused = false;
};
DECLARE_REFLECTION_STRUCT(DescriptorAccess);
DOCUMENT("Information about a single constant buffer binding.");
struct BoundCBuffer
{
+7
View File
@@ -27,6 +27,7 @@
#include <functional>
#include "apidefs.h"
#include "common_pipestate.h"
#include "data_types.h"
#include "rdcarray.h"
#include "replay_enums.h"
@@ -638,6 +639,12 @@ struct DescriptorRange
DescriptorRange(const DescriptorRange &) = default;
DescriptorRange &operator=(const DescriptorRange &) = default;
DescriptorRange(const DescriptorAccess &access)
{
offset = access.byteOffset;
descriptorSize = access.byteSize;
}
DOCUMENT("The offset in the descriptor storage where the descriptor range starts.");
uint32_t offset = 0;
DOCUMENT("The size of each descriptor in the range.");
+7
View File
@@ -588,6 +588,13 @@ Multiple ranges within the store can be queried at once, and are returned in a c
virtual rdcarray<SamplerDescriptor> GetSamplerDescriptors(
ResourceId descriptorStore, const rdcarray<DescriptorRange> &ranges) = 0;
DOCUMENT(R"(Retrieve the descriptor accesses that happened at the current event.
:return: The descriptor accesses.
:rtype: List[DescriptorAccess]
)");
virtual rdcarray<DescriptorAccess> GetDescriptorAccess() = 0;
DOCUMENT(R"(Retrieve the list of possible disassembly targets for :meth:`DisassembleShader`. The
values are implementation dependent but will always include a default target first which is the
native disassembly of the shader. Further options may be available for additional diassembly views
+33 -1
View File
@@ -907,6 +907,38 @@ enum class DescriptorType : uint8_t
DECLARE_REFLECTION_ENUM(DescriptorType);
DOCUMENT("Checks if a descriptor type corresponds to a constant buffer in shader reflection.");
constexpr bool IsConstantBufferDescriptor(DescriptorType type)
{
return type == DescriptorType::ConstantBuffer;
}
DOCUMENT(R"(Checks if a descriptor type corresponds to a sampler in shader reflection. Only dedicated
sampler types are sampler descriptors, combined image/samplers are reported only as read only
resources.
)");
constexpr bool IsSamplerDescriptor(DescriptorType type)
{
return type == DescriptorType::Sampler;
}
DOCUMENT(R"(Checks if a descriptor type corresponds to a read only resource in shader reflection.
Combined image/samplers are reported as read only resources.
)");
constexpr bool IsReadOnlyDescriptor(DescriptorType type)
{
return type == DescriptorType::ImageSampler || type == DescriptorType::Image ||
type == DescriptorType::TypedBuffer;
}
DOCUMENT(R"(Checks if a descriptor type corresponds to a read write resource in shader reflection.
)");
constexpr bool IsReadWriteDescriptor(DescriptorType type)
{
return type == DescriptorType::ReadWriteBuffer || type == DescriptorType::ReadWriteImage ||
type == DescriptorType::ReadWriteTypedBuffer;
}
DOCUMENT3(R"(Annotates a particular built-in input or output from a shader with a special meaning to
the hardware or API.
@@ -2472,7 +2504,7 @@ DOCUMENT(R"(The stage in a pipeline where a shader runs
The mesh shader.
)");
enum class ShaderStage : uint32_t
enum class ShaderStage : uint8_t
{
Vertex = 0,
First = Vertex,
+1
View File
@@ -279,6 +279,7 @@ public:
ret.resize(count);
return ret;
}
rdcarray<DescriptorAccess> GetDescriptorAccess() { return {}; }
DriverInformation GetDriverInfo()
{
DriverInformation ret = {};
+31
View File
@@ -100,6 +100,7 @@ rdcstr DoStringise(const ReplayProxyPacket &el)
STRINGISE_ENUM_NAMED(eReplayProxy_GetDescriptors, "GetDescriptors");
STRINGISE_ENUM_NAMED(eReplayProxy_GetSamplerDescriptors, "GetSamplerDescriptors");
STRINGISE_ENUM_NAMED(eReplayProxy_GetDescriptorAccess, "GetDescriptorAccess");
}
END_ENUM_STRINGISE();
}
@@ -1906,6 +1907,35 @@ rdcarray<SamplerDescriptor> ReplayProxy::GetSamplerDescriptors(ResourceId descri
PROXY_FUNCTION(GetSamplerDescriptors, descriptorStore, ranges);
}
template <typename ParamSerialiser, typename ReturnSerialiser>
rdcarray<DescriptorAccess> ReplayProxy::Proxied_GetDescriptorAccess(ParamSerialiser &paramser,
ReturnSerialiser &retser)
{
const ReplayProxyPacket expectedPacket = eReplayProxy_GetDescriptorAccess;
ReplayProxyPacket packet = eReplayProxy_GetDescriptorAccess;
rdcarray<DescriptorAccess> ret;
{
BEGIN_PARAMS();
END_PARAMS();
}
{
REMOTE_EXECUTION();
if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored)
ret = m_Remote->GetDescriptorAccess();
}
SERIALISE_RETURN(ret);
return ret;
}
rdcarray<DescriptorAccess> ReplayProxy::GetDescriptorAccess()
{
PROXY_FUNCTION(GetDescriptorAccess);
}
template <typename ParamSerialiser, typename ReturnSerialiser>
void ReplayProxy::Proxied_ReplayLog(ParamSerialiser &paramser, ReturnSerialiser &retser,
uint32_t endEventID, ReplayLogType replayType)
@@ -2978,6 +3008,7 @@ bool ReplayProxy::Tick(int type)
case eReplayProxy_SavePipelineState: SavePipelineState(0); break;
case eReplayProxy_GetDescriptors: GetDescriptors(ResourceId(), {}); break;
case eReplayProxy_GetSamplerDescriptors: GetSamplerDescriptors(ResourceId(), {}); break;
case eReplayProxy_GetDescriptorAccess: GetDescriptorAccess(); break;
case eReplayProxy_GetUsage: GetUsage(ResourceId()); break;
case eReplayProxy_GetLiveID: GetLiveID(ResourceId()); break;
case eReplayProxy_GetFrameRecord: GetFrameRecord(); break;
+2
View File
@@ -108,6 +108,7 @@ enum ReplayProxyPacket
eReplayProxy_GetDescriptors,
eReplayProxy_GetSamplerDescriptors,
eReplayProxy_GetDescriptorAccess,
};
DECLARE_REFLECTION_ENUM(ReplayProxyPacket);
@@ -485,6 +486,7 @@ public:
const rdcarray<DescriptorRange> &ranges);
IMPLEMENT_FUNCTION_PROXIED(rdcarray<SamplerDescriptor>, GetSamplerDescriptors,
ResourceId descriptorStore, const rdcarray<DescriptorRange> &ranges);
IMPLEMENT_FUNCTION_PROXIED(rdcarray<DescriptorAccess>, GetDescriptorAccess);
IMPLEMENT_FUNCTION_PROXIED(rdcarray<uint32_t>, GetPassEvents, uint32_t eventId);
+1 -1
View File
@@ -41,7 +41,7 @@ rdcstr InsertSnippetAfterVersion(ShaderType type, const char *source, int len, c
// for unit tests
struct ShaderReflection;
struct ShaderBindpointMapping;
enum class ShaderStage : uint32_t;
enum class ShaderStage : uint8_t;
using ReflectionMaker =
std::function<void(ShaderStage stage, const rdcstr &source, const rdcstr &entryPoint,
ShaderReflection &refl, ShaderBindpointMapping &mapping)>;
+5
View File
@@ -1982,6 +1982,11 @@ rdcarray<SamplerDescriptor> D3D11Replay::GetSamplerDescriptors(ResourceId descri
return ret;
}
rdcarray<DescriptorAccess> D3D11Replay::GetDescriptorAccess()
{
return {};
}
RDResult D3D11Replay::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
{
return m_pDevice->ReadLogInitialisation(rdc, storeStructuredBuffers);
+1
View File
@@ -186,6 +186,7 @@ public:
const rdcarray<DescriptorRange> &ranges);
rdcarray<SamplerDescriptor> GetSamplerDescriptors(ResourceId descriptorStore,
const rdcarray<DescriptorRange> &ranges);
rdcarray<DescriptorAccess> GetDescriptorAccess();
void FreeTargetResource(ResourceId id);
void FreeCustomShader(ResourceId id);
+5
View File
@@ -2427,6 +2427,11 @@ rdcarray<SamplerDescriptor> D3D12Replay::GetSamplerDescriptors(ResourceId descri
return ret;
}
rdcarray<DescriptorAccess> D3D12Replay::GetDescriptorAccess()
{
return {};
}
void D3D12Replay::RenderHighlightBox(float w, float h, float scale)
{
OutputWindow &outw = m_OutputWindows[m_CurrentOutputWindow];
+1
View File
@@ -142,6 +142,7 @@ public:
const rdcarray<DescriptorRange> &ranges);
rdcarray<SamplerDescriptor> GetSamplerDescriptors(ResourceId descriptorStore,
const rdcarray<DescriptorRange> &ranges);
rdcarray<DescriptorAccess> GetDescriptorAccess();
void FreeTargetResource(ResourceId id);
void FreeCustomShader(ResourceId id);
+5
View File
@@ -2574,6 +2574,11 @@ rdcarray<SamplerDescriptor> GLReplay::GetSamplerDescriptors(ResourceId descripto
return ret;
}
rdcarray<DescriptorAccess> GLReplay::GetDescriptorAccess()
{
return {};
}
void GLReplay::OpenGLFillCBufferVariables(ResourceId shader, GLuint prog, bool bufferBacked,
rdcstr prefix, const rdcarray<ShaderConstant> &variables,
rdcarray<ShaderVariable> &outvars,
+1
View File
@@ -164,6 +164,7 @@ public:
const rdcarray<DescriptorRange> &ranges);
rdcarray<SamplerDescriptor> GetSamplerDescriptors(ResourceId descriptorStore,
const rdcarray<DescriptorRange> &ranges);
rdcarray<DescriptorAccess> GetDescriptorAccess();
void FreeTargetResource(ResourceId id);
RDResult ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
@@ -453,7 +453,7 @@ struct SpecConstant
DECLARE_STRINGISE_TYPE(rdcspv::Id);
enum class ShaderStage : uint32_t;
enum class ShaderStage : uint8_t;
enum class ShaderBuiltin : uint32_t;
ShaderStage MakeShaderStage(rdcspv::ExecutionModel model);
@@ -29,7 +29,7 @@
#include "spirv_processor.h"
enum class GraphicsAPI : uint32_t;
enum class ShaderStage : uint32_t;
enum class ShaderStage : uint8_t;
enum class ShaderBuiltin : uint32_t;
struct ShaderReflection;
struct ShaderBindpointMapping;
+5
View File
@@ -2605,6 +2605,11 @@ rdcarray<SamplerDescriptor> VulkanReplay::GetSamplerDescriptors(ResourceId descr
return ret;
}
rdcarray<DescriptorAccess> VulkanReplay::GetDescriptorAccess()
{
return {};
}
void VulkanReplay::FillCBufferVariables(ResourceId pipeline, ResourceId shader, ShaderStage stage,
rdcstr entryPoint, uint32_t cbufSlot,
rdcarray<ShaderVariable> &outvars, const bytebuf &data)
+1
View File
@@ -353,6 +353,7 @@ public:
const rdcarray<DescriptorRange> &ranges);
rdcarray<SamplerDescriptor> GetSamplerDescriptors(ResourceId descriptorStore,
const rdcarray<DescriptorRange> &ranges);
rdcarray<DescriptorAccess> GetDescriptorAccess();
void FreeTargetResource(ResourceId id);
RDResult ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
+5
View File
@@ -165,6 +165,11 @@ rdcarray<SamplerDescriptor> DummyDriver::GetSamplerDescriptors(ResourceId descri
return ret;
}
rdcarray<DescriptorAccess> DummyDriver::GetDescriptorAccess()
{
return {};
}
FrameRecord DummyDriver::GetFrameRecord()
{
return m_FrameRecord;
+1
View File
@@ -64,6 +64,7 @@ public:
const rdcarray<DescriptorRange> &ranges);
rdcarray<SamplerDescriptor> GetSamplerDescriptors(ResourceId descriptorStore,
const rdcarray<DescriptorRange> &ranges);
rdcarray<DescriptorAccess> GetDescriptorAccess();
FrameRecord GetFrameRecord();
+16
View File
@@ -1121,6 +1121,21 @@ void DoSerialise(SerialiserType &ser, SamplerDescriptor &el)
SIZE_CHECK(72);
}
template <typename SerialiserType>
void DoSerialise(SerialiserType &ser, DescriptorAccess &el)
{
SERIALISE_MEMBER(stage);
SERIALISE_MEMBER(type);
SERIALISE_MEMBER(index);
SERIALISE_MEMBER(arrayElement);
SERIALISE_MEMBER(descriptorStore);
SERIALISE_MEMBER(byteOffset);
SERIALISE_MEMBER(byteSize);
SERIALISE_MEMBER(staticallyUnused);
SIZE_CHECK(32);
}
template <typename SerialiserType>
void DoSerialise(SerialiserType &ser, StencilFace &el)
{
@@ -2564,6 +2579,7 @@ INSTANTIATE_SERIALISE_TYPE(DebugPixelInputs)
INSTANTIATE_SERIALISE_TYPE(DescriptorRange)
INSTANTIATE_SERIALISE_TYPE(Descriptor)
INSTANTIATE_SERIALISE_TYPE(SamplerDescriptor)
INSTANTIATE_SERIALISE_TYPE(DescriptorAccess)
INSTANTIATE_SERIALISE_TYPE(D3D11Pipe::Layout)
INSTANTIATE_SERIALISE_TYPE(D3D11Pipe::InputAssembly)
INSTANTIATE_SERIALISE_TYPE(D3D11Pipe::View)
+7
View File
@@ -131,6 +131,13 @@ rdcarray<Descriptor> ReplayController::GetDescriptors(ResourceId descriptorStore
return m_pDevice->GetDescriptors(m_pDevice->GetLiveID(descriptorStore), ranges);
}
rdcarray<DescriptorAccess> ReplayController::GetDescriptorAccess()
{
CHECK_REPLAY_THREAD();
return m_pDevice->GetDescriptorAccess();
}
rdcarray<SamplerDescriptor> ReplayController::GetSamplerDescriptors(
ResourceId descriptorStore, const rdcarray<DescriptorRange> &ranges)
{
+1
View File
@@ -154,6 +154,7 @@ public:
const rdcarray<DescriptorRange> &ranges);
rdcarray<SamplerDescriptor> GetSamplerDescriptors(ResourceId descriptorStore,
const rdcarray<DescriptorRange> &ranges);
rdcarray<DescriptorAccess> GetDescriptorAccess();
rdcarray<rdcstr> GetDisassemblyTargets(bool withPipeline);
rdcstr DisassembleShader(ResourceId pipeline, const ShaderReflection *refl, const rdcstr &target);
+1
View File
@@ -166,6 +166,7 @@ public:
const rdcarray<DescriptorRange> &ranges) = 0;
virtual rdcarray<SamplerDescriptor> GetSamplerDescriptors(
ResourceId descriptorStore, const rdcarray<DescriptorRange> &ranges) = 0;
virtual rdcarray<DescriptorAccess> GetDescriptorAccess() = 0;
virtual FrameRecord GetFrameRecord() = 0;