From 64406b47a34798ffb60a36ff6e6a1ebb8a25e4db Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 15 Feb 2018 10:21:52 +0000 Subject: [PATCH] Add an SDBasic type for ResourceId. * This type is core enum and used globally (not API specific) that it merits becoming a specific structured data type --- qrenderdoc/Code/QRDUtils.cpp | 4 +- renderdoc/api/replay/renderdoc_replay.h | 96 ++++++++++--------- renderdoc/api/replay/structured_data.h | 22 +++++ renderdoc/core/core.cpp | 2 +- .../driver/d3d12/d3d12_command_list_wrap.cpp | 15 +-- renderdoc/renderdoc.natvis | 1 + renderdoc/serialise/codecs/xml_codec.cpp | 13 ++- renderdoc/serialise/serialiser.cpp | 1 + renderdoc/serialise/serialiser.h | 26 ++++- 9 files changed, 109 insertions(+), 71 deletions(-) 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()