diff --git a/qrenderdoc/Code/QRDUtils.cpp b/qrenderdoc/Code/QRDUtils.cpp
index 1879d7bc2..1470b3cfb 100644
--- a/qrenderdoc/Code/QRDUtils.cpp
+++ b/qrenderdoc/Code/QRDUtils.cpp
@@ -682,8 +682,7 @@ void addStructuredObjects(RDTreeWidgetItem *parent, const StructuredObjectList &
// that for the best raw structured data representation instead of flattening those out to just
// "ResourceId", and we also don't want to store two types ('fake' and 'real'), so instead we
// check the custom string.
- if((obj->type.flags & SDTypeFlags::HasCustomString) &&
- !strncmp(obj->data.str.c_str(), "ResourceId", 10))
+ if(obj->type.basetype == SDBasic::ResourceId)
{
ResourceId id;
static_assert(sizeof(id) == sizeof(obj->data.basic.u), "ResourceId is no longer uint64_t!");
@@ -715,6 +714,7 @@ void addStructuredObjects(RDTreeWidgetItem *parent, const StructuredObjectList &
case SDBasic::Null: param = lit("NULL"); break;
case SDBasic::Buffer: param = lit("(%1 bytes)").arg(obj->type.byteSize); break;
case SDBasic::String: param = obj->data.str; break;
+ case SDBasic::ResourceId:
case SDBasic::Enum:
case SDBasic::UnsignedInteger: param = Formatter::Format(obj->data.basic.u); break;
case SDBasic::SignedInteger: param = Formatter::Format(obj->data.basic.i); break;
diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h
index e4dd6fb47..61c3cf6b4 100644
--- a/renderdoc/api/replay/renderdoc_replay.h
+++ b/renderdoc/api/replay/renderdoc_replay.h
@@ -251,6 +251,54 @@ inline enum_name operator++(enum_name &a) \
#define ENUM_ARRAY_SIZE(enum_name) size_t(enum_name::Count)
+// declare ResourceId extremely early so that it can be referenced in structured_data.h
+
+#ifdef RENDERDOC_EXPORTS
+struct ResourceId;
+
+namespace ResourceIDGen
+{
+// the only function allowed access to ResourceId internals, for allocating a new ID
+ResourceId GetNewUniqueID();
+};
+#endif
+
+// We give every resource a globally unique ID so that we can differentiate
+// between two textures allocated in the same memory (after the first is freed)
+//
+// it's a struct around a uint64_t to aid in template selection
+DOCUMENT(R"(This is an opaque identifier that uniquely locates a resource.
+
+.. note::
+ These IDs do not overlap ever - textures, buffers, shaders and samplers will all have unique IDs
+ and do not reuse the namespace. Likewise the IDs assigned for resources during capture are not
+ re-used on replay - the corresponding resources created on replay to stand-in for capture-time
+ resources are given unique IDs and a mapping is stored to between the capture-time resource and
+ the replay-time one.
+)");
+struct ResourceId
+{
+ ResourceId() : id() {}
+ DOCUMENT("A helper function that explicitly creates an empty/invalid/null :class:`ResourceId`.");
+ inline static ResourceId Null() { return ResourceId(); }
+ DOCUMENT("Compares two ``ResourceId`` objects for equality.");
+ bool operator==(const ResourceId u) const { return id == u.id; }
+ DOCUMENT("Compares two ``ResourceId`` objects for inequality.");
+ bool operator!=(const ResourceId u) const { return id != u.id; }
+ DOCUMENT("Compares two ``ResourceId`` objects for less-than.");
+ bool operator<(const ResourceId u) const { return id < u.id; }
+#if defined(RENDERDOC_QT_COMPAT)
+ operator QVariant() const { return QVariant::fromValue(*this); }
+#endif
+
+private:
+ uint64_t id;
+
+#ifdef RENDERDOC_EXPORTS
+ friend ResourceId ResourceIDGen::GetNewUniqueID();
+#endif
+};
+
#include "basic_types.h"
#include "stringise.h"
#include "structured_data.h"
@@ -422,52 +470,8 @@ struct GlobalEnvironment
Display *xlibDisplay = NULL;
};
-#ifdef RENDERDOC_EXPORTS
-struct ResourceId;
-
-namespace ResourceIDGen
-{
-// the only function allowed access to ResourceId internals, for allocating a new ID
-ResourceId GetNewUniqueID();
-};
-#endif
-
-// We give every resource a globally unique ID so that we can differentiate
-// between two textures allocated in the same memory (after the first is freed)
-//
-// it's a struct around a uint64_t to aid in template selection
-DOCUMENT(R"(This is an opaque identifier that uniquely locates a resource.
-
-.. note::
- These IDs do not overlap ever - textures, buffers, shaders and samplers will all have unique IDs
- and do not reuse the namespace. Likewise the IDs assigned for resources during capture are not
- re-used on replay - the corresponding resources created on replay to stand-in for capture-time
- resources are given unique IDs and a mapping is stored to between the capture-time resource and
- the replay-time one.
-)");
-struct ResourceId
-{
- ResourceId() : id() {}
- DOCUMENT("A helper function that explicitly creates an empty/invalid/null :class:`ResourceId`.");
- inline static ResourceId Null() { return ResourceId(); }
- DOCUMENT("Compares two ``ResourceId`` objects for equality.");
- bool operator==(const ResourceId u) const { return id == u.id; }
- DOCUMENT("Compares two ``ResourceId`` objects for inequality.");
- bool operator!=(const ResourceId u) const { return id != u.id; }
- DOCUMENT("Compares two ``ResourceId`` objects for less-than.");
- bool operator<(const ResourceId u) const { return id < u.id; }
-#if defined(RENDERDOC_QT_COMPAT)
- operator QVariant() const { return QVariant::fromValue(*this); }
-#endif
-
-private:
- uint64_t id;
-
-#ifdef RENDERDOC_EXPORTS
- friend ResourceId ResourceIDGen::GetNewUniqueID();
-#endif
-};
-
+// declare metatype/reflection for ResourceId here as the struct itself is declared before including
+// all relevant headers above
#if defined(RENDERDOC_QT_COMPAT)
Q_DECLARE_METATYPE(ResourceId);
#endif
diff --git a/renderdoc/api/replay/structured_data.h b/renderdoc/api/replay/structured_data.h
index f0bacbba9..17e934a40 100644
--- a/renderdoc/api/replay/structured_data.h
+++ b/renderdoc/api/replay/structured_data.h
@@ -81,6 +81,11 @@ DOCUMENT(R"(The basic irreducible type of an object. Every other more complex ty
A single byte character. Wide/multi-byte characters are not supported (these would be stored as a
string with 1 character and multiple bytes in UTF-8).
+
+.. data:: ResourceId
+
+ A ResourceId. Equivalent to (and stored as) an 8-byte unsigned integer, but specifically contains
+ the unique Id of a resource in a capture.
)");
enum class SDBasic : uint32_t
{
@@ -96,6 +101,7 @@ enum class SDBasic : uint32_t
Float,
Boolean,
Character,
+ ResourceId,
};
DECLARE_REFLECTION_ENUM(SDBasic);
@@ -251,9 +257,14 @@ union SDObjectPODData
DOCUMENT("The value as a single byte character.");
char c;
+ DOCUMENT("The value as a :class:`ResourceId`.");
+ ResourceId id;
+
// mostly here just for debugging
DOCUMENT("A useful alias of :data:`u` - the number of children when a struct/array.");
uint64_t numChildren;
+
+ SDObjectPODData() : u(0) {}
};
DECLARE_REFLECTION_STRUCT(SDObjectPODData);
@@ -378,6 +389,7 @@ struct SDObject
case SDBasic::Enum:
case SDBasic::UnsignedInteger: return QVariant(qulonglong(data.basic.u));
case SDBasic::SignedInteger: return QVariant(qlonglong(data.basic.i));
+ case SDBasic::ResourceId: return (QVariant)data.basic.id;
case SDBasic::Float: return data.basic.d;
case SDBasic::Boolean: return data.basic.b;
case SDBasic::Character: return data.basic.c;
@@ -523,6 +535,16 @@ inline SDObject *makeSDObject(const char *name, const char *val)
return ret;
}
+DOCUMENT("Make a structured object out of a ResourceId");
+inline SDObject *makeSDObject(const char *name, ResourceId val)
+{
+ SDObject *ret = new SDObject(name, "ResourceId");
+ ret->type.basetype = SDBasic::ResourceId;
+ ret->type.byteSize = 8;
+ ret->data.basic.id = val;
+ return ret;
+}
+
DOCUMENT("Make an array-type structured object out of a string");
inline SDObject *makeSDArray(const char *name)
{
diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp
index 6a24f270e..32c3d1599 100644
--- a/renderdoc/core/core.cpp
+++ b/renderdoc/core/core.cpp
@@ -48,7 +48,7 @@ std::string DoStringise(const ResourceId &el)
return StringFormat::Fmt("ResourceId::%llu", el);
}
-BASIC_TYPE_SERIALISE_STRINGIFY(ResourceId, (uint64_t &)el, SDBasic::UnsignedInteger, 8);
+BASIC_TYPE_SERIALISE_STRINGIFY(ResourceId, (uint64_t &)el, SDBasic::ResourceId, 8);
INSTANTIATE_SERIALISE_TYPE(ResourceId);
diff --git a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp
index a78a5f0c5..cc08c71e6 100644
--- a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp
+++ b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp
@@ -3761,10 +3761,7 @@ void WrappedID3D12GraphicsCommandList::PatchExecuteIndirect(BakedCmdListInfo &in
buf->type.basetype = SDBasic::Struct;
buf->type.byteSize = sizeof(D3D12BufferLocation);
- uint64_t bufid;
- memcpy(&bufid, &id, sizeof(bufid));
-
- buf->AddChild(makeSDObject("Buffer", bufid));
+ buf->AddChild(makeSDObject("Buffer", id));
buf->AddChild(makeSDObject("Offset", offs));
buf->data.children[0]->type.flags |= SDTypeFlags::HasCustomString;
@@ -3810,10 +3807,7 @@ void WrappedID3D12GraphicsCommandList::PatchExecuteIndirect(BakedCmdListInfo &in
buf->type.basetype = SDBasic::Struct;
buf->type.byteSize = sizeof(D3D12BufferLocation);
- uint64_t bufid;
- memcpy(&bufid, &id, sizeof(bufid));
-
- buf->AddChild(makeSDObject("Buffer", bufid));
+ buf->AddChild(makeSDObject("Buffer", id));
buf->AddChild(makeSDObject("Offset", offs));
buf->data.children[0]->type.flags |= SDTypeFlags::HasCustomString;
@@ -3866,10 +3860,7 @@ void WrappedID3D12GraphicsCommandList::PatchExecuteIndirect(BakedCmdListInfo &in
buf->type.basetype = SDBasic::Struct;
buf->type.byteSize = sizeof(D3D12BufferLocation);
- uint64_t bufid;
- memcpy(&bufid, &id, sizeof(bufid));
-
- buf->AddChild(makeSDObject("Buffer", bufid));
+ buf->AddChild(makeSDObject("Buffer", id));
buf->AddChild(makeSDObject("Offset", offs));
buf->data.children[0]->type.flags |= SDTypeFlags::HasCustomString;
diff --git a/renderdoc/renderdoc.natvis b/renderdoc/renderdoc.natvis
index 5048547af..531211ca9 100644
--- a/renderdoc/renderdoc.natvis
+++ b/renderdoc/renderdoc.natvis
@@ -52,6 +52,7 @@
{name} = {data.basic.d}
{name} = {data.basic.b}
{name} = {data.basic.c}
+ {name} = {data.basic.id}
{name} = {type.name}[]
SDObject: {type.name} {name}
diff --git a/renderdoc/serialise/codecs/xml_codec.cpp b/renderdoc/serialise/codecs/xml_codec.cpp
index 51ae796f7..cc1e3f542 100644
--- a/renderdoc/serialise/codecs/xml_codec.cpp
+++ b/renderdoc/serialise/codecs/xml_codec.cpp
@@ -30,8 +30,8 @@
#include "3rdparty/pugixml/pugixml.hpp"
static const char *typeNames[] = {
- "chunk", "struct", "array", "null", "buffer", "string",
- "enum", "uint", "int", "float", "bool", "char",
+ "chunk", "struct", "array", "null", "buffer", "string", "enum",
+ "uint", "int", "float", "bool", "char", "ResourceId",
};
template
@@ -190,7 +190,8 @@ static void Obj2XML(pugi::xml_node &parent, SDObject &child)
obj.append_attribute("typename") = child.type.name.c_str();
if(child.type.basetype == SDBasic::UnsignedInteger ||
- child.type.basetype == SDBasic::SignedInteger || child.type.basetype == SDBasic::Float)
+ child.type.basetype == SDBasic::SignedInteger || child.type.basetype == SDBasic::Float ||
+ child.type.basetype == SDBasic::ResourceId)
{
obj.append_attribute("width") = child.type.byteSize;
}
@@ -240,6 +241,7 @@ static void Obj2XML(pugi::xml_node &parent, SDObject &child)
switch(child.type.basetype)
{
+ case SDBasic::ResourceId:
case SDBasic::Enum:
case SDBasic::UnsignedInteger: obj.text() = child.data.basic.u; break;
case SDBasic::SignedInteger: obj.text() = child.data.basic.i; break;
@@ -404,8 +406,8 @@ static SDObject *XML2Obj(pugi::xml_node &obj)
}
}
- if(ret->type.basetype == SDBasic::UnsignedInteger ||
- ret->type.basetype == SDBasic::SignedInteger || ret->type.basetype == SDBasic::Float)
+ if(ret->type.basetype == SDBasic::UnsignedInteger || ret->type.basetype == SDBasic::SignedInteger ||
+ ret->type.basetype == SDBasic::Float || ret->type.basetype == SDBasic::ResourceId)
{
ret->type.byteSize = obj.attribute("width").as_uint();
}
@@ -460,6 +462,7 @@ static SDObject *XML2Obj(pugi::xml_node &obj)
switch(ret->type.basetype)
{
+ case SDBasic::ResourceId:
case SDBasic::Enum:
case SDBasic::UnsignedInteger: ret->data.basic.u = obj.text().as_ullong(); break;
case SDBasic::SignedInteger: ret->data.basic.i = obj.text().as_llong(); break;
diff --git a/renderdoc/serialise/serialiser.cpp b/renderdoc/serialise/serialiser.cpp
index b2664cf4b..1fdc8c1d0 100644
--- a/renderdoc/serialise/serialiser.cpp
+++ b/renderdoc/serialise/serialiser.cpp
@@ -668,6 +668,7 @@ void DoSerialise(SerialiserType &ser, SDObject *el)
}
case SDBasic::Boolean: ser.Serialise("", el->data.basic.b); break;
case SDBasic::Character: ser.Serialise("", el->data.basic.c); break;
+ case SDBasic::ResourceId: ser.Serialise("", el->data.basic.id); break;
case SDBasic::UnsignedInteger:
if(el->type.byteSize == 1)
{
diff --git a/renderdoc/serialise/serialiser.h b/renderdoc/serialise/serialiser.h
index a999a550d..bf1187915 100644
--- a/renderdoc/serialise/serialiser.h
+++ b/renderdoc/serialise/serialiser.h
@@ -1338,6 +1338,7 @@ public:
case SDBasic::Null: RDCFATAL("Cannot call SerialiseValue for type %d!", type); break;
case SDBasic::String: RDCFATAL("eString should be specialised!"); break;
case SDBasic::Enum:
+ case SDBasic::ResourceId:
case SDBasic::UnsignedInteger:
if(byteSize == 1)
current.data.basic.u = (uint64_t)(uint8_t)el;
@@ -1634,12 +1635,27 @@ BASIC_TYPE_SERIALISE(bool, el, SDBasic::Boolean, 1);
BASIC_TYPE_SERIALISE(char, el, SDBasic::Character, 1);
-BASIC_TYPE_SERIALISE(char *, el, SDBasic::String, 0);
-BASIC_TYPE_SERIALISE(const char *, el, SDBasic::String, 0);
+template <>
+inline const char *TypeName()
+{
+ return "string";
+}
+template
+void DoSerialise(SerialiserType &ser, char *&el)
+{
+ ser.SerialiseValue(SDBasic::String, 0, el);
+}
-// these are special because we give them a typename of 'string' for both:
-// BASIC_TYPE_SERIALISE(rdcstr, el, SDBasic::String, 0);
-// BASIC_TYPE_SERIALISE(std::string, el, SDBasic::String, 0);
+template <>
+inline const char *TypeName()
+{
+ return "string";
+}
+template
+void DoSerialise(SerialiserType &ser, const char *&el)
+{
+ ser.SerialiseValue(SDBasic::String, 0, el);
+}
template <>
inline const char *TypeName()