Vulkan/Debug: Add Value and Variable
The Value interface exposes values to the debugger.
Variables are named values.
VariableContainer is a collection of Variables.
Bug: b/145351270
Change-Id: Iae3749447554977f84bfc6e58f37b52aa6ed262f
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38893
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Vulkan/Debug/Value.cpp b/src/Vulkan/Debug/Value.cpp
new file mode 100644
index 0000000..db7f1ca
--- /dev/null
+++ b/src/Vulkan/Debug/Value.cpp
@@ -0,0 +1,80 @@
+// 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"
+#include "Value.hpp"
+#include "Variable.hpp"
+
+namespace vk
+{
+namespace dbg
+{
+
+const FormatFlags FormatFlags::Default = {
+ "[", // listPrefix
+ "]", // listSuffix
+ ", ", // listDelimiter
+ "", // listIndent
+ &FormatFlags::Default, // subListFmt
+};
+
+std::string Value::string(const FormatFlags& fmt /* = FormatFlags::Default */) const
+{
+ 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, [&](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 "";
+}
+
+} // namespace dbg
+} // namespace vk
\ No newline at end of file
diff --git a/src/Vulkan/Debug/Value.hpp b/src/Vulkan/Debug/Value.hpp
new file mode 100644
index 0000000..c45b33c
--- /dev/null
+++ b/src/Vulkan/Debug/Value.hpp
@@ -0,0 +1,104 @@
+// 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_VALUE_HPP_
+#define VK_DEBUG_VALUE_HPP_
+
+#include <memory>
+#include <string>
+
+namespace vk
+{
+namespace dbg
+{
+
+class Type;
+
+// FormatFlags holds settings used to serialize a Value to a string.
+struct FormatFlags
+{
+ // The default FormatFlags used to serialize a Value to a string.
+ static const FormatFlags Default;
+
+ std::string listPrefix; // Prefix to lists.
+ std::string listSuffix; // Suffix to lists.
+ std::string listDelimiter; // List item delimiter.
+ std::string listIndent; // List item indententation prefix.
+ const FormatFlags* subListFmt; // Format used for list sub items.
+};
+
+// Value holds a value that can be read and possible written to.
+class Value
+{
+public:
+ virtual ~Value() = default;
+
+ // type() returns the value's type.
+ virtual std::shared_ptr<Type> type() const = 0;
+
+ // string() returns a string representation of the value using the specified
+ // FormatFlags.
+ virtual std::string string(const FormatFlags& = FormatFlags::Default) const;
+
+ // 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; }
+};
+
+// Constant is an immutable value.
+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;
+
+private:
+ const T value;
+};
+
+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;
+}
+
+// make_constant() returns a shared_ptr to a Constant with the given value.
+template <typename T>
+inline std::shared_ptr<Constant<T>> make_constant(const T& value)
+{
+ return std::shared_ptr<Constant<T>>(new vk::dbg::Constant<T>(value));
+}
+
+} // namespace dbg
+} // namespace vk
+
+#endif // VK_DEBUG_VALUE_HPP_
\ No newline at end of file
diff --git a/src/Vulkan/Debug/Variable.hpp b/src/Vulkan/Debug/Variable.hpp
new file mode 100644
index 0000000..15b50b3
--- /dev/null
+++ b/src/Vulkan/Debug/Variable.hpp
@@ -0,0 +1,139 @@
+// 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_VARIABLE_HPP_
+#define VK_DEBUG_VARIABLE_HPP_
+
+#include "ID.hpp"
+#include "Type.hpp"
+#include "Value.hpp"
+
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace vk
+{
+namespace dbg
+{
+
+// Variable is a named value.
+struct Variable
+{
+ std::string name;
+ std::shared_ptr<Value> value;
+};
+
+// VariableContainer is a collection of named values.
+class VariableContainer : public Value
+{
+public:
+ using ID = dbg::ID<VariableContainer>;
+
+ inline VariableContainer(ID id);
+
+ // 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, 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;
+
+ // put() places the variable var into the container.
+ inline void put(const Variable& var);
+
+ // 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);
+
+ // The unique identifier of the variable.
+ const ID id;
+
+private:
+ inline std::shared_ptr<Type> type() const override;
+ inline const void* get() const override;
+
+ mutable std::mutex mutex;
+ std::vector<Variable> variables;
+ std::unordered_map<std::string, int> indices;
+};
+
+VariableContainer::VariableContainer(ID id) :
+ id(id) {}
+
+template <typename F>
+void VariableContainer::foreach(size_t startIndex, const F& cb) const
+{
+ std::unique_lock<std::mutex> lock(mutex);
+ for(size_t i = startIndex; i < variables.size(); i++)
+ {
+ cb(variables[i]);
+ }
+}
+
+template <typename F>
+bool VariableContainer::find(const std::string& name, const F& cb) const
+{
+ std::unique_lock<std::mutex> lock(mutex);
+ for(auto const& var : variables)
+ {
+ if(var.name == name)
+ {
+ cb(var);
+ return true;
+ }
+ }
+ return false;
+}
+
+void VariableContainer::put(const Variable& var)
+{
+ std::unique_lock<std::mutex> lock(mutex);
+ auto it = indices.find(var.name);
+ if(it == indices.end())
+ {
+ indices.emplace(var.name, variables.size());
+ variables.push_back(var);
+ }
+ else
+ {
+ variables[it->second].value = var.value;
+ }
+}
+
+void VariableContainer::put(const std::string& name,
+ const std::shared_ptr<Value>& value)
+{
+ put({ name, value });
+}
+
+std::shared_ptr<Type> VariableContainer::type() const
+{
+ return TypeOf<VariableContainer>::get();
+}
+
+const void* VariableContainer::get() const
+{
+ return nullptr;
+}
+
+} // namespace dbg
+} // namespace vk
+
+#endif // VK_DEBUG_VARIABLE_HPP_
\ No newline at end of file