Adding utility code for VK code generator.

ExtObject extends the SDObject structure with helper
methods.
Intervals are used for memory region tracking.

Change-Id: I38198c0a096ed838d527b6526216fb28326ebc89
This commit is contained in:
akharlamov
2018-12-11 17:04:58 -08:00
committed by Baldur Karlsson
parent 5aaf3b4631
commit 04ca50ba63
7 changed files with 436 additions and 10 deletions
+2 -2
View File
@@ -51,7 +51,7 @@ std::string ToStr(const T &el)
// helper macros for common enum switch
#define BEGIN_ENUM_STRINGISE(type) \
using enumType = type; \
static const char unknown_prefix[] = #type "<"; \
static const char unknown_prefix[] = #type "("; \
static_assert(std::is_same<const type &, decltype(el)>::value, \
"Type in macro doesn't match el"); \
(void)(enumType) el; \
@@ -78,7 +78,7 @@ std::string ToStr(const T &el)
// end enum switches
#define END_ENUM_STRINGISE() \
} \
return unknown_prefix + ToStr((uint32_t)el) + ">";
return unknown_prefix + ToStr((uint32_t)el) + ")";
// helper macros for common bitfield check-and-append
#define BEGIN_BITFIELD_STRINGISE(type) \
+79 -7
View File
@@ -380,7 +380,6 @@ struct SDObject
for(size_t i = 0; i < data.children.size(); i++)
if(data.children[i]->name == childName)
return data.children[i];
return NULL;
}
@@ -389,10 +388,11 @@ struct SDObject
{
if(index < data.children.size())
return data.children[index];
return NULL;
}
DOCUMENT("Get the number of child objects.");
inline size_t NumChildren() const { return data.children.size(); }
DOCUMENT("Get a ``list`` of :class:`SDObject` children.");
inline StructuredObjectList &GetChildren() { return data.children; }
#if !defined(SWIG)
@@ -413,7 +413,7 @@ struct SDObject
}
inline double AsDouble() const { return data.basic.d; }
inline float AsFloat() const { return (float)data.basic.d; }
inline float AsChar() const { return (float)data.basic.c; }
inline char AsChar() const { return data.basic.c; }
inline std::string 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; }
@@ -423,6 +423,72 @@ struct SDObject
inline int16_t AsInt16() const { return (int16_t)data.basic.i; }
inline uint8_t AsUInt8() const { return (uint8_t)data.basic.u; }
inline int8_t AsInt8() const { return (int8_t)data.basic.i; }
inline double &Double() { return data.basic.d; }
inline uint64_t &UInt64() { return data.basic.u; }
inline int64_t &Int64() { return data.basic.i; }
inline bool IsStruct() const { return type.basetype == SDBasic::Struct; }
inline bool IsNULL() const
{
return type.basetype == SDBasic::Null || (IsArray() && NumChildren() == 0) ||
(IsString() && (type.flags & SDTypeFlags::NullString));
}
inline bool IsUInt() const { return type.basetype == SDBasic::UnsignedInteger; }
inline bool IsInt() const { return type.basetype == SDBasic::SignedInteger; }
inline bool IsFloat() const { return type.basetype == SDBasic::Float; }
inline bool IsString() const { return type.basetype == SDBasic::String; }
inline bool IsArray() const { return type.basetype == SDBasic::Array; }
inline bool IsFixedArray(uint64_t size = 0) const
{
return IsArray() && (type.flags & SDTypeFlags::FixedArray) &&
(size > 0 ? NumChildren() <= size : true);
}
inline bool IsVariableArray() const
{
return IsArray() && ((type.flags & SDTypeFlags::FixedArray) == SDTypeFlags::NoFlags);
}
inline bool IsEnum() const { return type.basetype == SDBasic::Enum; }
inline bool IsBuffer() const { return type.basetype == SDBasic::Buffer; }
inline bool IsPointer() const
{
return (type.flags & SDTypeFlags::Nullable) && (NumChildren() != 0);
}
inline bool IsResource() const { return type.basetype == SDBasic::Resource; }
inline bool IsUnion() const
{
return (type.basetype == SDBasic::Struct) && (type.flags & SDTypeFlags::Union);
}
inline bool IsSimpleType() const
{
return IsNULL() || (!IsStruct() && !IsArray() && !IsPointer() && !IsUnion());
}
// Is it possible to fully inline the data structure declaration?
inline bool IsInlineable() const
{
// if it has elements that are not inlineable, return false.
for(size_t i = 0; i < NumChildren(); i++)
if(!GetChild(i)->IsInlineable())
return false;
if((IsPointer() || IsVariableArray()) && !IsNULL())
return false;
if(IsUnion())
return false;
return true;
}
const char *Type() const { return type.name.c_str(); }
const char *Name() const { return name.c_str(); }
SDObject *SetTypeName(const char *customTypeName)
{
type.name = customTypeName;
return this;
}
SDObject *SetCustomString(const char *customString)
{
data.str = customString;
type.flags = SDTypeFlags::HasCustomString;
return this;
}
#endif
// these are common to both python and C++
@@ -676,10 +742,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) \
{ \
return makeSDFunc(name, value); \
#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; \
}
SDOBJECT_MAKER(int64_t, makeSDInt64);
+171
View File
@@ -0,0 +1,171 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2018 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#pragma once
#include <algorithm>
#include <map>
template <typename T>
struct Intervals;
template <typename T>
struct IntervalsIter
{
friend struct Intervals<T>;
private:
typename std::map<uint64_t, T>::iterator iter;
std::map<uint64_t, T> *owner;
IntervalsIter(std::map<uint64_t, T> *owner, typename std::map<uint64_t, T>::iterator iter)
: iter(iter), owner(owner)
{
}
typename std::map<uint64_t, T>::iterator unwrap() { return iter; }
public:
IntervalsIter(const IntervalsIter &src) : owner(src.owner), iter(src.iter) {}
IntervalsIter &operator++()
{
++iter;
return *this;
}
IntervalsIter operator++(int)
{
IntervalsIter tmp(*this);
operator++();
return tmp;
}
IntervalsIter &operator--()
{
--iter;
return *this;
}
IntervalsIter operator--(int)
{
IntervalsIter tmp(*this);
operator--();
return tmp;
}
bool operator==(const IntervalsIter &rhs) const { return iter == rhs.iter && owner == rhs.owner; }
bool operator!=(const IntervalsIter &rhs) const { return iter != rhs.iter && owner == rhs.owner; }
IntervalsIter &operator=(const IntervalsIter &rhs)
{
iter = rhs.iter;
owner = rhs.owner;
return *this;
}
inline uint64_t start() const { return iter->first; }
inline uint64_t end() const
{
typename std::map<uint64_t, T>::iterator next = iter;
next++;
if(next == owner->end())
{
return UINT64_MAX;
}
return next->first;
}
inline const T &value() const { return iter->second; }
inline void setValue(uint64_t aStart, uint64_t aEnd, const T &aValue)
{
T old_value = this->value();
if((aValue == old_value || aEnd <= start()) && end() <= aStart)
{
// The value is unchanged, or the specified interval is disjoint from this interval.
return;
}
// Add a new endpoint for aStart, if necessary, and update iter's value to aValue.
if(start() < aStart)
{
// The updated portion of this interval begins at aStart.
iter = owner->insert(std::pair<uint64_t, T>(aStart, aValue)).first;
}
else
{
// The updated portion of this interval begins at start()
iter->second = aValue;
}
// Add a new endpoint for aEnd, if necessary.
if(aEnd < end())
{
owner->insert(std::pair<uint64_t, T>(aEnd, old_value));
}
// Merge with preceding interval, if necessary
if(iter != owner->begin())
{
typename std::map<uint64_t, T>::iterator prev_it = iter;
prev_it--;
if(prev_it->second == iter->second)
{
owner->erase(iter);
iter = prev_it;
}
}
// Merge with succeding interval, if necessary
typename std::map<uint64_t, T>::iterator next_it = iter;
next_it++;
if(next_it != owner->end())
{
if(next_it->second == iter->second)
{
owner->erase(next_it);
}
}
}
};
template <typename T>
struct Intervals
{
private:
std::map<uint64_t, T> StartPoints;
public:
private:
IntervalsIter<T> Wrap(typename std::map<uint64_t, T>::iterator iter)
{
return IntervalsIter<T>(&StartPoints, iter);
}
public:
Intervals() : StartPoints{{0, T()}} {}
IntervalsIter<T> begin() { return Wrap(StartPoints.begin()); }
IntervalsIter<T> end() { return Wrap(StartPoints.end()); }
// finds the interval containing `x`.
IntervalsIter<T> find(uint64_t x)
{
// Find the first interval which starts AFTER `x`
typename std::map<uint64_t, T>::iterator it = StartPoints.upper_bound(x);
// Because the first interval always starts at 0, the found interval cannot be the first
// interval
RDCASSERT(it != StartPoints.begin());
// Move back 1 interval, to find the last interval that starts no later than `range.start`.
// This is the interval that contains the point
it--;
return Wrap(it);
}
};
+1 -1
View File
@@ -777,7 +777,7 @@ std::string DoStringise(const D3D11_LOGIC_OP &el)
TEST_CASE("D3D11 ToStr", "[tostr][d3d]")
{
CHECK(ToStr(D3D11_LOGIC_OP_SET) == "D3D11_LOGIC_OP_SET");
CHECK(ToStr(D3D11_LOGIC_OP(9999)) == "D3D11_LOGIC_OP<9999>");
CHECK(ToStr(D3D11_LOGIC_OP(9999)) == "D3D11_LOGIC_OP(9999)");
CHECK(ToStr(D3D11_BIND_FLAG(D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_INDEX_BUFFER)) ==
"D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_INDEX_BUFFER");
+2
View File
@@ -183,6 +183,7 @@
<ClInclude Include="common\wrapped_pool.h" />
<ClInclude Include="core\core.h" />
<ClInclude Include="core\crash_handler.h" />
<ClInclude Include="core\intervals.h" />
<ClInclude Include="core\plugins.h" />
<ClInclude Include="core\precompiled.h" />
<ClInclude Include="core\replay_proxy.h" />
@@ -213,6 +214,7 @@
<ClInclude Include="os\win32\win32_specific.h" />
<ClInclude Include="replay\replay_driver.h" />
<ClInclude Include="replay\replay_controller.h" />
<ClInclude Include="serialise\codecs\vk_cpp_codec_common.h" />
<ClInclude Include="serialise\lz4io.h" />
<ClInclude Include="serialise\rdcfile.h" />
<ClInclude Include="serialise\serialiser.h" />
+12
View File
@@ -130,6 +130,12 @@
<Filter Include="3rdparty\miniz">
<UniqueIdentifier>{5994c355-880b-45b9-b17a-2e9e1fc2044a}</UniqueIdentifier>
</Filter>
<Filter Include="Common\Serialise\Codecs\cpp_codec">
<UniqueIdentifier>{27f41754-8fa8-4a78-afb8-f63a32473540}</UniqueIdentifier>
</Filter>
<Filter Include="Common\Serialise\Codecs\cpp_codec\vulkan">
<UniqueIdentifier>{ee6a7f7e-becf-43f0-8c7f-e0109a364ebb}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="maths\camera.h">
@@ -459,6 +465,12 @@
<ClInclude Include="api\replay\pipestate.h">
<Filter>API\Replay</Filter>
</ClInclude>
<ClInclude Include="core\intervals.h">
<Filter>Core</Filter>
</ClInclude>
<ClInclude Include="serialise\codecs\vk_cpp_codec_common.h">
<Filter>Common\Serialise\Codecs\cpp_codec\vulkan</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="maths\camera.cpp">
@@ -0,0 +1,169 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2018 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#pragma once
#include <string.h>
#include <string>
#include <unordered_map>
#include <vector>
#include "serialise/rdcfile.h"
namespace vk_cpp_codec
{
inline const char *Type(SDObject *ptr)
{
// (akharlamov) Moving this to filtering stage in TraceTracker class
// isn't trivial. Patching type.name, when done in Type() is only applied
// for SDObjects that store data structures, and patching them during filtering
// stage means the filter stage would need to touch on most of Vulkan API OR
// crawl through the entire SDObject list and patch every object ignoring Vulkan
// specifics.
// Vulkan doesn't use std::string, so need to cast it to const char *
if(ptr->IsString() || ptr->type.name == "string")
return "const char* ";
return ptr->type.name.c_str();
}
inline std::string ValueStr(SDObject *ptr)
{
RDCASSERT(ptr->IsSimpleType());
std::string result;
if(ptr->IsBuffer())
{
std::string buf_name = ptr->AsString();
RDCASSERT(!buf_name.empty());
// A value for for a Buffer is it's $name.data().
result = buf_name + ".data()";
// just-in-time fix for vkCreatShaderModule pCode variable
if(ptr->name == "pCode")
result = "(const uint32_t*) " + result;
}
else if(ptr->IsNULL())
{
result = "NULL";
}
else if(ptr->IsUInt())
{
result = std::to_string(ptr->AsUInt64()) + "u";
}
else if(ptr->IsInt())
{
result = std::to_string(ptr->AsInt64());
}
else if(ptr->IsFloat())
{
if(isnan(ptr->data.basic.d))
ptr->data.basic.d = 1.0f;
result = std::to_string(ptr->AsDouble()) + "f";
}
else if(ptr->IsEnum())
{
result = ptr->data.str;
}
else if(ptr->IsString())
{
std::string escaped;
escaped.reserve(ptr->data.str.size());
for(char c : ptr->data.str)
{
switch(c)
{
case '\a': escaped += "\\a"; break;
case '\b': escaped += "\\b"; break;
case '\f': escaped += "\\f"; break;
case '\n': escaped += "\\n"; break;
case '\r': escaped += "\\r"; break;
case '\t': escaped += "\\t"; break;
case '\v': escaped += "\\v"; break;
case '"':
case '\\':
escaped.push_back('\\');
escaped.push_back(c);
break;
default:
if(c < 32 || c > 127)
{
char buf[8] = {};
snprintf(buf, sizeof(buf), "\\x%02X", c);
escaped += buf;
}
else
{
escaped.push_back(c);
}
break;
}
}
result = std::string("\"") + escaped + std::string("\"");
}
return result;
}
inline uint64_t CanonicalUnionBranch(SDObject *ptr)
{
if(ptr->type.name == "VkClearValue")
{
return 0; // Use `color`
}
else if(ptr->type.name == "VkClearColorValue")
{
return 2; // Use `uint32`
}
// This function must be modified further to return the index of the canonical branch, which
// should be chosen so that it's size is equal to the size of the entire union, and so that the
// values can be represented exactly (e.g., not floating point).
RDCERR("Attempting to output an unknown union type %s", ptr->type.name.c_str());
return 0;
}
typedef std::vector<SDObject *> SDObjectVec;
typedef SDObjectVec::iterator SDObjectVecIter;
typedef std::map<uint64_t, SDObject *> SDObjectIDMap;
typedef SDObjectIDMap::iterator SDObjectIDMapIter;
typedef std::pair<uint64_t, SDObject *> SDObjectIDMapPair;
typedef std::map<uint64_t, SDObjectVec> SDObjectVecIDMap;
typedef SDObjectVecIDMap::iterator SDObjectVecIDMapIter;
typedef std::pair<uint64_t, SDObjectVec> SDObjectVecIDMapPair;
typedef std::vector<SDChunk *> SDChunkVec;
typedef SDChunkVec::iterator SDChunkVecIter;
typedef std::map<uint64_t, SDChunk *> SDChunkIDMap;
typedef SDChunkIDMap::iterator SDChunkIDMapIter;
typedef std::pair<uint64_t, SDChunk *> SDChunkIDMapPair;
typedef std::map<uint64_t, SDChunkVec> SDChunkVecIDMap;
typedef SDChunkVecIDMap::iterator SDChunkVecIDMapIter;
typedef std::pair<uint64_t, SDChunkVec> SDChunkVecIDMapPair;
} // namespace vk_cpp_codec