add D3D11 support for annotations on immediate context only

This commit is contained in:
Remi Palandri
2026-01-28 14:42:09 +00:00
committed by baldurk
parent c793e9a73e
commit 727f450be2
8 changed files with 238 additions and 12 deletions
+4
View File
@@ -528,6 +528,10 @@ bool D3D11InitParams::IsSupportedVersion(uint64_t ver)
if(ver == 0x12)
return true;
// 0x13 -> 0x14 - added serialised annotations
if(ver == 0x12)
return true;
return false;
}
+1
View File
@@ -403,6 +403,7 @@ enum class D3D11Chunk : uint32_t
OpenSharedResource1,
OpenSharedResourceByName,
SetShaderExtUAV,
SetCommandAnnotation,
Max,
};
+58 -2
View File
@@ -236,6 +236,17 @@ WrappedID3D11DeviceContext::~WrappedID3D11DeviceContext()
SAFE_DELETE(m_DescriptorStore);
// Clean up annotation data
for(auto it = m_Annotations.begin(); it != m_Annotations.end(); ++it)
delete it->second;
m_Annotations.clear();
SAFE_DELETE(m_RootAnnotation);
for(SDObject *obj : m_EventAnnotations)
delete obj;
m_EventAnnotations.clear();
SAFE_DELETE(m_FrameReader);
SAFE_RELEASE(m_WrappedVideo.m_pReal);
@@ -451,6 +462,35 @@ bool WrappedID3D11DeviceContext::Serialise_BeginCaptureFrame(SerialiserType &ser
}
}
// Serialize object annotations
if(ser.VersionAtLeast(0x14))
{
SCOPED_LOCK(m_AnnotationsLock);
SERIALISE_ELEMENT_LOCAL(numAnnotations, uint32_t(m_Annotations.size()));
auto it = m_Annotations.begin();
for(uint32_t i = 0; i < numAnnotations; i++)
{
SERIALISE_ELEMENT_LOCAL(id, it->first);
SDObject *annotation = it->second;
if(ser.IsReading())
annotation = new SDObject(""_lit, ""_lit); // will be overwritten below
ser.Serialise("annotation"_lit, *annotation);
if(ser.IsReading() && IsLoading(m_State))
{
m_Annotations[id] = annotation;
m_pDevice->GetReplay()->GetResourceDesc(id).annotations = annotation;
}
++it;
}
if(numAnnotations > 0)
m_pDevice->GetReplay()->WriteFrameRecord().frameInfo.containsAnnotations = true;
}
return true;
}
@@ -895,6 +935,11 @@ bool WrappedID3D11DeviceContext::ProcessChunk(ReadSerialiser &ser, D3D11Chunk ch
case D3D11Chunk::SetMarker: ret = Serialise_SetMarker(ser, 0, L""); break;
case D3D11Chunk::PopMarker: ret = Serialise_PopMarker(ser); break;
case D3D11Chunk::SetCommandAnnotation:
ret = Serialise_SetCommandAnnotation(ser, rdcstr(), eRENDERDOC_AnnotationMax, 0,
RENDERDOC_AnnotationValue());
break;
case D3D11Chunk::DiscardResource: ret = Serialise_DiscardResource(ser, NULL); break;
case D3D11Chunk::DiscardView: ret = Serialise_DiscardView(ser, NULL); break;
case D3D11Chunk::DiscardView1: ret = Serialise_DiscardView1(ser, NULL, NULL, 0); break;
@@ -1014,7 +1059,8 @@ bool WrappedID3D11DeviceContext::ProcessChunk(ReadSerialiser &ser, D3D11Chunk ch
m_ActionStack.pop_back();
}
if(!m_AddedAction)
// annotations don't add events
if(!m_AddedAction && chunk != D3D11Chunk::SetCommandAnnotation)
AddEvent();
}
@@ -1212,6 +1258,13 @@ void WrappedID3D11DeviceContext::AddEvent()
}
}
// Apply current annotation state to this event
if(m_RootAnnotation)
{
apievent.annotations = m_RootAnnotation->Duplicate();
m_EventAnnotations.push_back(apievent.annotations);
}
m_CurEvents.push_back(apievent);
if(IsLoading(m_State))
@@ -1382,7 +1435,10 @@ RDResult WrappedID3D11DeviceContext::ReplayLog(CaptureState readType, uint32_t s
break;
m_LastChunk = chunktype;
m_CurEventID++;
// annotations do not produce events
if(chunktype != D3D11Chunk::SetCommandAnnotation)
m_CurEventID++;
}
if(IsLoading(m_State))
+25
View File
@@ -227,6 +227,12 @@ private:
rdcarray<Annotation> m_AnnotationQueue;
Threading::CriticalSection m_AnnotLock;
// Object and command annotation support
Threading::CriticalSection m_AnnotationsLock;
std::unordered_map<ResourceId, SDObject *> m_Annotations; // Object annotations by ResourceId
SDObject *m_RootAnnotation = NULL; // Root for event annotation state
rdcarray<SDObject *> m_EventAnnotations; // Track allocations for cleanup
uint64_t m_TimeBase = 0;
double m_TimeFrequency = 1.0f;
SDFile *m_StructuredFile = NULL;
@@ -290,12 +296,25 @@ private:
SERIALISED_ID3D11CONTEXT_MARKER_FUNCTIONS();
#define SERIALISED_ID3D11CONTEXT_ANNOTATION_FUNCTIONS() \
IMPLEMENT_FUNCTION_SERIALISED(bool, SetCommandAnnotation, rdcstr key, \
RENDERDOC_AnnotationType valueType, uint32_t valueVectorWidth, \
RENDERDOC_AnnotationValue value);
SERIALISED_ID3D11CONTEXT_ANNOTATION_FUNCTIONS();
public:
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D11DeviceContext);
WrappedID3D11DeviceContext(WrappedID3D11Device *realDevice, ID3D11DeviceContext *context);
virtual ~WrappedID3D11DeviceContext();
void RemoveAnnotations(ResourceId id)
{
SCOPED_LOCK(m_AnnotationsLock);
m_Annotations.erase(id);
}
void SetReplayResourceID(ResourceId id) { m_ResourceID = id; }
void VerifyState();
@@ -358,6 +377,12 @@ public:
void IntAddRef();
void IntRelease();
// annotations functions in DeviceContext (immediate only)
uint32_t SetCommandAnnotation(const char *key, RENDERDOC_AnnotationType valueType,
uint32_t valueVectorWidth, const RENDERDOC_AnnotationValue *value);
uint32_t SetObjectAnnotation(void *object, const char *key, RENDERDOC_AnnotationType valueType,
uint32_t valueVectorWidth, const RENDERDOC_AnnotationValue *value);
//////////////////////////////
// implement IUnknown
ULONG STDMETHODCALLTYPE AddRef();
@@ -29,6 +29,7 @@
#include "tinyfiledialogs/tinyfiledialogs.h"
#include "d3d11_debug.h"
#include "d3d11_renderstate.h"
#include "d3d11_replay.h"
#include "d3d11_resources.h"
#ifndef DXGI_ERROR_INVALID_CALL
@@ -188,6 +189,118 @@ int WrappedID3D11DeviceContext::PopMarker()
return --m_MarkerIndentLevel;
}
template <typename SerialiserType>
bool WrappedID3D11DeviceContext::Serialise_SetCommandAnnotation(SerialiserType &ser, rdcstr key,
RENDERDOC_AnnotationType valueType,
uint32_t valueVectorWidth,
RENDERDOC_AnnotationValue value)
{
SERIALISE_ELEMENT(key);
SERIALISE_ELEMENT(valueType);
ser.SetStructArg(valueType);
SERIALISE_ELEMENT(valueVectorWidth);
SERIALISE_ELEMENT(value);
SERIALISE_CHECK_READ_ERRORS();
if(IsReplayingAndReading())
{
if(IsLoading(m_State))
{
if(!m_RootAnnotation)
m_RootAnnotation = new SDObject("Event Annotations"_lit, "Event Annotations"_lit);
SDObject *root = m_RootAnnotation;
if(valueType == eRENDERDOC_Empty)
{
root->EraseChildByKeyPath(key);
}
else
{
WriteAnnotation(root->CreateChildByKeyPath(key), valueType, valueVectorWidth, value);
}
m_pDevice->GetReplay()->WriteFrameRecord().frameInfo.containsAnnotations = true;
}
}
return true;
}
uint32_t WrappedID3D11DeviceContext::SetCommandAnnotation(const char *key,
RENDERDOC_AnnotationType valueType,
uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value)
{
SERIALISE_TIME_CALL();
if(IsActiveCapturing(m_State))
{
USE_SCRATCH_SERIALISER();
GET_SERIALISER.SetActionChunk();
SCOPED_SERIALISE_CHUNK(D3D11Chunk::SetCommandAnnotation);
SERIALISE_ELEMENT(m_ResourceID).Named("Context"_lit).TypedAs("ID3D11DeviceContext *"_lit);
RENDERDOC_AnnotationValue val = value ? *value : RENDERDOC_AnnotationValue();
if(valueType == eRENDERDOC_APIObject && val.apiObject)
{
ResourceId id = GetIDForDeviceChild((ID3D11DeviceChild *)val.apiObject);
RDCCOMPILE_ASSERT(sizeof(val.uint64) == sizeof(id), "ResourceId isn't 64-bit!");
memcpy(&val.uint64, &id, sizeof(id));
}
Serialise_SetCommandAnnotation(GET_SERIALISER, key, valueType, valueVectorWidth, val);
m_ContextRecord->AddChunk(scope.Get());
}
return 0;
}
uint32_t WrappedID3D11DeviceContext::SetObjectAnnotation(void *object, const char *key,
RENDERDOC_AnnotationType valueType,
uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value)
{
ResourceId id = GetIDForDeviceChild((ID3D11DeviceChild *)object);
if(id != ResourceId())
{
RENDERDOC_AnnotationValue val = value ? *value : RENDERDOC_AnnotationValue();
// Convert API object references to ResourceId
if(valueType == eRENDERDOC_APIObject && val.apiObject)
{
ResourceId valId = GetIDForDeviceChild((ID3D11DeviceChild *)val.apiObject);
RDCCOMPILE_ASSERT(sizeof(val.uint64) == sizeof(valId), "ResourceId isn't 64-bit!");
memcpy(&val.uint64, &valId, sizeof(valId));
}
SDObject *root = NULL;
{
SCOPED_LOCK(m_AnnotationsLock);
root = m_Annotations[id];
if(!root)
root = m_Annotations[id] = new SDObject("Object Annotations"_lit, "Object Annotations"_lit);
}
if(valueType == eRENDERDOC_Empty)
{
root->EraseChildByKeyPath(key);
}
else
{
WriteAnnotation(root->CreateChildByKeyPath(key), valueType, valueVectorWidth, val);
}
return 0;
}
return 2;
}
void WrappedID3D11DeviceContext::ThreadSafe_SetMarker(uint32_t col, const wchar_t *name)
{
Annotation annot;
@@ -8153,3 +8266,4 @@ void WrappedID3D11DeviceContext::Unmap(ID3D11Resource *pResource, UINT Subresour
SERIALISED_ID3D11CONTEXT_FUNCTIONS();
SERIALISED_ID3D11CONTEXT_MARKER_FUNCTIONS();
SERIALISED_ID3D11CONTEXT_ANNOTATION_FUNCTIONS();
+30
View File
@@ -1230,6 +1230,7 @@ bool WrappedID3D11Device::ProcessChunk(ReadSerialiser &ser, D3D11Chunk context)
case D3D11Chunk::PostExecuteCommandList:
case D3D11Chunk::PostFinishCommandListSet:
case D3D11Chunk::SwapDeviceContextState:
case D3D11Chunk::SetCommandAnnotation:
case D3D11Chunk::SwapchainPresent: return m_pImmediateContext->ProcessChunk(ser, context);
// no explicit default so that we have compiler warnings if a chunk isn't explicitly handled.
@@ -1947,6 +1948,9 @@ void WrappedID3D11Device::DestroyDeadObject(ID3D11DeviceChild *child)
{
ResourceId id = wrapped->GetResourceID();
if(m_pImmediateContext)
m_pImmediateContext->RemoveAnnotations(id);
// clean up book-keeping
rm->RemoveWrapper(wrapped->GetReal());
rm->ReleaseResource(id);
@@ -1998,6 +2002,32 @@ int WrappedID3D11Device::EndEvent()
return m_pCurrentWrappedDevice->m_pImmediateContext->ThreadSafe_EndEvent();
}
uint32_t WrappedID3D11Device::SetObjectAnnotation(void *object, const char *key,
RENDERDOC_AnnotationType valueType,
uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value)
{
return m_pImmediateContext->SetObjectAnnotation(object, key, valueType, valueVectorWidth, value);
}
uint32_t WrappedID3D11Device::SetCommandAnnotation(void *queueOrCommandBuffer, const char *key,
RENDERDOC_AnnotationType valueType,
uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value)
{
if(queueOrCommandBuffer != NULL && queueOrCommandBuffer != m_pImmediateContext)
return 2;
// D3D11 doesn't have queues or command buffers, so we accept NULL
// and treat all command annotations as immediate/global
if(IsActiveCapturing(m_State))
{
return m_pImmediateContext->SetCommandAnnotation(key, valueType, valueVectorWidth, value);
}
return 0;
}
void WrappedID3D11Device::StartFrameCapture(DeviceOwnedWindow devWnd)
{
SCOPED_LOCK(m_D3DLock);
+3 -9
View File
@@ -82,7 +82,7 @@ struct D3D11InitParams
uint32_t VendorUAV = ~0U;
// check if a frame capture section version is supported
static const uint64_t CurrentVersion = 0x13;
static const uint64_t CurrentVersion = 0x14;
static bool IsSupportedVersion(uint64_t ver);
};
@@ -722,16 +722,10 @@ public:
bool EndFrameCapture(DeviceOwnedWindow devWnd);
bool DiscardFrameCapture(DeviceOwnedWindow devWnd);
uint32_t SetObjectAnnotation(void *object, const char *key, RENDERDOC_AnnotationType valueType,
uint32_t valueVectorWidth, const RENDERDOC_AnnotationValue *value)
{
return 2;
}
uint32_t valueVectorWidth, const RENDERDOC_AnnotationValue *value);
uint32_t SetCommandAnnotation(void *queueOrCommandBuffer, const char *key,
RENDERDOC_AnnotationType valueType, uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value)
{
return 2;
}
const RENDERDOC_AnnotationValue *value);
ID3DUserDefinedAnnotation *GetAnnotations() { return m_RealAnnotations; }
ID3D11InfoQueue *GetInfoQueue() { return m_pInfoQueue; }
+3 -1
View File
@@ -59,7 +59,7 @@ rdcstr DoStringise(const D3D11ResourceType &el)
template <>
rdcstr DoStringise(const D3D11Chunk &el)
{
RDCCOMPILE_ASSERT((uint32_t)D3D11Chunk::Max == 1131, "Chunks changed without updating names");
RDCCOMPILE_ASSERT((uint32_t)D3D11Chunk::Max == 1132, "Chunks changed without updating names");
BEGIN_ENUM_STRINGISE(D3D11Chunk)
{
@@ -213,6 +213,8 @@ rdcstr DoStringise(const D3D11Chunk &el)
STRINGISE_ENUM_CLASS_NAMED(OpenSharedResource1, "ID3D11Device1::OpenSharedResource1");
STRINGISE_ENUM_CLASS_NAMED(OpenSharedResourceByName, "ID3D11Device1::OpenSharedResourceByName");
STRINGISE_ENUM_CLASS_NAMED(SetShaderExtUAV, "VendorExtension::SetExtensionUAVSlot");
STRINGISE_ENUM_CLASS_NAMED(SetCommandAnnotation, "Internal::SetCommandAnnotation");
STRINGISE_ENUM_CLASS_NAMED(Max, "Max Chunk");
}
END_ENUM_STRINGISE()