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.
This commit is contained in:
baldurk
2020-10-27 15:15:19 +00:00
parent c58f3edafa
commit 935cb113ed
18 changed files with 396 additions and 71 deletions
@@ -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")))
+2 -2
View File
@@ -47,7 +47,7 @@ inline SDChunk *MakeFromArgsTuple<SDChunk>(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<SDObject>(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:
@@ -664,6 +664,67 @@ struct TypeConversion<rdcstr, false>
}
};
template <>
struct TypeConversion<rdcinflexiblestr, false>
{
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
+2
View File
@@ -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)
+1 -1
View File
@@ -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
@@ -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();
}
+5 -2
View File
@@ -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();
+194
View File
@@ -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
};
+47 -32
View File
@@ -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;
+1 -1
View File
@@ -1829,7 +1829,7 @@ void ReplayProxy::Proxied_FetchStructuredFile(ParamSerialiser &paramser, 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]);
}
+15 -14
View File
@@ -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<uint32_t>::value()
const rdcstr &ConfigVarRegistration<rdcstr>::value()
{
(void)tmp;
return obj->data.str;
tmp = obj->data.str;
return tmp;
}
template <typename T>
@@ -405,12 +406,12 @@ rdcstr DefValString(const rdcarray<rdcstr> &el)
return ret;
}
inline SDObject *makeSDObject(const char *name, const rdcarray<rdcstr> &vals)
inline SDObject *makeSDObject(const rdcinflexiblestr &name, const rdcarray<rdcstr> &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<rdcstr> &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); \
\
@@ -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;
@@ -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;
@@ -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;
+16
View File
@@ -1,5 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="rdcinflexiblestr">
<DisplayString>{(char*)pointer,s}</DisplayString>
<StringView>(char*)pointer,s</StringView>
<Expand>
<Synthetic Name="[mode]" Condition="is_literal != 0">
<DisplayString>Compile-Time Literal</DisplayString>
</Synthetic>
<Synthetic Name="[mode]" Condition="is_literal == 0">
<DisplayString>Heap allocated</DisplayString>
</Synthetic>
<ArrayItems>
<Size>strlen((char *)pointer)</Size>
<ValuePointer>(char *)pointer</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="rdcstr">
<DisplayString Condition="d.fixed.flags &amp; rdcstr::FIXED_STATE">{d.fixed.str,s}</DisplayString>
<DisplayString Condition="d.fixed.flags &amp; rdcstr::ALLOC_STATE">{d.alloc.str,s}</DisplayString>
+3 -3
View File
@@ -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();
+9 -3
View File
@@ -188,7 +188,7 @@ uint32_t Serialiser<SerialiserMode::Reading>::BeginChunk(uint32_t, uint64_t)
if(name.empty())
name = "<Unknown Chunk>";
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<SerialiserMode::Writing>::BeginChunk(uint32_t chunkID, uint6
if(name.empty())
name = "<Unknown Chunk>";
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)
{
+27
View File
@@ -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<rdcinflexiblestr>()
{
return "string"_lit;
}
template <class SerialiserType>
void DoSerialise(SerialiserType &ser, rdcinflexiblestr &el)
{
ser.SerialiseValue(SDBasic::String, 0, el);
}
DECLARE_STRINGISE_TYPE(SDObject *);
class ScopedChunk;