From 935cb113edffc43f02d8a6a407660c6cf9ee074a Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 26 Oct 2020 16:20:20 +0000 Subject: [PATCH] Add new string type rdcinflexiblestr specifically for structured data * This is a string type which heavily optimises for immutability and minimal storage. It only contains one pointer to the string data and always reallocates on modify. For compile-time literals it doesn't modify or allocate. * On x64 we use the top bit in a tagged pointer to store a flag of whether it's heap or literal, on other platforms it uses a separate field (meaning another pointer sized value effectively, including padding). * This is best for structured data which tends to use a lot of immutable strings for type/name information, and only a few for actual string data (which are only allocated once and aren't modified after that). Similarly we rarely want to know only the size of any of these strings, we want the whole string so not explicitly storing the size is not a big deal. * Overall this reduces SDObject from 128 bytes to 80 bytes. --- .../Code/Interface/PersistantConfig.cpp | 2 +- qrenderdoc/Code/pyrenderdoc/ext_refcounts.h | 4 +- qrenderdoc/Code/pyrenderdoc/pyconversion.h | 61 ++++++ qrenderdoc/Code/pyrenderdoc/renderdoc.i | 2 + qrenderdoc/Windows/Dialogs/ConfigEditor.cpp | 2 +- qrenderdoc/Windows/Dialogs/SettingsDialog.cpp | 2 +- qrenderdoc/Windows/ResourceInspector.cpp | 7 +- renderdoc/api/replay/rdcstr.h | 194 ++++++++++++++++++ renderdoc/api/replay/structured_data.h | 79 ++++--- renderdoc/core/replay_proxy.cpp | 2 +- renderdoc/core/settings.cpp | 29 +-- .../driver/d3d12/d3d12_command_list_wrap.cpp | 2 +- .../driver/gl/wrappers/gl_draw_funcs.cpp | 8 +- .../driver/vulkan/wrappers/vk_draw_funcs.cpp | 12 +- renderdoc/renderdoc.natvis | 16 ++ renderdoc/serialise/codecs/xml_codec.cpp | 6 +- renderdoc/serialise/serialiser.cpp | 12 +- renderdoc/serialise/serialiser.h | 27 +++ 18 files changed, 396 insertions(+), 71 deletions(-) diff --git a/qrenderdoc/Code/Interface/PersistantConfig.cpp b/qrenderdoc/Code/Interface/PersistantConfig.cpp index 00d96e0e6..508111eff 100644 --- a/qrenderdoc/Code/Interface/PersistantConfig.cpp +++ b/qrenderdoc/Code/Interface/PersistantConfig.cpp @@ -271,7 +271,7 @@ void PersistantConfig::applyValues(const QVariantMap &values) debug->ReserveChildren(searchPaths.size()); for(int i = 0; i < searchPaths.size(); i++) - debug->AddAndOwnChild(makeSDString("$el", searchPaths[i])); + debug->AddAndOwnChild(makeSDString("$el"_lit, searchPaths[i])); } if(settings.contains(lit("d3d12ShaderDebugging"))) diff --git a/qrenderdoc/Code/pyrenderdoc/ext_refcounts.h b/qrenderdoc/Code/pyrenderdoc/ext_refcounts.h index 214384307..518f570ff 100644 --- a/qrenderdoc/Code/pyrenderdoc/ext_refcounts.h +++ b/qrenderdoc/Code/pyrenderdoc/ext_refcounts.h @@ -47,7 +47,7 @@ inline SDChunk *MakeFromArgsTuple(PyObject *args) if(!SWIG_IsOK(res)) SWIG_exception_fail(SWIG_ArgError(res), "invalid name used to create SDChunk, expected string"); - result = new SDChunk(name.c_str()); + result = new SDChunk(name); return result; fail: @@ -77,7 +77,7 @@ inline SDObject *MakeFromArgsTuple(PyObject *args) SWIG_exception_fail(SWIG_ArgError(res), "invalid type name used to create SDObject, expected string"); - result = new SDObject(name.c_str(), typeName); + result = new SDObject(name, typeName); return result; fail: diff --git a/qrenderdoc/Code/pyrenderdoc/pyconversion.h b/qrenderdoc/Code/pyrenderdoc/pyconversion.h index c9a20eaca..8d447c1ed 100644 --- a/qrenderdoc/Code/pyrenderdoc/pyconversion.h +++ b/qrenderdoc/Code/pyrenderdoc/pyconversion.h @@ -664,6 +664,67 @@ struct TypeConversion } }; +template <> +struct TypeConversion +{ + static swig_type_info *GetTypeInfo() + { + static swig_type_info *cached_type_info = NULL; + + if(cached_type_info) + return cached_type_info; + + cached_type_info = SWIG_TypeQuery("rdcinflexiblestr *"); + + return cached_type_info; + } + + static int ConvertFromPy(PyObject *in, rdcinflexiblestr &out) + { + if(PyUnicode_Check(in)) + { + PyObject *bytes = PyUnicode_AsUTF8String(in); + + if(!bytes) + return SWIG_ERROR; + + char *buf = NULL; + Py_ssize_t size = 0; + + int ret = PyBytes_AsStringAndSize(bytes, &buf, &size); + + if(ret == 0) + { + out = rdcstr(buf, size); + + Py_DecRef(bytes); + + return SWIG_OK; + } + + Py_DecRef(bytes); + + return SWIG_ERROR; + } + + swig_type_info *type_info = GetTypeInfo(); + if(!type_info) + return SWIG_ERROR; + + rdcinflexiblestr *ptr = NULL; + int res = SWIG_ConvertPtr(in, (void **)&ptr, type_info, 0); + if(SWIG_IsOK(res)) + out = *ptr; + + return res; + } + + static PyObject *ConvertToPy(const rdcinflexiblestr &in) + { + return PyUnicode_FromString(in.c_str()); + } +}; + #include "structured_conversion.h" // free functions forward to struct diff --git a/qrenderdoc/Code/pyrenderdoc/renderdoc.i b/qrenderdoc/Code/pyrenderdoc/renderdoc.i index e6cff1d4a..c27d8e1ea 100644 --- a/qrenderdoc/Code/pyrenderdoc/renderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/renderdoc.i @@ -86,6 +86,7 @@ // completely ignore types that we custom convert to/from a native python type %ignore rdcdatetime; %ignore rdcstr; +%ignore rdcinflexiblestr; %ignore rdcliteral; %ignore rdcpair; %ignore bytebuf; @@ -193,6 +194,7 @@ } SIMPLE_TYPEMAPS(rdcstr) +SIMPLE_TYPEMAPS(rdcinflexiblestr) SIMPLE_TYPEMAPS(rdcdatetime) SIMPLE_TYPEMAPS(bytebuf) diff --git a/qrenderdoc/Windows/Dialogs/ConfigEditor.cpp b/qrenderdoc/Windows/Dialogs/ConfigEditor.cpp index 58e5c7500..c70885652 100644 --- a/qrenderdoc/Windows/Dialogs/ConfigEditor.cpp +++ b/qrenderdoc/Windows/Dialogs/ConfigEditor.cpp @@ -603,7 +603,7 @@ QWidget *SettingDelegate::createEditor(QWidget *parent, const QStyleOptionViewIt val->ReserveChildren(items.size()); for(int i = 0; i < items.size(); i++) - val->AddAndOwnChild(makeSDString("$el", items[i])); + val->AddAndOwnChild(makeSDString("$el"_lit, items[i])); } // we've handled the edit synchronously, don't create an edit widget diff --git a/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp b/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp index cde1330de..480bbcf1c 100644 --- a/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp +++ b/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp @@ -511,7 +511,7 @@ void SettingsDialog::on_chooseSearchPaths_clicked() setPaths->ReserveChildren(items.size()); for(int i = 0; i < items.size(); i++) - setPaths->AddAndOwnChild(makeSDString("$el", items[i])); + setPaths->AddAndOwnChild(makeSDString("$el"_lit, items[i])); RENDERDOC_SaveConfigSettings(); } diff --git a/qrenderdoc/Windows/ResourceInspector.cpp b/qrenderdoc/Windows/ResourceInspector.cpp index 06948e211..1b68e6b48 100644 --- a/qrenderdoc/Windows/ResourceInspector.cpp +++ b/qrenderdoc/Windows/ResourceInspector.cpp @@ -123,7 +123,11 @@ ResourceInspector::ResourceInspector(ICaptureContext &ctx, QWidget *parent) ui->resourceList->setModel(m_FilterModel); - ui->initChunks->setColumns({lit("Parameter"), tr("Value")}); + m_ChunksModel = new StructuredDataItemModel(this); + ui->initChunks->setModel(m_ChunksModel); + m_ChunksModel->setColumns({tr("Parameter"), tr("Value")}, + {StructuredDataItemModel::Name, StructuredDataItemModel::Value}); + ui->initChunks->header()->resizeSection(0, 200); ui->initChunks->setFont(Formatter::PreferredFont()); @@ -228,7 +232,6 @@ void ResourceInspector::Inspect(ResourceId id) ui->resetName->hide(); ui->initChunks->setUpdatesEnabled(false); - ui->initChunks->clear(); ui->resourceUsage->clear(); const SDFile &file = m_Ctx.GetStructuredFile(); diff --git a/renderdoc/api/replay/rdcstr.h b/renderdoc/api/replay/rdcstr.h index a2a0b3c6e..99951fc5b 100644 --- a/renderdoc/api/replay/rdcstr.h +++ b/renderdoc/api/replay/rdcstr.h @@ -33,6 +33,8 @@ void RENDERDOC_OutOfMemory(uint64_t sz); #endif +class rdcinflexiblestr; + // special type for storing literals. This allows functions to force callers to pass them literals class rdcliteral { @@ -42,6 +44,9 @@ class rdcliteral // make the literal operator a friend so it can construct fixed strings. No-one else can. friend rdcliteral operator"" _lit(const char *str, size_t len); + // similarly friend inflexible strings to allow them to decompose to a literal + friend class rdcinflexiblestr; + rdcliteral(const char *s, size_t l) : str(s), len(l) {} rdcliteral() = delete; @@ -128,6 +133,9 @@ private: bool is_alloc() const { return !!(d.fixed.flags & ALLOC_STATE); } bool is_fixed() const { return !!(d.fixed.flags & FIXED_STATE); } bool is_array() const { return !is_alloc() && !is_fixed(); } + // allow inflexible string to introspect to see if we're a literal + friend class rdcinflexiblestr; + ///////////////////////////////////////////////////////////////// // memory management, in a dll safe way @@ -938,3 +946,189 @@ inline rdcstr operator+(const QChar &left, const rdcstr &right) return rdcstr(left) += right; } #endif + +// this class generally should not be used directly. You almost always want rdcstr (or rarely +// rdcliteral) instead. This class is used for structured data where the vast majority of the time +// it stores a literal and is only accessed for the string contents, but it has to allow for +// modification just in case the structured data is dynamically generated. +// It is optimised for storage space and uses a single tagged pointer on x64 - if the tag is set, +// the pointer is to a null-terminated literal, otherwise it is to an allocated null-terminated +// string. There are no built-in modification functions but it can be assigned from an rdcstr and +// converted to an rdcstr - whenever it's assigned, the old storage is deallocated and new storage +// is allocated so it is highly inefficient if the string is being modified. +class rdcinflexiblestr +{ + static char *allocate(size_t count) + { + char *ret = NULL; +#ifdef RENDERDOC_EXPORTS + ret = (char *)malloc(count); + if(ret == NULL) + RENDERDOC_OutOfMemory(count); +#else + ret = (char *)RENDERDOC_AllocArrayMem(count); +#endif + return ret; + } + static void deallocate(char *p) + { +#ifdef RENDERDOC_EXPORTS + free((void *)p); +#else + RENDERDOC_FreeArrayMem((void *)p); +#endif + } + +// we use tagged pointers on x86-64 to minimise storage. On other architecture this isn't safe +// so we have to keep it separate. This is still a storage win over rdcstr + +#if defined(__x86_64__) || defined(_M_X64) + // use a signed pointer to sign-extend for canonical form + intptr_t pointer : 63; + intptr_t is_literal : 1; +#else + intptr_t pointer; + intptr_t is_literal; +#endif + +public: + rdcinflexiblestr() + { + pointer = (intptr_t)(void *)""; + is_literal |= 0x1; + } + ~rdcinflexiblestr() + { + if(is_literal == 0) + deallocate((char *)pointer); + pointer = 0; + is_literal = 0; + } + rdcinflexiblestr(rdcinflexiblestr &&in) + { + pointer = in.pointer; + is_literal = in.is_literal; + in.pointer = 0; + in.is_literal = 0; + } + rdcinflexiblestr &operator=(rdcinflexiblestr &&in) + { + if(is_literal == 0) + deallocate((char *)pointer); + + pointer = in.pointer; + is_literal = in.is_literal; + in.pointer = 0; + in.is_literal = 0; + + return *this; + } + rdcinflexiblestr(const rdcinflexiblestr &in) + { + pointer = 0; + is_literal = 0; + *this = in; + } + + rdcinflexiblestr(const rdcliteral &lit) + { + pointer = (intptr_t)lit.c_str(); + is_literal |= 0x1; + } + rdcinflexiblestr &operator=(const rdcliteral &in) + { + if(is_literal == 0) + deallocate((char *)pointer); + pointer = (intptr_t)in.c_str(); + is_literal |= 0x1; + return *this; + } + rdcinflexiblestr(const rdcstr &in) + { + pointer = 0; + is_literal = 0; + *this = in; + } + rdcinflexiblestr &operator=(const rdcstr &in) + { + if(is_literal == 0) + deallocate((char *)pointer); + + // unbox a literal from the rdcstr if it has one + if(in.is_fixed()) + { + pointer = (intptr_t)in.c_str(); + is_literal |= 0x1; + } + else + { + // always allocate for rdcstr, don't try to unbox a literal if one exists + size_t size = in.size() + 1; + void *dst = allocate(size); + memcpy(dst, in.c_str(), size); + pointer = (intptr_t)dst; + is_literal = 0; + } + return *this; + } + rdcinflexiblestr &operator=(const rdcinflexiblestr &in) + { + if(is_literal == 0) + deallocate((char *)pointer); + + if(in.is_literal != 0) + { + pointer = in.pointer; + is_literal = in.is_literal; + } + else + { + size_t size = in.size() + 1; + void *dst = allocate(size); + memcpy(dst, in.c_str(), size); + pointer = (intptr_t)dst; + is_literal = 0; + } + + return *this; + } + + bool operator==(const rdcstr &o) const + { + if(o.c_str()[0] == 0) + return c_str()[0] == 0; + return !strcmp(o.c_str(), c_str()); + } + bool operator==(const rdcinflexiblestr &o) const + { + if(o.c_str()[0] == 0) + return c_str()[0] == 0; + return !strcmp(o.c_str(), c_str()); + } + bool operator==(const rdcliteral &o) const + { + if(o.c_str()[0] == 0) + return c_str()[0] == 0; + return !strcmp(o.c_str(), c_str()); + } + + bool operator!=(const rdcinflexiblestr &o) const { return !(*this == o); } + bool operator!=(const rdcstr &o) const { return !(*this == o); } + bool operator<(const rdcinflexiblestr &o) const { return strcmp(c_str(), o.c_str()) < 0; } + bool operator>(const rdcinflexiblestr &o) const { return strcmp(c_str(), o.c_str()) > 0; } + bool empty() const { return c_str()[0] == 0; } + const char *c_str() const { return (const char *)pointer; } + size_t size() const { return strlen(c_str()); } + operator rdcstr() const + { + if(is_literal == 0) + return rdcstr(c_str()); + else + return rdcstr(rdcliteral(c_str(), size())); + } + +#if defined(RENDERDOC_QT_COMPAT) + operator QString() const { return QString::fromUtf8(c_str(), (int32_t)size()); } + operator QVariant() const { return QVariant(QString::fromUtf8(c_str(), (int32_t)size())); } +#endif +}; diff --git a/renderdoc/api/replay/structured_data.h b/renderdoc/api/replay/structured_data.h index 1ada7168b..874200a6c 100644 --- a/renderdoc/api/replay/structured_data.h +++ b/renderdoc/api/replay/structured_data.h @@ -166,13 +166,19 @@ struct SDChunk; DOCUMENT("Details the name and properties of a structured type"); struct SDType { - SDType(const rdcstr &n) + SDType(const rdcinflexiblestr &n) : name(n), basetype(SDBasic::Struct), flags(SDTypeFlags::NoFlags), byteSize(0) { } +#if !defined(SWIG) + SDType(rdcinflexiblestr &&n) + : name(std::move(n)), basetype(SDBasic::Struct), flags(SDTypeFlags::NoFlags), byteSize(0) + { + } +#endif DOCUMENT("The name of this type."); - rdcstr name; + rdcinflexiblestr name; DOCUMENT("The :class:`SDBasic` category that this type belongs to."); SDBasic basetype; @@ -355,7 +361,7 @@ struct SDObjectData SDObjectPODData basic; DOCUMENT("The string contents of the object."); - rdcstr str; + rdcinflexiblestr str; SDObjectData(const SDObjectData &) = delete; SDObjectData &operator=(const SDObjectData &other) = delete; @@ -468,12 +474,18 @@ struct SDObject void *operator new[](size_t count) = delete; void operator delete[](void *p) = delete; - SDObject(const rdcstr &n, const rdcstr &t) : type(t) + SDObject(const rdcinflexiblestr &n, const rdcinflexiblestr &t) : name(n), type(t) { - name = n; data.basic.u = 0; m_Lazy = NULL; } +#if !defined(SWIG) + SDObject(rdcinflexiblestr &&n, rdcinflexiblestr &&t) : name(std::move(n)), type(std::move(t)) + { + data.basic.u = 0; + m_Lazy = NULL; + } +#endif ~SDObject() { @@ -506,7 +518,7 @@ struct SDObject } DOCUMENT("The name of this object."); - rdcstr name; + rdcinflexiblestr name; DOCUMENT("The :class:`SDType` of this object."); SDType type; @@ -715,7 +727,7 @@ returned. inline double AsDouble() const { return data.basic.d; } inline float AsFloat() const { return (float)data.basic.d; } inline char AsChar() const { return data.basic.c; } - inline const rdcstr &AsString() const { return data.str; } + inline const rdcinflexiblestr &AsString() const { return data.str; } inline uint64_t AsUInt64() const { return (uint64_t)data.basic.u; } inline int64_t AsInt64() const { return (int64_t)data.basic.i; } inline uint32_t AsUInt32() const { return (uint32_t)data.basic.u; } @@ -901,7 +913,7 @@ private: DECLARE_REFLECTION_STRUCT(SDObject); #if defined(RENDERDOC_QT_COMPAT) -inline SDObject *makeSDObject(const char *name, QVariant val) +inline SDObject *makeSDObject(const rdcinflexiblestr &name, QVariant val) { SDObject *ret = new SDObject(name, "QVariant"_lit); ret->type.basetype = SDBasic::Null; @@ -988,7 +1000,7 @@ inline SDObject *makeSDObject(const char *name, QVariant val) ret->type.basetype = SDBasic::Array; ret->ReserveChildren(list.size()); for(int i = 0; i < list.size(); i++) - ret->AddAndOwnChild(makeSDObject("[]", list.at(i))); + ret->AddAndOwnChild(makeSDObject("[]"_lit, list.at(i))); ret->type.byteSize = list.size(); break; } @@ -999,7 +1011,7 @@ inline SDObject *makeSDObject(const char *name, QVariant val) ret->type.basetype = SDBasic::Struct; ret->ReserveChildren(map.size()); for(const QString &str : map.keys()) - ret->AddAndOwnChild(makeSDObject(str.toUtf8().data(), map[str])); + ret->AddAndOwnChild(makeSDObject(rdcstr(str.toUtf8().data()), map[str])); ret->type.byteSize = map.size(); break; } @@ -1011,7 +1023,7 @@ inline SDObject *makeSDObject(const char *name, QVariant val) #endif DOCUMENT("Make a structured object out of a signed integer"); -inline SDObject *makeSDInt64(const char *name, int64_t val) +inline SDObject *makeSDInt64(const rdcinflexiblestr &name, int64_t val) { SDObject *ret = new SDObject(name, "int64_t"_lit); ret->type.basetype = SDBasic::SignedInteger; @@ -1021,7 +1033,7 @@ inline SDObject *makeSDInt64(const char *name, int64_t val) } DOCUMENT("Make a structured object out of an unsigned integer"); -inline SDObject *makeSDUInt64(const char *name, uint64_t val) +inline SDObject *makeSDUInt64(const rdcinflexiblestr &name, uint64_t val) { SDObject *ret = new SDObject(name, "uint64_t"_lit); ret->type.basetype = SDBasic::UnsignedInteger; @@ -1031,7 +1043,7 @@ inline SDObject *makeSDUInt64(const char *name, uint64_t val) } DOCUMENT("Make a structured object out of a integer, stored as signed 32-bits"); -inline SDObject *makeSDInt32(const char *name, int32_t val) +inline SDObject *makeSDInt32(const rdcinflexiblestr &name, int32_t val) { SDObject *ret = new SDObject(name, "int32_t"_lit); ret->type.basetype = SDBasic::SignedInteger; @@ -1041,7 +1053,7 @@ inline SDObject *makeSDInt32(const char *name, int32_t val) } DOCUMENT("Make a structured object out of a integer, stored as unsigned 32-bits"); -inline SDObject *makeSDUInt32(const char *name, uint32_t val) +inline SDObject *makeSDUInt32(const rdcinflexiblestr &name, uint32_t val) { SDObject *ret = new SDObject(name, "uint32_t"_lit); ret->type.basetype = SDBasic::UnsignedInteger; @@ -1051,7 +1063,7 @@ inline SDObject *makeSDUInt32(const char *name, uint32_t val) } DOCUMENT("Make a structured object out of a floating point value"); -inline SDObject *makeSDFloat(const char *name, float val) +inline SDObject *makeSDFloat(const rdcinflexiblestr &name, float val) { SDObject *ret = new SDObject(name, "float"_lit); ret->type.basetype = SDBasic::Float; @@ -1061,7 +1073,7 @@ inline SDObject *makeSDFloat(const char *name, float val) } DOCUMENT("Make a structured object out of a boolean value"); -inline SDObject *makeSDBool(const char *name, bool val) +inline SDObject *makeSDBool(const rdcinflexiblestr &name, bool val) { SDObject *ret = new SDObject(name, "bool"_lit); ret->type.basetype = SDBasic::Boolean; @@ -1071,7 +1083,7 @@ inline SDObject *makeSDBool(const char *name, bool val) } DOCUMENT("Make a structured object out of a string"); -inline SDObject *makeSDString(const char *name, const rdcstr &val) +inline SDObject *makeSDString(const rdcinflexiblestr &name, const rdcstr &val) { SDObject *ret = new SDObject(name, "string"_lit); ret->type.basetype = SDBasic::String; @@ -1081,7 +1093,7 @@ inline SDObject *makeSDString(const char *name, const rdcstr &val) } DOCUMENT("Make a structured object out of a ResourceId"); -inline SDObject *makeSDResourceId(const char *name, ResourceId val) +inline SDObject *makeSDResourceId(const rdcinflexiblestr &name, ResourceId val) { SDObject *ret = new SDObject(name, "ResourceId"_lit); ret->type.basetype = SDBasic::Resource; @@ -1091,7 +1103,7 @@ inline SDObject *makeSDResourceId(const char *name, ResourceId val) } DOCUMENT("Make a structured object out of an enumeration value"); -inline SDObject *makeSDEnum(const char *name, uint32_t val) +inline SDObject *makeSDEnum(const rdcinflexiblestr &name, uint32_t val) { SDObject *ret = new SDObject(name, "enum"_lit); ret->type.basetype = SDBasic::Enum; @@ -1101,7 +1113,7 @@ inline SDObject *makeSDEnum(const char *name, uint32_t val) } DOCUMENT("Make an array-type structured object"); -inline SDObject *makeSDArray(const char *name) +inline SDObject *makeSDArray(const rdcinflexiblestr &name) { SDObject *ret = new SDObject(name, "array"_lit); ret->type.basetype = SDBasic::Array; @@ -1109,7 +1121,7 @@ inline SDObject *makeSDArray(const char *name) } DOCUMENT("Make an struct-type structured object"); -inline SDObject *makeSDStruct(const char *name, const char *structtype) +inline SDObject *makeSDStruct(const rdcinflexiblestr &name, const rdcinflexiblestr &structtype) { SDObject *ret = new SDObject(name, structtype); ret->type.basetype = SDBasic::Struct; @@ -1120,16 +1132,16 @@ inline SDObject *makeSDStruct(const char *name, const char *structtype) // concept of different width types like 32-bit vs 64-bit ints #if !defined(SWIG) -#define SDOBJECT_MAKER(basetype, makeSDFunc) \ - inline SDObject *makeSDObject(const char *name, basetype value, const char *customString = NULL, \ - const char *customTypeName = NULL) \ - { \ - SDObject *ptr = makeSDFunc(name, value); \ - if(customString) \ - ptr->SetCustomString(customString); \ - if(customTypeName) \ - ptr->SetTypeName(customTypeName); \ - return ptr; \ +#define SDOBJECT_MAKER(basetype, makeSDFunc) \ + inline SDObject *makeSDObject(const rdcinflexiblestr &name, basetype value, \ + const char *customString = NULL, const char *customTypeName = NULL) \ + { \ + SDObject *ptr = makeSDFunc(name, value); \ + if(customString) \ + ptr->SetCustomString(customString); \ + if(customTypeName) \ + ptr->SetTypeName(customTypeName); \ + return ptr; \ } SDOBJECT_MAKER(int64_t, makeSDInt64); @@ -1174,7 +1186,10 @@ struct SDChunk : public SDObject void *operator new[](size_t count) = delete; void operator delete[](void *p) = delete; - SDChunk(const char *name) : SDObject(name, "Chunk"_lit) { type.basetype = SDBasic::Chunk; } + SDChunk(const rdcinflexiblestr &name) : SDObject(name, "Chunk"_lit) + { + type.basetype = SDBasic::Chunk; + } DOCUMENT("The :class:`SDChunkMetaData` with the metadata for this chunk."); SDChunkMetaData metadata; diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index b8420d884..3549d49c3 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -1829,7 +1829,7 @@ void ReplayProxy::Proxied_FetchStructuredFile(ParamSerialiser ¶mser, ReturnS for(size_t c = 0; c < (size_t)chunkCount; c++) { if(retser.IsReading()) - file->chunks[c] = new SDChunk(""); + file->chunks[c] = new SDChunk(""_lit); ser.Serialise("chunk"_lit, *file->chunks[c]); } diff --git a/renderdoc/core/settings.cpp b/renderdoc/core/settings.cpp index 2c256ef15..7f1674bb4 100644 --- a/renderdoc/core/settings.cpp +++ b/renderdoc/core/settings.cpp @@ -63,7 +63,7 @@ struct xml_stream_writer : pugi::xml_writer void write(const void *data, size_t size) { stream.Write(data, size); } }; -static SDObject *makeSDObject(const char *name, SDBasic type, pugi::xml_node &value) +static SDObject *makeSDObject(const rdcinflexiblestr &name, SDBasic type, pugi::xml_node &value) { switch(type) { @@ -136,7 +136,8 @@ static void Config2XML(pugi::xml_node &parent, const SDObject &child) static SDObject *XML2Config(pugi::xml_node &obj) { - SDObject *ret = new SDObject(obj.name(), obj.attribute("type") ? "setting"_lit : "category"_lit); + SDObject *ret = + new SDObject(rdcstr(obj.name()), obj.attribute("type") ? "setting"_lit : "category"_lit); if(ret->type.name == "category"_lit) { @@ -167,7 +168,7 @@ static SDObject *XML2Config(pugi::xml_node &obj) rdcstr description = obj.previous_sibling().value(); description.trim(); - ret->AddAndOwnChild(makeSDObject("description", description)); + ret->AddAndOwnChild(makeSDObject("description"_lit, description)); SDObject *valueObj = NULL; @@ -185,12 +186,12 @@ static SDObject *XML2Config(pugi::xml_node &obj) if(type == SDBasic::Array) { type = types[basicTypeStrings.indexOf(obj.attribute("elemtype").as_string())]; - valueObj = makeSDArray("value"); + valueObj = makeSDArray("value"_lit); uint32_t i = 0; for(pugi::xml_node el = value.first_child(); el; el = el.next_sibling()) { - SDObject *childObj = makeSDObject("$el", type, el); + SDObject *childObj = makeSDObject("$el"_lit, type, el); if(childObj) { @@ -209,7 +210,7 @@ static SDObject *XML2Config(pugi::xml_node &obj) } else { - valueObj = makeSDObject("value", type, value); + valueObj = makeSDObject("value"_lit, type, value); if(!valueObj) { @@ -372,8 +373,8 @@ const uint32_t &ConfigVarRegistration::value() const rdcstr &ConfigVarRegistration::value() { - (void)tmp; - return obj->data.str; + tmp = obj->data.str; + return tmp; } template @@ -405,12 +406,12 @@ rdcstr DefValString(const rdcarray &el) return ret; } -inline SDObject *makeSDObject(const char *name, const rdcarray &vals) +inline SDObject *makeSDObject(const rdcinflexiblestr &name, const rdcarray &vals) { SDObject *ret = new SDObject(name, "array"_lit); ret->type.basetype = SDBasic::Array; for(const rdcstr &s : vals) - ret->AddAndOwnChild(makeSDObject("$el", s)); + ret->AddAndOwnChild(makeSDObject("$el"_lit, s)); return ret; } @@ -436,10 +437,10 @@ inline SDObject *makeSDObject(const char *name, const rdcarray &vals) } \ \ SDObject *setting = new SDObject(settingName, "setting"_lit); \ - setting->AddAndOwnChild(makeSDObject("value", defaultValue)); \ - setting->AddAndOwnChild(makeSDObject("key", name)); \ - setting->AddAndOwnChild(makeSDObject("default", defaultValue)); \ - setting->AddAndOwnChild(makeSDObject("description", desc.c_str())); \ + setting->AddAndOwnChild(makeSDObject("value"_lit, defaultValue)); \ + setting->AddAndOwnChild(makeSDObject("key"_lit, name)); \ + setting->AddAndOwnChild(makeSDObject("default"_lit, defaultValue)); \ + setting->AddAndOwnChild(makeSDObject("description"_lit, desc)); \ \ obj = setting->GetChild(0); \ \ diff --git a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp index 40e16c220..658c87dae 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp @@ -3623,7 +3623,7 @@ void WrappedID3D12GraphicsCommandList::PatchExecuteIndirect(BakedCmdListInfo &in curEvent = &dummy; } - SDChunk *fakeChunk = new SDChunk(""); + SDChunk *fakeChunk = new SDChunk(""_lit); fakeChunk->metadata = baseChunk->metadata; fakeChunk->metadata.chunkID = (uint32_t)D3D12Chunk::List_IndirectSubCommand; diff --git a/renderdoc/driver/gl/wrappers/gl_draw_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_draw_funcs.cpp index c62543960..4dcd48a19 100644 --- a/renderdoc/driver/gl/wrappers/gl_draw_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_draw_funcs.cpp @@ -2733,7 +2733,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawArraysIndirect(SerialiserType &ser, GLe multidraw.topology = MakePrimitiveTopology(mode); // add a fake chunk for this individual indirect draw - SDChunk *fakeChunk = new SDChunk(multidraw.name.c_str()); + SDChunk *fakeChunk = new SDChunk(multidraw.name); fakeChunk->metadata = baseChunk->metadata; fakeChunk->metadata.chunkID = (uint32_t)GLChunk::glIndirectSubCommand; @@ -2959,7 +2959,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawElementsIndirect(SerialiserType &ser, G multidraw.indexByteWidth = IdxSize; // add a fake chunk for this individual indirect draw - SDChunk *fakeChunk = new SDChunk(multidraw.name.c_str()); + SDChunk *fakeChunk = new SDChunk(multidraw.name); fakeChunk->metadata = baseChunk->metadata; fakeChunk->metadata.chunkID = (uint32_t)GLChunk::glIndirectSubCommand; @@ -3185,7 +3185,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawArraysIndirectCount(SerialiserType &ser multidraw.topology = MakePrimitiveTopology(mode); // add a fake chunk for this individual indirect draw - SDChunk *fakeChunk = new SDChunk(multidraw.name.c_str()); + SDChunk *fakeChunk = new SDChunk(multidraw.name); fakeChunk->metadata = baseChunk->metadata; fakeChunk->metadata.chunkID = (uint32_t)GLChunk::glIndirectSubCommand; @@ -3420,7 +3420,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawElementsIndirectCount(SerialiserType &s multidraw.indexByteWidth = IdxSize; // add a fake chunk for this individual indirect draw - SDChunk *fakeChunk = new SDChunk(multidraw.name.c_str()); + SDChunk *fakeChunk = new SDChunk(multidraw.name); fakeChunk->metadata = baseChunk->metadata; fakeChunk->metadata.chunkID = (uint32_t)GLChunk::glIndirectSubCommand; diff --git a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp index c5cc8e60a..2e2a24ec0 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp @@ -670,7 +670,7 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndirect(SerialiserType &ser, VkCommandBu AddEvent(); // add a fake chunk for this individual indirect draw - SDChunk *fakeChunk = new SDChunk("Indirect sub-command"); + SDChunk *fakeChunk = new SDChunk("Indirect sub-command"_lit); fakeChunk->metadata = baseChunk->metadata; fakeChunk->metadata.chunkID = (uint32_t)VulkanChunk::vkCmdIndirectSubCommand; @@ -738,7 +738,7 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndirect(SerialiserType &ser, VkCommandBu multi.flags |= DrawFlags::Drawcall | DrawFlags::Instanced | DrawFlags::Indirect; // add a fake chunk for this individual indirect draw - SDChunk *fakeChunk = new SDChunk("Indirect sub-command"); + SDChunk *fakeChunk = new SDChunk("Indirect sub-command"_lit); fakeChunk->metadata = baseChunk->metadata; fakeChunk->metadata.chunkID = (uint32_t)VulkanChunk::vkCmdIndirectSubCommand; @@ -1053,7 +1053,7 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndexedIndirect(SerialiserType &ser, AddEvent(); // add a fake chunk for this individual indirect draw - SDChunk *fakeChunk = new SDChunk("Indirect sub-command"); + SDChunk *fakeChunk = new SDChunk("Indirect sub-command"_lit); fakeChunk->metadata = baseChunk->metadata; fakeChunk->metadata.chunkID = (uint32_t)VulkanChunk::vkCmdIndirectSubCommand; @@ -1124,7 +1124,7 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndexedIndirect(SerialiserType &ser, DrawFlags::Drawcall | DrawFlags::Instanced | DrawFlags::Indexed | DrawFlags::Indirect; // add a fake chunk for this individual indirect draw - SDChunk *fakeChunk = new SDChunk("Indirect sub-command"); + SDChunk *fakeChunk = new SDChunk("Indirect sub-command"_lit); fakeChunk->metadata = baseChunk->metadata; fakeChunk->metadata.chunkID = (uint32_t)VulkanChunk::vkCmdIndirectSubCommand; @@ -2947,7 +2947,7 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndirectCount(SerialiserType &ser, multi.flags |= DrawFlags::Drawcall | DrawFlags::Instanced | DrawFlags::Indirect; // add a fake chunk for this individual indirect draw - SDChunk *fakeChunk = new SDChunk("Indirect sub-command"); + SDChunk *fakeChunk = new SDChunk("Indirect sub-command"_lit); fakeChunk->metadata = baseChunk->metadata; fakeChunk->metadata.chunkID = (uint32_t)VulkanChunk::vkCmdIndirectSubCommand; @@ -3310,7 +3310,7 @@ bool WrappedVulkan::Serialise_vkCmdDrawIndexedIndirectCount( DrawFlags::Drawcall | DrawFlags::Instanced | DrawFlags::Indexed | DrawFlags::Indirect; // add a fake chunk for this individual indirect draw - SDChunk *fakeChunk = new SDChunk("Indirect sub-command"); + SDChunk *fakeChunk = new SDChunk("Indirect sub-command"_lit); fakeChunk->metadata = baseChunk->metadata; fakeChunk->metadata.chunkID = (uint32_t)VulkanChunk::vkCmdIndirectSubCommand; diff --git a/renderdoc/renderdoc.natvis b/renderdoc/renderdoc.natvis index f14621d0f..7da0a0423 100644 --- a/renderdoc/renderdoc.natvis +++ b/renderdoc/renderdoc.natvis @@ -1,5 +1,21 @@ + + {(char*)pointer,s} + (char*)pointer,s + + + Compile-Time Literal + + + Heap allocated + + + strlen((char *)pointer) + (char *)pointer + + + {d.fixed.str,s} {d.alloc.str,s} diff --git a/renderdoc/serialise/codecs/xml_codec.cpp b/renderdoc/serialise/codecs/xml_codec.cpp index 2e3e563d9..4dbfe0dd9 100644 --- a/renderdoc/serialise/codecs/xml_codec.cpp +++ b/renderdoc/serialise/codecs/xml_codec.cpp @@ -467,8 +467,8 @@ static ReplayStatus Structured2XML(const char *filename, const RDCFile &file, ui static SDObject *XML2Obj(pugi::xml_node &obj) { - SDObject *ret = - new SDObject(obj.attribute("name").as_string(), obj.attribute("typename").as_string()); + SDObject *ret = new SDObject(rdcstr(obj.attribute("name").as_string()), + rdcstr(obj.attribute("typename").as_string())); rdcstr name = obj.name(); @@ -783,7 +783,7 @@ static ReplayStatus XML2Structured(const char *xml, const ThumbTypeAndData &thum if(strcmp(xChunk.name(), "chunk") != 0) return ReplayStatus::FileCorrupted; - SDChunk *chunk = new SDChunk(xChunk.attribute("name").as_string()); + SDChunk *chunk = new SDChunk(rdcstr(xChunk.attribute("name").as_string())); chunk->metadata.chunkID = xChunk.attribute("id").as_uint(); chunk->metadata.length = xChunk.attribute("length").as_uint(); diff --git a/renderdoc/serialise/serialiser.cpp b/renderdoc/serialise/serialiser.cpp index f2b2c7ca8..10e5be8a8 100644 --- a/renderdoc/serialise/serialiser.cpp +++ b/renderdoc/serialise/serialiser.cpp @@ -188,7 +188,7 @@ uint32_t Serialiser::BeginChunk(uint32_t, uint64_t) if(name.empty()) name = ""; - SDChunk *chunk = new SDChunk(name.c_str()); + SDChunk *chunk = new SDChunk(name); chunk->metadata = m_ChunkMetadata; m_StructuredFile->chunks.push_back(chunk); @@ -446,7 +446,7 @@ uint32_t Serialiser::BeginChunk(uint32_t chunkID, uint6 if(name.empty()) name = ""; - SDChunk *chunk = new SDChunk(name.c_str()); + SDChunk *chunk = new SDChunk(name); chunk->metadata = m_ChunkMetadata; m_StructuredFile->chunks.push_back(chunk); @@ -698,7 +698,7 @@ void DoSerialise(SerialiserType &ser, StructuredObjectList &el) { // we also assume that the caller serialising these objects will handle lifetime management. if(ser.IsReading()) - el[c] = new SDObject("", ""); + el[c] = new SDObject(""_lit, ""_lit); ser.Serialise("$el"_lit, *el[c]); } @@ -875,6 +875,12 @@ rdcstr DoStringise(const rdcstr &el) return el; } +template <> +rdcstr DoStringise(const rdcinflexiblestr &el) +{ + return el; +} + template <> rdcstr DoStringise(void *const &el) { diff --git a/renderdoc/serialise/serialiser.h b/renderdoc/serialise/serialiser.h index 29f8d4d3b..0dcd276a1 100644 --- a/renderdoc/serialise/serialiser.h +++ b/renderdoc/serialise/serialiser.h @@ -1204,6 +1204,22 @@ public: } } + void SerialiseValue(SDBasic type, size_t byteSize, rdcinflexiblestr &el) + { + if(IsReading()) + { + rdcstr str; + SerialiseValue(type, byteSize, str); + el = str; + } + else + { + rdcstr str; + str = el; + SerialiseValue(type, byteSize, str); + } + } + void SerialiseValue(SDBasic type, size_t byteSize, char *&el) { int32_t len = 0; @@ -1486,6 +1502,17 @@ void DoSerialise(SerialiserType &ser, rdcstr &el) ser.SerialiseValue(SDBasic::String, 0, el); } +template <> +inline rdcliteral TypeName() +{ + return "string"_lit; +} +template +void DoSerialise(SerialiserType &ser, rdcinflexiblestr &el) +{ + ser.SerialiseValue(SDBasic::String, 0, el); +} + DECLARE_STRINGISE_TYPE(SDObject *); class ScopedChunk;