Vulkan/Debug: Overhaul Values / Variables
`Value` had a number of methods that were never used (like `set()`), so just remove them.
Remove `Type`, this was also unused, and was unncessarily complex to maintain.
Add `Variables` interface that allows other composite value implementations that are not `VariableContainer`.
Break the inheritance of `VariableContainer` from `Value`, as this forces pointer casting and doesn't work with the `Variables` interface.
Add `Struct` which is an implementation of `Value` that implements the new `children()` method to return the provided `Variables`.
Sets the groundwork for the overhauled debugger implementation.
Note: The changes to `SpirvShaderDebugger.cpp` are a least-effort set of changes to make things compile.
A significant amount of this file (along with these changes) will be reimplemented in a followup change.
Bug: b/145351270
Change-Id: Ic3a641a246737b1f82c786fa8c1ec75700b2a71a
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/48693
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/Pipeline/SpirvShaderDebugger.cpp b/src/Pipeline/SpirvShaderDebugger.cpp
index 1608bc5..432b937 100644
--- a/src/Pipeline/SpirvShaderDebugger.cpp
+++ b/src/Pipeline/SpirvShaderDebugger.cpp
@@ -453,7 +453,7 @@
vc,
[&](std::shared_ptr<vk::dbg::VariableContainer> &parent, uint32_t idx) {
auto child = std::make_shared<vk::dbg::VariableContainer>();
- parent->put(tostring(idx), child);
+ parent->put(tostring(idx), std::make_shared<vk::dbg::Struct>("array", child));
return child;
},
[&](std::shared_ptr<vk::dbg::VariableContainer> &parent, uint32_t idx, uint32_t offset) {
@@ -466,7 +466,7 @@
# endif
parent->put(key, child);
});
- return vc;
+ return std::make_shared<vk::dbg::Struct>("array", vc);
}
};
@@ -502,7 +502,7 @@
# endif
vc->put(elKey, base->value(elPtr, interleaved));
}
- return vc;
+ return std::make_shared<vk::dbg::Struct>("vector", vc);
}
};
@@ -571,7 +571,7 @@
# endif
vc->put(elKey, member->type->value(elPtr, interleaved));
}
- return vc;
+ return std::make_shared<vk::dbg::Struct>(name, vc);
}
};
@@ -928,7 +928,7 @@
for(int i = 0; i < sw::SIMD::Width; i++)
{
auto locals = std::make_shared<vk::dbg::VariableContainer>();
- frame.locals->variables->put(laneNames[i], locals);
+ frame.locals->variables->put(laneNames[i], std::make_shared<vk::dbg::Struct>("", locals));
globals.localsByLane[i] = locals;
}
});
@@ -979,7 +979,7 @@
vk::dbg::VariableContainer *SpirvShader::Impl::Debugger::State::group(vk::dbg::VariableContainer *vc, K key)
{
auto out = std::make_shared<vk::dbg::VariableContainer>();
- vc->put(tostring(key), out);
+ vc->put(tostring(key), std::make_shared<vk::dbg::Struct>("", out));
return out.get();
}
@@ -1018,7 +1018,7 @@
{
auto locals = std::make_shared<vk::dbg::VariableContainer>();
s.localsByLane[i] = locals;
- s.locals->variables->put(laneNames[i], locals);
+ s.locals->variables->put(laneNames[i], std::make_shared<vk::dbg::Struct>("", locals));
}
if(hasDebuggerScope(spirvScope->parent))
diff --git a/src/Vulkan/CMakeLists.txt b/src/Vulkan/CMakeLists.txt
index 5128fe9..4652917 100644
--- a/src/Vulkan/CMakeLists.txt
+++ b/src/Vulkan/CMakeLists.txt
@@ -116,8 +116,8 @@
Debug/Server.hpp
Debug/Thread.cpp
Debug/Thread.hpp
- Debug/Type.cpp
- Debug/Type.hpp
+ Debug/TypeOf.cpp
+ Debug/TypeOf.hpp
Debug/Value.cpp
Debug/Value.hpp
Debug/Variable.cpp
diff --git a/src/Vulkan/Debug/Context.cpp b/src/Vulkan/Debug/Context.cpp
index ccee98f..b311e2f 100644
--- a/src/Vulkan/Debug/Context.cpp
+++ b/src/Vulkan/Debug/Context.cpp
@@ -183,12 +183,11 @@
WeakMap<File::ID, File> files;
WeakMap<Frame::ID, Frame> frames;
WeakMap<Scope::ID, Scope> scopes;
- WeakMap<VariableContainer::ID, VariableContainer> variableContainers;
+ WeakMap<Variables::ID, Variables> variables;
Thread::ID nextThreadID = 1;
File::ID nextFileID = 1;
Frame::ID nextFrameID = 1;
Scope::ID nextScopeID = 1;
- VariableContainer::ID nextVariableContainerID = 1;
};
Context::Lock Context::Impl::lock()
@@ -390,14 +389,14 @@
return ctx->scopes.get(id);
}
-void Context::Lock::track(const std::shared_ptr<VariableContainer> &vc)
+void Context::Lock::track(const std::shared_ptr<Variables> &vars)
{
- ctx->variableContainers.add(vc->id, vc);
+ ctx->variables.add(vars->id, vars);
}
-std::shared_ptr<VariableContainer> Context::Lock::get(VariableContainer::ID id)
+std::shared_ptr<Variables> Context::Lock::get(Variables::ID id)
{
- return ctx->variableContainers.get(id);
+ return ctx->variables.get(id);
}
void Context::Lock::addFunctionBreakpoint(const std::string &name)
diff --git a/src/Vulkan/Debug/Context.hpp b/src/Vulkan/Debug/Context.hpp
index 832c9c4..64e7e55 100644
--- a/src/Vulkan/Debug/Context.hpp
+++ b/src/Vulkan/Debug/Context.hpp
@@ -29,7 +29,7 @@
class File;
class Frame;
class Scope;
-class VariableContainer;
+class Variables;
class ClientEventListener;
class ServerEventListener;
@@ -107,16 +107,16 @@
// does not exist.
std::shared_ptr<Scope> get(ID<Scope>);
- // track() registers the variable container with the context so it can
- // be retrieved by get(). Note that the context does not hold a strong
- // reference to the variable container, and get() will return nullptr
- // if all strong external references are dropped.
- void track(const std::shared_ptr<VariableContainer> &);
+ // track() registers the variables with the context so it can be
+ // retrieved by get(). Note that the context does not hold a strong
+ // reference to the variables, and get() will return nullptr if all
+ // strong external references are dropped.
+ void track(const std::shared_ptr<Variables> &);
- // get() returns the variable container with the given ID, or null if
- // the variable container does not exist or no longer has any external
- // shared_ptr references.
- std::shared_ptr<VariableContainer> get(ID<VariableContainer>);
+ // get() returns the variables with the given ID, or null if the
+ // variables does not exist or no longer has any external shared_ptr
+ // references.
+ std::shared_ptr<Variables> get(ID<Variables>);
// addFunctionBreakpoint() adds a breakpoint to the start of the
// function with the given name.
diff --git a/src/Vulkan/Debug/Server.cpp b/src/Vulkan/Debug/Server.cpp
index b6d4443..9dd05ce 100644
--- a/src/Vulkan/Debug/Server.cpp
+++ b/src/Vulkan/Debug/Server.cpp
@@ -269,7 +269,7 @@
DAP_LOG("VariablesRequest receieved");
auto lock = ctx->lock();
- auto vars = lock.get(VariableContainer::ID(req.variablesReference));
+ auto vars = lock.get(Variables::ID(req.variablesReference));
if(!vars)
{
return dap::Error("VariablesReference %d not found",
@@ -281,15 +281,15 @@
dap::Variable out;
out.evaluateName = v.name;
out.name = v.name;
- out.type = v.value->type()->string();
- out.value = v.value->string();
- if(v.value->type()->kind == Kind::VariableContainer)
+ out.type = v.value->type();
+ out.value = v.value->get();
+ if(auto children = v.value->children())
{
- auto const vc = std::dynamic_pointer_cast<VariableContainer>(v.value);
- out.variablesReference = vc->id.value();
- lock.track(vc);
+ out.variablesReference = children->id.value();
+ lock.track(children);
}
response.variables.push_back(out);
+ return true;
});
return response;
});
@@ -446,12 +446,8 @@
}
dap::EvaluateResponse response;
- auto findHandler = [&](const Variable &var) {
- response.result = var.value->string(fmt);
- response.type = var.value->type()->string();
- };
- std::vector<std::shared_ptr<vk::dbg::VariableContainer>> variables = {
+ std::vector<std::shared_ptr<vk::dbg::Variables>> variables = {
frame->locals->variables,
frame->arguments->variables,
frame->registers->variables,
@@ -460,7 +456,12 @@
for(auto const &vars : variables)
{
- if(vars->find(req.expression, findHandler)) { return response; }
+ if(auto val = vars->get(req.expression))
+ {
+ response.result = val->get(fmt);
+ response.type = val->type();
+ return response;
+ }
}
// HACK: VSCode does not appear to include the % in %123 tokens
@@ -469,7 +470,12 @@
auto withPercent = "%" + req.expression;
for(auto const &vars : variables)
{
- if(vars->find(withPercent, findHandler)) { return response; }
+ if(auto val = vars->get(withPercent))
+ {
+ response.result = val->get(fmt);
+ response.type = val->type();
+ return response;
+ }
}
}
diff --git a/src/Vulkan/Debug/Type.cpp b/src/Vulkan/Debug/Type.cpp
deleted file mode 100644
index c3e0ab4..0000000
--- a/src/Vulkan/Debug/Type.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "Type.hpp"
-
-namespace vk {
-namespace dbg {
-
-// clang-format off
-std::shared_ptr<Type> TypeOf<bool>::get() { static auto ty = std::make_shared<Type>(Kind::Bool); return ty; }
-std::shared_ptr<Type> TypeOf<uint8_t>::get() { static auto ty = std::make_shared<Type>(Kind::U8); return ty; }
-std::shared_ptr<Type> TypeOf<int8_t>::get() { static auto ty = std::make_shared<Type>(Kind::S8); return ty; }
-std::shared_ptr<Type> TypeOf<uint16_t>::get() { static auto ty = std::make_shared<Type>(Kind::U16); return ty; }
-std::shared_ptr<Type> TypeOf<int16_t>::get() { static auto ty = std::make_shared<Type>(Kind::S16); return ty; }
-std::shared_ptr<Type> TypeOf<float>::get() { static auto ty = std::make_shared<Type>(Kind::F32); return ty; }
-std::shared_ptr<Type> TypeOf<uint32_t>::get() { static auto ty = std::make_shared<Type>(Kind::U32); return ty; }
-std::shared_ptr<Type> TypeOf<int32_t>::get() { static auto ty = std::make_shared<Type>(Kind::S32); return ty; }
-std::shared_ptr<Type> TypeOf<double>::get() { static auto ty = std::make_shared<Type>(Kind::F64); return ty; }
-std::shared_ptr<Type> TypeOf<uint64_t>::get() { static auto ty = std::make_shared<Type>(Kind::U64); return ty; }
-std::shared_ptr<Type> TypeOf<int64_t>::get() { static auto ty = std::make_shared<Type>(Kind::S64); return ty; }
-std::shared_ptr<Type> TypeOf<VariableContainer>::get() { static auto ty = std::make_shared<Type>(Kind::VariableContainer); return ty; }
-// clang-format on
-
-std::string Type::string() const
-{
- switch(kind)
- {
- case Kind::Bool:
- return "bool";
- case Kind::U8:
- return "uint8_t";
- case Kind::S8:
- return "int8_t";
- case Kind::U16:
- return "uint16_t";
- case Kind::S16:
- return "int16_t";
- case Kind::F32:
- return "float";
- case Kind::U32:
- return "uint32_t";
- case Kind::S32:
- return "int32_t";
- case Kind::F64:
- return "double";
- case Kind::U64:
- return "uint64_t";
- case Kind::S64:
- return "int64_t";
- case Kind::Ptr:
- return elem->string() + "*";
- case Kind::VariableContainer:
- return "struct";
- }
- return "";
-}
-
-} // namespace dbg
-} // namespace vk
\ No newline at end of file
diff --git a/src/Vulkan/Debug/Type.hpp b/src/Vulkan/Debug/Type.hpp
deleted file mode 100644
index c3c3d4b..0000000
--- a/src/Vulkan/Debug/Type.hpp
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef VK_DEBUG_TYPE_HPP_
-#define VK_DEBUG_TYPE_HPP_
-
-#include <memory>
-
-#include <cstdint>
-#include <string>
-
-namespace vk {
-namespace dbg {
-
-class VariableContainer;
-class Value;
-
-// Kind is an enumerator of type kinds.
-enum class Kind
-{
- Bool, // Boolean
- U8, // 8-bit unsigned integer.
- S8, // 8-bit signed integer.
- U16, // 16-bit unsigned integer.
- S16, // 16-bit signed integer.
- F32, // 32-bit unsigned integer.
- U32, // 32-bit signed integer.
- S32, // 32-bit unsigned integer.
- F64, // 64-bit signed integer.
- U64, // 64-bit unsigned integer.
- S64, // 64-bit signed integer.
- Ptr, // A pointer.
- VariableContainer, // A VariableContainer.
-};
-
-// Type describes the type of a value.
-class Type
-{
-public:
- inline Type(Kind kind);
- inline Type(Kind kind, const std::shared_ptr<const Type> &elem);
-
- // string() returns a string representation of the type.
- std::string string() const;
-
- const Kind kind; // Type kind.
- const std::shared_ptr<const Type> elem; // Element type of pointer.
-};
-
-Type::Type(Kind kind)
- : kind(kind)
-{}
-
-Type::Type(Kind kind, const std::shared_ptr<const Type> &elem)
- : kind(kind)
- , elem(elem)
-{}
-
-// clang-format off
-template <typename T> struct TypeOf;
-template <> struct TypeOf<bool> { static std::shared_ptr<Type> get(); };
-template <> struct TypeOf<uint8_t> { static std::shared_ptr<Type> get(); };
-template <> struct TypeOf<int8_t> { static std::shared_ptr<Type> get(); };
-template <> struct TypeOf<uint16_t> { static std::shared_ptr<Type> get(); };
-template <> struct TypeOf<int16_t> { static std::shared_ptr<Type> get(); };
-template <> struct TypeOf<float> { static std::shared_ptr<Type> get(); };
-template <> struct TypeOf<uint32_t> { static std::shared_ptr<Type> get(); };
-template <> struct TypeOf<int32_t> { static std::shared_ptr<Type> get(); };
-template <> struct TypeOf<double> { static std::shared_ptr<Type> get(); };
-template <> struct TypeOf<uint64_t> { static std::shared_ptr<Type> get(); };
-template <> struct TypeOf<int64_t> { static std::shared_ptr<Type> get(); };
-template <> struct TypeOf<VariableContainer> { static std::shared_ptr<Type> get(); };
-// clang-format on
-
-} // namespace dbg
-} // namespace vk
-
-#endif // VK_DEBUG_TYPE_HPP_
\ No newline at end of file
diff --git a/src/Vulkan/Debug/TypeOf.cpp b/src/Vulkan/Debug/TypeOf.cpp
new file mode 100644
index 0000000..637d03c
--- /dev/null
+++ b/src/Vulkan/Debug/TypeOf.cpp
@@ -0,0 +1,33 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "TypeOf.hpp"
+
+namespace vk {
+namespace dbg {
+
+std::string TypeOf<bool>::name = "bool";
+std::string TypeOf<uint8_t>::name = "uint8_t";
+std::string TypeOf<int8_t>::name = "int8_t";
+std::string TypeOf<uint16_t>::name = "uint16_t";
+std::string TypeOf<int16_t>::name = "int16_t";
+std::string TypeOf<float>::name = "float";
+std::string TypeOf<uint32_t>::name = "uint32_t";
+std::string TypeOf<int32_t>::name = "int32_t";
+std::string TypeOf<double>::name = "double";
+std::string TypeOf<uint64_t>::name = "uint64_t";
+std::string TypeOf<int64_t>::name = "int64_t";
+
+} // namespace dbg
+} // namespace vk
diff --git a/src/Vulkan/Debug/TypeOf.hpp b/src/Vulkan/Debug/TypeOf.hpp
new file mode 100644
index 0000000..3c5a8c5
--- /dev/null
+++ b/src/Vulkan/Debug/TypeOf.hpp
@@ -0,0 +1,44 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef VK_DEBUG_TYPE_HPP_
+#define VK_DEBUG_TYPE_HPP_
+
+#include <memory>
+
+#include <cstdint>
+#include <string>
+
+namespace vk {
+namespace dbg {
+
+// clang-format off
+template <typename T> struct TypeOf;
+template <> struct TypeOf<bool> { static std::string name; };
+template <> struct TypeOf<uint8_t> { static std::string name; };
+template <> struct TypeOf<int8_t> { static std::string name; };
+template <> struct TypeOf<uint16_t> { static std::string name; };
+template <> struct TypeOf<int16_t> { static std::string name; };
+template <> struct TypeOf<float> { static std::string name; };
+template <> struct TypeOf<uint32_t> { static std::string name; };
+template <> struct TypeOf<int32_t> { static std::string name; };
+template <> struct TypeOf<double> { static std::string name; };
+template <> struct TypeOf<uint64_t> { static std::string name; };
+template <> struct TypeOf<int64_t> { static std::string name; };
+// clang-format on
+
+} // namespace dbg
+} // namespace vk
+
+#endif // VK_DEBUG_TYPE_HPP_
diff --git a/src/Vulkan/Debug/Value.cpp b/src/Vulkan/Debug/Value.cpp
index 49420b4..8ff221d 100644
--- a/src/Vulkan/Debug/Value.cpp
+++ b/src/Vulkan/Debug/Value.cpp
@@ -13,7 +13,6 @@
// limitations under the License.
#include "Value.hpp"
-#include "Type.hpp"
#include "Variable.hpp"
namespace vk {
@@ -27,54 +26,10 @@
&FormatFlags::Default, // subListFmt
};
-std::string Value::string(const FormatFlags &fmt /* = FormatFlags::Default */) const
+std::string Struct::get(const FormatFlags &fmt /* = FormatFlags::Default */)
{
- switch(type()->kind)
- {
- case Kind::Bool:
- return *reinterpret_cast<const bool *>(get()) ? "true" : "false";
- case Kind::U8:
- return std::to_string(*reinterpret_cast<const uint8_t *>(get()));
- case Kind::S8:
- return std::to_string(*reinterpret_cast<const int8_t *>(get()));
- case Kind::U16:
- return std::to_string(*reinterpret_cast<const uint16_t *>(get()));
- case Kind::S16:
- return std::to_string(*reinterpret_cast<const int16_t *>(get()));
- case Kind::F32:
- return std::to_string(*reinterpret_cast<const float *>(get()));
- case Kind::U32:
- return std::to_string(*reinterpret_cast<const uint32_t *>(get()));
- case Kind::S32:
- return std::to_string(*reinterpret_cast<const int32_t *>(get()));
- case Kind::F64:
- return std::to_string(*reinterpret_cast<const double *>(get()));
- case Kind::U64:
- return std::to_string(*reinterpret_cast<const uint64_t *>(get()));
- case Kind::S64:
- return std::to_string(*reinterpret_cast<const int64_t *>(get()));
- case Kind::Ptr:
- return std::to_string(reinterpret_cast<uintptr_t>(get()));
- case Kind::VariableContainer:
- {
- auto const *vc = static_cast<const VariableContainer *>(this);
- std::string out = "";
- auto subfmt = *fmt.subListFmt;
- subfmt.listIndent = fmt.listIndent + fmt.subListFmt->listIndent;
- bool first = true;
- vc->foreach(0, ~0, [&](const Variable &var) {
- if(!first) { out += fmt.listDelimiter; }
- first = false;
- out += fmt.listIndent;
- out += var.name;
- out += ": ";
- out += var.value->string(subfmt);
- });
- return fmt.listPrefix + out + fmt.listSuffix;
- }
- }
- return "";
+ return members->string(fmt);
}
} // namespace dbg
-} // namespace vk
\ No newline at end of file
+} // namespace vk
diff --git a/src/Vulkan/Debug/Value.hpp b/src/Vulkan/Debug/Value.hpp
index 15105c2..6deb3d6 100644
--- a/src/Vulkan/Debug/Value.hpp
+++ b/src/Vulkan/Debug/Value.hpp
@@ -15,7 +15,9 @@
#ifndef VK_DEBUG_VALUE_HPP_
#define VK_DEBUG_VALUE_HPP_
-#include "Type.hpp"
+#include "TypeOf.hpp"
+
+#include "System/Debug.hpp"
#include <memory>
#include <string>
@@ -23,6 +25,9 @@
namespace vk {
namespace dbg {
+class Variables;
+class VariableContainer;
+
// FormatFlags holds settings used to serialize a Value to a string.
struct FormatFlags
{
@@ -36,97 +41,85 @@
const FormatFlags *subListFmt; // Format used for list sub items.
};
-// Value holds a value that can be read and possible written to.
+// Value holds a value that can be read.
class Value
{
public:
virtual ~Value() = default;
- // type() returns the value's type.
- virtual std::shared_ptr<Type> type() const = 0;
+ // type() returns the typename for the value.
+ virtual std::string type() = 0;
- // string() returns a string representation of the value using the specified
+ // get() returns a string representation of the value using the specified
// FormatFlags.
- virtual std::string string(const FormatFlags & = FormatFlags::Default) const;
+ virtual std::string get(const FormatFlags & = FormatFlags::Default) = 0;
- // get() returns a pointer to the value.
- virtual const void *get() const = 0;
-
- // set() changes the value to a copy of the value at ptr.
- // set() returns true if the value was changed, or false if the value cannot
- // be set.
- virtual bool set(void *ptr) { return false; }
+ // children() returns the optional child members of this value.
+ virtual std::shared_ptr<Variables> children() { return nullptr; }
};
-// Constant is an immutable value.
+// Constant is constant value of type T.
template<typename T>
class Constant : public Value
{
public:
- inline Constant(const T &value);
- inline std::shared_ptr<Type> type() const override;
- inline const void *get() const override;
+ Constant(const T &val)
+ : val(val)
+ {}
+ std::string type() override { return TypeOf<T>::name; }
+ std::string get(const FormatFlags &fmt = FormatFlags::Default) override { return std::to_string(val); }
private:
- const T value;
+ T const val;
};
-template<typename T>
-Constant<T>::Constant(const T &value)
- : value(value)
-{
-}
-
-template<typename T>
-std::shared_ptr<Type> Constant<T>::type() const
-{
- return TypeOf<T>::get();
-}
-
-template<typename T>
-const void *Constant<T>::get() const
-{
- return &value;
-}
-
// Reference is reference to a value in memory.
template<typename T>
class Reference : public Value
{
public:
- inline Reference(T &ptr);
- inline std::shared_ptr<Type> type() const override;
- inline const void *get() const override;
- inline bool set(void *ptr) override;
+ Reference(const T &ref)
+ : ref(ref)
+ {}
+ std::string type() override { return TypeOf<T>::name; }
+ std::string get(const FormatFlags &fmt = FormatFlags::Default) override { return std::to_string(ref); }
private:
- T &ref;
+ T const &ref;
};
-template<typename T>
-Reference<T>::Reference(T &ref)
- : ref(ref)
+// Struct is an implementation of Value that delegates calls to children() on to
+// the constructor provided Variables.
+class Struct : public Value
{
-}
+public:
+ Struct(const std::string &type, const std::shared_ptr<Variables> &members)
+ : ty(type)
+ , members(members)
+ {
+ ASSERT(members);
+ }
-template<typename T>
-std::shared_ptr<Type> Reference<T>::type() const
-{
- return TypeOf<T>::get();
-}
+ std::string type() override { return ty; }
+ std::string get(const FormatFlags &fmt = FormatFlags::Default) override;
+ std::shared_ptr<Variables> children() override { return members; }
-template<typename T>
-const void *Reference<T>::get() const
-{
- return &ref;
-}
+ // create() constructs and returns a new Struct with the given type name and
+ // calls fields to populate the child members.
+ // fields must be a function that has the signature:
+ // void(std::shared_pointer<VariableContainer>&)
+ template<typename F>
+ static std::shared_ptr<Struct> create(const std::string &name, F &&fields)
+ {
+ auto vc = std::make_shared<VariableContainer>();
+ fields(vc);
+ return std::make_shared<Struct>(name, vc);
+ }
-template<typename T>
-bool Reference<T>::set(void *ptr)
-{
- ref = *reinterpret_cast<const T *>(ptr);
- return true;
-}
+private:
+ std::string const ty;
+ std::shared_ptr<Variables> const members;
+};
// make_constant() returns a shared_ptr to a Constant with the given value.
template<typename T>
@@ -137,7 +130,7 @@
// make_reference() returns a shared_ptr to a Reference with the given value.
template<typename T>
-inline std::shared_ptr<Reference<T>> make_reference(T &value)
+inline std::shared_ptr<Reference<T>> make_reference(const T &value)
{
return std::make_shared<Reference<T>>(value);
}
@@ -145,4 +138,4 @@
} // namespace dbg
} // namespace vk
-#endif // VK_DEBUG_VALUE_HPP_
\ No newline at end of file
+#endif // VK_DEBUG_VALUE_HPP_
diff --git a/src/Vulkan/Debug/Variable.cpp b/src/Vulkan/Debug/Variable.cpp
index 8145e01..abade64 100644
--- a/src/Vulkan/Debug/Variable.cpp
+++ b/src/Vulkan/Debug/Variable.cpp
@@ -17,7 +17,41 @@
namespace vk {
namespace dbg {
-std::atomic<int> VariableContainer::nextID{};
+std::atomic<int> Variables::nextID{};
+
+Variables::~Variables() = default;
+
+std::shared_ptr<Value> Variables::get(const std::string &name)
+{
+ std::shared_ptr<Value> found;
+ foreach([&](const Variable &var) {
+ if(var.name == name)
+ {
+ found = var.value;
+ return false;
+ }
+ return true;
+ });
+ return found;
+}
+
+std::string Variables::string(const FormatFlags &fmt /* = FormatFlags::Default */)
+{
+ std::string out = "";
+ auto subfmt = *fmt.subListFmt;
+ subfmt.listIndent = fmt.listIndent + fmt.subListFmt->listIndent;
+ bool first = true;
+ foreach([&](const Variable &var) {
+ if(!first) { out += fmt.listDelimiter; }
+ first = false;
+ out += fmt.listIndent;
+ out += var.name;
+ out += ": ";
+ out += var.value->get(subfmt);
+ return true;
+ });
+ return fmt.listPrefix + out + fmt.listSuffix;
+}
} // namespace dbg
} // namespace vk
diff --git a/src/Vulkan/Debug/Variable.hpp b/src/Vulkan/Debug/Variable.hpp
index 8818b5b..cbc8d51 100644
--- a/src/Vulkan/Debug/Variable.hpp
+++ b/src/Vulkan/Debug/Variable.hpp
@@ -16,14 +16,16 @@
#define VK_DEBUG_VARIABLE_HPP_
#include "ID.hpp"
-#include "Type.hpp"
#include "Value.hpp"
+#include "System/Debug.hpp"
+
#include "marl/mutex.h"
#include "marl/tsa.h"
#include <algorithm>
#include <atomic>
+#include <limits>
#include <memory>
#include <string>
#include <unordered_map>
@@ -37,26 +39,64 @@
{
std::string name;
std::shared_ptr<Value> value;
+
+ // operator bool returns true iff value is not nullptr.
+ operator bool() const { return value != nullptr; }
};
-// VariableContainer is a collection of named values.
-class VariableContainer : public Value
+// Variables is an interface to a collection of named values.
+class Variables
+{
+public:
+ using ID = dbg::ID<Variables>;
+
+ using ForeachCallback = std::function<bool(const Variable &)>;
+ using FindCallback = std::function<void(const Variable &)>;
+
+ inline Variables();
+ virtual ~Variables();
+
+ // foreach() calls cb with each of the variables in the container, while cb
+ // returns true.
+ // foreach() will return when cb returns false.
+ inline void foreach(const ForeachCallback &cb);
+
+ // foreach() calls cb with each of the variables in the container within the
+ // indexed range: [startIndex, startIndex+count), while cb returns true.
+ // foreach() will return when cb returns false.
+ virtual void foreach(size_t startIndex, size_t count, const ForeachCallback &cb) = 0;
+
+ // get() looks up and returns the variable with the given name.
+ virtual std::shared_ptr<Value> get(const std::string &name);
+
+ // string() returns the list of variables formatted to a string using the
+ // given flags.
+ virtual std::string string(const FormatFlags &fmt /* = FormatFlags::Default */);
+
+ // The unique identifier of the variables.
+ const ID id;
+
+private:
+ static std::atomic<int> nextID;
+};
+
+Variables::Variables()
+ : id(nextID++)
+{}
+
+void Variables::foreach(const ForeachCallback &cb)
+{
+ foreach(0, std::numeric_limits<size_t>::max(), cb);
+}
+
+// VariableContainer is mutable collection of named values.
+class VariableContainer : public Variables
{
public:
using ID = dbg::ID<VariableContainer>;
- inline VariableContainer();
-
- // foreach() calls cb with each of the variables in the container.
- // F must be a function with the signature void(const Variable&).
- template<typename F>
- inline void foreach(size_t startIndex, size_t count, const F &cb) const;
-
- // find() looks up the variable with the given name.
- // If the variable with the given name is found, cb is called with the
- // variable and find() returns true.
- template<typename F>
- inline bool find(const std::string &name, const F &cb) const;
+ inline void foreach(size_t startIndex, size_t count, const ForeachCallback &cb) override;
+ inline std::shared_ptr<Value> get(const std::string &name) override;
// put() places the variable var into the container.
inline void put(const Variable &var);
@@ -64,16 +104,12 @@
// put() places the variable with the given name and value into the container.
inline void put(const std::string &name, const std::shared_ptr<Value> &value);
- // extend() adds base to the list of VariableContainers that will be
- // searched and traversed for variables.
- inline void extend(const std::shared_ptr<VariableContainer> &base);
-
- // The unique identifier of the variable.
- const ID id;
+ // extend() adds base to the list of Variables that will be searched and
+ // traversed for variables after those in this VariableContainer are
+ // searched / traversed.
+ inline void extend(const std::shared_ptr<Variables> &base);
private:
- static std::atomic<int> nextID;
-
struct ForeachIndex
{
size_t start;
@@ -81,35 +117,30 @@
};
template<typename F>
- inline void foreach(ForeachIndex &index, const F &cb) const;
-
- inline std::shared_ptr<Type> type() const override;
- inline const void *get() const override;
+ inline void foreach(ForeachIndex &index, const F &cb);
mutable marl::mutex mutex;
std::vector<Variable> variables GUARDED_BY(mutex);
std::unordered_map<std::string, int> indices GUARDED_BY(mutex);
- std::vector<std::shared_ptr<VariableContainer>> extends GUARDED_BY(mutex);
+ std::vector<std::shared_ptr<Variables>> extends GUARDED_BY(mutex);
};
-VariableContainer::VariableContainer()
- : id(nextID++)
-{}
-
-template<typename F>
-void VariableContainer::foreach(size_t startIndex, size_t count, const F &cb) const
+void VariableContainer::foreach(size_t startIndex, size_t count, const ForeachCallback &cb)
{
auto index = ForeachIndex{ startIndex, count };
foreach(index, cb);
}
template<typename F>
-void VariableContainer::foreach(ForeachIndex &index, const F &cb) const
+void VariableContainer::foreach(ForeachIndex &index, const F &cb)
{
marl::lock lock(mutex);
for(size_t i = index.start; i < variables.size() && i < index.count; i++)
{
- cb(variables[i]);
+ if(!cb(variables[i]))
+ {
+ return;
+ }
}
index.start -= std::min(index.start, variables.size());
@@ -117,34 +148,34 @@
for(auto &base : extends)
{
- base->foreach(index, cb);
+ base->foreach(index.start, index.count, cb);
}
}
-template<typename F>
-bool VariableContainer::find(const std::string &name, const F &cb) const
+std::shared_ptr<Value> VariableContainer::get(const std::string &name)
{
marl::lock lock(mutex);
for(auto const &var : variables)
{
if(var.name == name)
{
- cb(var);
- return true;
+ return var.value;
}
}
for(auto &base : extends)
{
- if(base->find(name, cb))
+ if(auto val = base->get(name))
{
- return true;
+ return val;
}
}
- return false;
+ return nullptr;
}
void VariableContainer::put(const Variable &var)
{
+ ASSERT(var.value);
+
marl::lock lock(mutex);
auto it = indices.find(var.name);
if(it == indices.end())
@@ -164,22 +195,12 @@
put({ name, value });
}
-void VariableContainer::extend(const std::shared_ptr<VariableContainer> &base)
+void VariableContainer::extend(const std::shared_ptr<Variables> &base)
{
marl::lock lock(mutex);
extends.emplace_back(base);
}
-std::shared_ptr<Type> VariableContainer::type() const
-{
- return TypeOf<VariableContainer>::get();
-}
-
-const void *VariableContainer::get() const
-{
- return nullptr;
-}
-
} // namespace dbg
} // namespace vk