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;