Add a new in-application API for setting user-specified annotations

This commit is contained in:
baldurk committed 2026-01-28 14:42:08 +00:00
1 parent ba10b62149
commit 8f0a408a2b
8 files changed
+319 -35

No files matched your search

+126 -14
View File
@@ -68,6 +68,10 @@ extern "C" {
// truncated version when only a uint64_t is available (e.g. Vulkan tags):
#define RENDERDOC_ShaderDebugMagicValue_truncated 0x48656670eab25520ULL
// this is a magic value for vulkan user tags to indicate which dispatchable API objects are which
// for object annotations
#define RENDERDOC_APIObjectAnnotationHelper 0xfbb3b337b664d0adULL
//////////////////////////////////////////////////////////////////////////////////////////////////
// RenderDoc capture options
//
@@ -560,6 +564,106 @@ typedef uint32_t(RENDERDOC_CC *pRENDERDOC_DiscardFrameCapture)(RENDERDOC_DeviceP
// multiple times only the last title will be used.
typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureTitle)(const char *title);
// Annotations API:
//
// These functions allow you to specify annotations either on a per-command level, or a per-object
// level.
//
// Basic types of annotations are supported, as well as vector versions and references to API objects.
//
// The annotations are stored as keys, with the key being a dot-separated path allowing arbitrary
// nesting and user organisation. The keys are sorted in human order so `foo.2.bar` will be displayed
// before `foo.10.bar` to allow creation of arrays if desired.
//
// Deleting an annotation can be done by assigning an empty value to it.
// the type of an annotation value, or Empty to delete an annotation
typedef enum RENDERDOC_AnnotationType
{
eRENDERDOC_Empty,
eRENDERDOC_Bool,
eRENDERDOC_Int32,
eRENDERDOC_UInt32,
eRENDERDOC_Int64,
eRENDERDOC_UInt64,
eRENDERDOC_Float,
eRENDERDOC_Double,
eRENDERDOC_String,
eRENDERDOC_APIObject,
eRENDERDOC_AnnotationMax = 0x7FFFFFFF,
} RENDERDOC_AnnotationType;
// a union with vector annotation value data
typedef union RENDERDOC_AnnotationVectorValue
{
bool boolean[4];
int32_t int32[4];
int64_t int64[4];
uint32_t uint32[4];
uint64_t uint64[4];
float float32[4];
double float64[4];
} RENDERDOC_AnnotationVectorValue;
// a union with scalar annotation value data
typedef union RENDERDOC_AnnotationValue
{
bool boolean;
int32_t int32;
int64_t int64;
uint32_t uint32;
uint64_t uint64;
float float32;
double float64;
RENDERDOC_AnnotationVectorValue vector;
const char *string;
void *apiObject;
} RENDERDOC_AnnotationValue;
// simple C++ helper to avoid the need for a temporary object to pass a simple value via the function
#ifdef __cplusplus
struct RDAnnotationHelper
{
RENDERDOC_AnnotationValue val;
RDAnnotationHelper(bool b) { val.boolean = b; }
RDAnnotationHelper(int32_t i) { val.int32 = i; }
RDAnnotationHelper(int64_t i) { val.int64 = i; }
RDAnnotationHelper(uint32_t i) { val.uint32 = i; }
RDAnnotationHelper(uint64_t i) { val.uint64 = i; }
RDAnnotationHelper(float f) { val.float32 = f; }
RDAnnotationHelper(double d) { val.float64 = d; }
RDAnnotationHelper(const char *s) { val.string = s; }
operator RENDERDOC_AnnotationValue *() { return &val; }
};
#endif
// The device is specified in the same way as other API calls that take a RENDERDOC_DevicePointer
// to specify the device.
//
// The object or queue/commandbuffer will depend on the graphics API in question.
//
// Return value:
// 0 - The annotation was applied successfully.
// 1 - The device is unknown/invalid
// 2 - The device is valid but the annotation is not supported for API-specific reasons, such as an
// unrecognised or invalid object or queue/commandbuffer
// 3 - The call is ill-formed or invalid e.g. empty is specified with a value pointer, or non-empty
// is specified with a NULL value pointer
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_SetObjectAnnotation)(RENDERDOC_DevicePointer device,
void *object, const char *key,
RENDERDOC_AnnotationType valueType,
uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value);
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_SetCommandAnnotation)(
RENDERDOC_DevicePointer device, void *queueOrCommandBuffer, const char *key,
RENDERDOC_AnnotationType valueType, uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value);
//////////////////////////////////////////////////////////////////////////////////////////////////
// RenderDoc API versions
//
@@ -588,6 +692,7 @@ typedef enum RENDERDOC_Version
eRENDERDOC_API_Version_1_4_2 = 10402, // RENDERDOC_API_1_4_2 = 1 04 02
eRENDERDOC_API_Version_1_5_0 = 10500, // RENDERDOC_API_1_5_0 = 1 05 00
eRENDERDOC_API_Version_1_6_0 = 10600, // RENDERDOC_API_1_6_0 = 1 06 00
eRENDERDOC_API_Version_1_7_0 = 10700, // RENDERDOC_API_1_7_0 = 1 07 00
} RENDERDOC_Version;
// API version changelog:
@@ -618,8 +723,10 @@ typedef enum RENDERDOC_Version
// 1.5.0 - Added feature: ShowReplayUI() to request that the replay UI show itself if connected
// 1.6.0 - Added feature: SetCaptureTitle() which can be used to set a title for a
// capture made with StartFrameCapture() or EndFrameCapture()
// 1.7.0 - Added feature: SetObjectAnnotation() / SetCommandAnnotation() for adding rich
// annotations to objects and command streams
typedef struct RENDERDOC_API_1_6_0
typedef struct RENDERDOC_API_1_7_0
{
pRENDERDOC_GetAPIVersion GetAPIVersion;
@@ -697,20 +804,25 @@ typedef struct RENDERDOC_API_1_6_0
// new function in 1.6.0
pRENDERDOC_SetCaptureTitle SetCaptureTitle;
} RENDERDOC_API_1_6_0;
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_0_0;
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_0_1;
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_0_2;
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_1_0;
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_1_1;
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_1_2;
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_2_0;
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_3_0;
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_4_0;
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_4_1;
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_4_2;
typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_5_0;
// new functions in 1.7.0
pRENDERDOC_SetObjectAnnotation SetObjectAnnotation;
pRENDERDOC_SetCommandAnnotation SetCommandAnnotation;
} RENDERDOC_API_1_7_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_0_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_0_1;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_0_2;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_1_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_1_1;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_1_2;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_2_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_3_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_4_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_4_1;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_4_2;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_5_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_6_0;
//////////////////////////////////////////////////////////////////////////////////////////////////
// RenderDoc API entry point
+33
View File
@@ -301,6 +301,39 @@ rdcstr DoStringise(const SystemChunk &el)
END_ENUM_STRINGISE();
}
template <>
rdcstr DoStringise(const RENDERDOC_AnnotationType &el)
{
BEGIN_ENUM_STRINGISE(RENDERDOC_AnnotationType);
{
STRINGISE_ENUM_NAMED(eRENDERDOC_Bool, "bool");
STRINGISE_ENUM_NAMED(eRENDERDOC_Int32, "int32");
STRINGISE_ENUM_NAMED(eRENDERDOC_UInt32, "uint32");
STRINGISE_ENUM_NAMED(eRENDERDOC_Int64, "int64");
STRINGISE_ENUM_NAMED(eRENDERDOC_UInt64, "uint64");
STRINGISE_ENUM_NAMED(eRENDERDOC_Float, "float");
STRINGISE_ENUM_NAMED(eRENDERDOC_Double, "double");
STRINGISE_ENUM_NAMED(eRENDERDOC_String, "string");
STRINGISE_ENUM_NAMED(eRENDERDOC_APIObject, "object");
}
END_ENUM_STRINGISE();
}
template <class SerialiserType>
void DoSerialise(SerialiserType &ser, RENDERDOC_AnnotationValue &el)
{
if(ser.GetStructArg() == eRENDERDOC_String)
{
SERIALISE_MEMBER(string).Hidden();
}
else
{
SERIALISE_MEMBER(vector.uint64).Hidden();
}
}
INSTANTIATE_SERIALISE_TYPE(RENDERDOC_AnnotationValue);
RenderDoc &RenderDoc::Inst()
{
static RenderDoc realInst;
+12 -2
View File
@@ -36,6 +36,9 @@
#include "common/timing.h"
#include "os/os_specific.h"
DECLARE_REFLECTION_ENUM(RENDERDOC_AnnotationType);
DECLARE_REFLECTION_STRUCT(RENDERDOC_AnnotationValue);
class Chunk;
struct RDCThumb;
struct ReplayOptions;
@@ -103,6 +106,13 @@ struct IFrameCapturer
virtual void StartFrameCapture(DeviceOwnedWindow devWnd) = 0;
virtual bool EndFrameCapture(DeviceOwnedWindow devWnd) = 0;
virtual bool DiscardFrameCapture(DeviceOwnedWindow devWnd) = 0;
virtual uint32_t SetObjectAnnotation(void *object, const char *key,
RENDERDOC_AnnotationType valueType, uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value) = 0;
virtual uint32_t SetCommandAnnotation(void *queueOrCommandBuffer, const char *key,
RENDERDOC_AnnotationType valueType, uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value) = 0;
};
struct IDeviceProtocolHandler;
@@ -572,6 +582,8 @@ public:
void AddDeviceFrameCapturer(void *dev, IFrameCapturer *cap);
void RemoveDeviceFrameCapturer(void *dev);
IFrameCapturer *MatchFrameCapturer(DeviceOwnedWindow devWnd);
void StartFrameCapture(DeviceOwnedWindow devWnd);
bool IsFrameCapturing() { return m_CapturesActive > 0; }
void SetActiveWindow(DeviceOwnedWindow devWnd);
@@ -724,8 +736,6 @@ private:
DeviceOwnedWindow m_ActiveWindow;
std::map<void *, IFrameCapturer *> m_DeviceFrameCapturers;
IFrameCapturer *MatchFrameCapturer(DeviceOwnedWindow devWnd);
bool m_VendorExts[arraydim<VendorExtensions>()] = {};
volatile bool m_TargetControlThreadShutdown;
+11
View File
@@ -721,6 +721,17 @@ public:
void StartFrameCapture(DeviceOwnedWindow devWnd);
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 SetCommandAnnotation(void *queueOrCommandBuffer, const char *key,
RENDERDOC_AnnotationType valueType, uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value)
{
return 2;
}
ID3DUserDefinedAnnotation *GetAnnotations() { return m_RealAnnotations; }
ID3D11InfoQueue *GetInfoQueue() { return m_pInfoQueue; }
+11
View File
@@ -1116,6 +1116,17 @@ public:
void StartFrameCapture(DeviceOwnedWindow devWnd);
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 SetCommandAnnotation(void *queueOrCommandBuffer, const char *key,
RENDERDOC_AnnotationType valueType, uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value)
{
return 2;
}
template <typename SerialiserType>
bool Serialise_Present(SerialiserType &ser, ID3D12Resource *PresentedImage, UINT SyncInterval,
+11
View File
@@ -705,6 +705,17 @@ public:
void StartFrameCapture(DeviceOwnedWindow devWnd);
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 SetCommandAnnotation(void *queueOrCommandBuffer, const char *key,
RENDERDOC_AnnotationType valueType, uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value)
{
return 2;
}
// map with key being mip level, value being stored data
typedef std::map<int, bytebuf> CompressedDataStore;
+11
View File
@@ -1199,6 +1199,17 @@ private:
void StartFrameCapture(DeviceOwnedWindow devWnd);
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 SetCommandAnnotation(void *queueOrCommandBuffer, const char *key,
RENDERDOC_AnnotationType valueType, uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value)
{
return 2;
}
void AdvanceFrame();
void Present(DeviceOwnedWindow devWnd);
+104 -19
View File
@@ -251,28 +251,109 @@ static uint32_t ShowReplayUI()
return RenderDoc::Inst().ShowReplayUI() ? 1 : 0;
}
static uint32_t SetObjectAnnotation(void *device, void *object, const char *key,
RENDERDOC_AnnotationType valueType, uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value)
{
if(object == NULL)
{
RDCWARN("Invalid annotation - object must not be NULL.");
return 3;
}
if((valueType == eRENDERDOC_Empty && value != NULL) ||
(valueType != eRENDERDOC_Empty && value == NULL))
{
RDCWARN("Invalid annotation - value should be NULL and type should be empty");
return 3;
}
if((valueType == eRENDERDOC_Empty || valueType == eRENDERDOC_String ||
valueType == eRENDERDOC_APIObject) &&
valueVectorWidth != 0)
{
RDCWARN(
"Invalid annotation - for deletion, or setting strings and objects, vector width must be "
"0");
return 3;
}
if(key == NULL || key[0] == 0 || key[0] == '.')
{
RDCWARN("Invalid annotation - key should not be NULL, empty, or start with a .");
return 3;
}
DeviceOwnedWindow devWnd(device, NULL);
IFrameCapturer *capturer = RenderDoc::Inst().MatchFrameCapturer(devWnd);
if(!capturer)
return 1;
return capturer->SetObjectAnnotation(object, key, valueType, valueVectorWidth, value);
}
static uint32_t SetCommandAnnotation(void *device, void *queueOrCommandBuffer, const char *key,
RENDERDOC_AnnotationType valueType, uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value)
{
if((valueType == eRENDERDOC_Empty && value != NULL) ||
(valueType != eRENDERDOC_Empty && value == NULL))
{
RDCWARN("Invalid annotation - value should be NULL and type should be empty");
return 3;
}
if(key == NULL || key[0] == 0 || key[0] == '.')
{
RDCWARN("Invalid annotation - key should not be NULL, empty, or start with a .");
return 3;
}
if((valueType == eRENDERDOC_Empty || valueType == eRENDERDOC_String ||
valueType == eRENDERDOC_APIObject) &&
valueVectorWidth != 0)
{
RDCWARN(
"Invalid annotation - for deletion, or setting strings and objects, vector width must be "
"0");
return 3;
}
DeviceOwnedWindow devWnd(device, NULL);
IFrameCapturer *capturer = RenderDoc::Inst().MatchFrameCapturer(devWnd);
if(!capturer)
return 1;
return capturer->SetCommandAnnotation(queueOrCommandBuffer, key, valueType, valueVectorWidth,
value);
}
// defined in capture_options.cpp
int RENDERDOC_CC SetCaptureOptionU32(RENDERDOC_CaptureOption opt, uint32_t val);
int RENDERDOC_CC SetCaptureOptionF32(RENDERDOC_CaptureOption opt, float val);
uint32_t RENDERDOC_CC GetCaptureOptionU32(RENDERDOC_CaptureOption opt);
float RENDERDOC_CC GetCaptureOptionF32(RENDERDOC_CaptureOption opt);
void RENDERDOC_CC GetAPIVersion_1_6_0(int *major, int *minor, int *patch)
void RENDERDOC_CC GetAPIVersion_1_7_0(int *major, int *minor, int *patch)
{
if(major)
*major = 1;
if(minor)
*minor = 6;
*minor = 7;
if(patch)
*patch = 0;
}
RENDERDOC_API_1_6_0 api_1_6_0;
void Init_1_6_0()
RENDERDOC_API_1_7_0 api_1_7_0;
void Init_1_7_0()
{
RENDERDOC_API_1_6_0 &api = api_1_6_0;
RENDERDOC_API_1_7_0 &api = api_1_7_0;
api.GetAPIVersion = &GetAPIVersion_1_6_0;
api.GetAPIVersion = &GetAPIVersion_1_7_0;
api.SetCaptureOptionU32 = &SetCaptureOptionU32;
api.SetCaptureOptionF32 = &SetCaptureOptionF32;
@@ -315,6 +396,9 @@ void Init_1_6_0()
api.ShowReplayUI = &ShowReplayUI;
api.SetCaptureTitle = &SetCaptureTitle;
api.SetObjectAnnotation = &SetObjectAnnotation;
api.SetCommandAnnotation = &SetCommandAnnotation;
}
extern "C" RENDERDOC_API int RENDERDOC_CC RENDERDOC_GetAPI(RENDERDOC_Version version,
@@ -341,19 +425,20 @@ extern "C" RENDERDOC_API int RENDERDOC_CC RENDERDOC_GetAPI(RENDERDOC_Version ver
ret = 1; \
}
API_VERSION_HANDLE(1_0_0, 1_6_0);
API_VERSION_HANDLE(1_0_1, 1_6_0);
API_VERSION_HANDLE(1_0_2, 1_6_0);
API_VERSION_HANDLE(1_1_0, 1_6_0);
API_VERSION_HANDLE(1_1_1, 1_6_0);
API_VERSION_HANDLE(1_1_2, 1_6_0);
API_VERSION_HANDLE(1_2_0, 1_6_0);
API_VERSION_HANDLE(1_3_0, 1_6_0);
API_VERSION_HANDLE(1_4_0, 1_6_0);
API_VERSION_HANDLE(1_4_1, 1_6_0);
API_VERSION_HANDLE(1_4_2, 1_6_0);
API_VERSION_HANDLE(1_5_0, 1_6_0);
API_VERSION_HANDLE(1_6_0, 1_6_0);
API_VERSION_HANDLE(1_0_0, 1_7_0);
API_VERSION_HANDLE(1_0_1, 1_7_0);
API_VERSION_HANDLE(1_0_2, 1_7_0);
API_VERSION_HANDLE(1_1_0, 1_7_0);
API_VERSION_HANDLE(1_1_1, 1_7_0);
API_VERSION_HANDLE(1_1_2, 1_7_0);
API_VERSION_HANDLE(1_2_0, 1_7_0);
API_VERSION_HANDLE(1_3_0, 1_7_0);
API_VERSION_HANDLE(1_4_0, 1_7_0);
API_VERSION_HANDLE(1_4_1, 1_7_0);
API_VERSION_HANDLE(1_4_2, 1_7_0);
API_VERSION_HANDLE(1_5_0, 1_7_0);
API_VERSION_HANDLE(1_6_0, 1_7_0);
API_VERSION_HANDLE(1_7_0, 1_7_0);
#undef API_VERSION_HANDLE