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