summaryrefslogtreecommitdiffstats
path: root/tools/gfx-util/shader-cursor.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2021-01-17 22:00:49 -0800
committerGitHub <noreply@github.com>2021-01-17 22:00:49 -0800
commit1296c7bb55b14db24308f31cacdda7f7a71fc937 (patch)
tree935ebf1e829361a17f98f5ead3460998719acf42 /tools/gfx-util/shader-cursor.cpp
parent2a5d5b32348c33aac7ca62aa9a4c2bb7cff8e08a (diff)
Make `gfx` compile to a DLL. (#1660)
* Make `gfx` compile to a DLL. * Fix cuda * Fix cuda build * Bug gl screen capture bug.
Diffstat (limited to 'tools/gfx-util/shader-cursor.cpp')
-rw-r--r--tools/gfx-util/shader-cursor.cpp249
1 files changed, 249 insertions, 0 deletions
diff --git a/tools/gfx-util/shader-cursor.cpp b/tools/gfx-util/shader-cursor.cpp
new file mode 100644
index 000000000..65cf2f8ac
--- /dev/null
+++ b/tools/gfx-util/shader-cursor.cpp
@@ -0,0 +1,249 @@
+#include "shader-cursor.h"
+
+namespace gfx
+{
+
+Result gfx::ShaderCursor::getDereferenced(ShaderCursor& outCursor) const
+{
+ switch (m_typeLayout->getKind())
+ {
+ default:
+ return SLANG_E_INVALID_ARG;
+
+ case slang::TypeReflection::Kind::ConstantBuffer:
+ case slang::TypeReflection::Kind::ParameterBlock:
+ {
+ auto subObject = m_baseObject->getObject(m_offset);
+ outCursor = ShaderCursor(subObject);
+ return SLANG_OK;
+ }
+ }
+}
+
+Result ShaderCursor::getField(Slang::UnownedStringSlice const& name, ShaderCursor& outCursor)
+{
+ // If this cursor is invalid, then can't possible fetch a field.
+ //
+ if (!isValid())
+ return SLANG_E_INVALID_ARG;
+
+ // If the cursor is valid, we want to consider the type of data
+ // it is referencing.
+ //
+ switch (m_typeLayout->getKind())
+ {
+ // The easy/expected case is when the value has a structure type.
+ //
+ case slang::TypeReflection::Kind::Struct:
+ {
+ // We start by looking up the index of a field matching `name`.
+ //
+ // If there is no such field, we have an error.
+ //
+ SlangInt fieldIndex = m_typeLayout->findFieldIndexByName(name.begin(), name.end());
+ if (fieldIndex == -1)
+ return SLANG_E_INVALID_ARG;
+
+ // Once we know the index of the field being referenced,
+ // we create a cursor to point at the field, based on
+ // the offset information already in this cursor, plus
+ // offsets derived from the field's layout.
+ //
+ slang::VariableLayoutReflection* fieldLayout =
+ m_typeLayout->getFieldByIndex((unsigned int)fieldIndex);
+ ShaderCursor fieldCursor;
+
+ // The field cursorwill point into the same parent object.
+ //
+ fieldCursor.m_baseObject = m_baseObject;
+
+ // The type being pointed to is the tyep of the field.
+ //
+ fieldCursor.m_typeLayout = fieldLayout->getTypeLayout();
+
+ // The byte offset is the current offset plus the relative offset of the field.
+ // The offset in binding ranges is computed similarly.
+ //
+ fieldCursor.m_offset.uniformOffset = m_offset.uniformOffset + fieldLayout->getOffset();
+ fieldCursor.m_offset.bindingRangeIndex =
+ m_offset.bindingRangeIndex + m_typeLayout->getFieldBindingRangeOffset(fieldIndex);
+
+ // The index of the field within any binding ranges will be the same
+ // as the index computed for the parent structure.
+ //
+ // Note: this case would arise for an array of structures with texture-type
+ // fields. Suppose we have:
+ //
+ // struct S { Texture2D t; Texture2D u; }
+ // S g[4];
+ //
+ // In this scenario, `g` holds two binding ranges:
+ //
+ // * Range #0 comprises 4 textures, representing `g[...].t`
+ // * Range #1 comprises 4 textures, representing `g[...].u`
+ //
+ // A cursor for `g[2]` would have a `bindingRangeIndex` of zero but
+ // a `bindingArrayIndex` of 2, iindicating that we could end up
+ // referencing either range, but no matter what we know the index
+ // is 2. Thus when we form a cursor for `g[2].u` we want to
+ // apply the binding range offset to get a `bindingRangeIndex` of
+ // 1, while the `bindingArrayIndex` is unmodified.
+ //
+ // The result is that `g[2].u` is stored in range #1 at array index 2.
+ //
+ fieldCursor.m_offset.bindingArrayIndex = m_offset.bindingArrayIndex;
+
+ outCursor = fieldCursor;
+ return SLANG_OK;
+ }
+ break;
+
+ // In some cases the user might be trying to acess a field by name
+ // from a cursor that references a constant buffer or parameter block,
+ // and in these cases we want the access to Just Work.
+ //
+ case slang::TypeReflection::Kind::ConstantBuffer:
+ case slang::TypeReflection::Kind::ParameterBlock:
+ {
+ // We basically need to "dereference" the current cursor
+ // to go from a pointer to a constant buffer to a pointer
+ // to the *contents* of the constant buffer.
+ //
+ ShaderCursor d = getDereferenced();
+ return d.getField(name, outCursor);
+ }
+ break;
+ }
+
+ return SLANG_E_INVALID_ARG;
+}
+
+ShaderCursor ShaderCursor::getElement(Slang::Index index)
+{
+ // TODO: need to auto-dereference various buffer types...
+
+ if (m_typeLayout->getKind() == slang::TypeReflection::Kind::Array)
+ {
+ ShaderCursor elementCursor;
+ elementCursor.m_baseObject = m_baseObject;
+ elementCursor.m_typeLayout = m_typeLayout->getElementTypeLayout();
+ elementCursor.m_offset.uniformOffset =
+ m_offset.uniformOffset +
+ index * m_typeLayout->getElementStride(SLANG_PARAMETER_CATEGORY_UNIFORM);
+ elementCursor.m_offset.bindingRangeIndex = m_offset.bindingRangeIndex;
+ elementCursor.m_offset.bindingArrayIndex =
+ m_offset.bindingArrayIndex * m_typeLayout->getElementCount() + index;
+ return elementCursor;
+ }
+
+ return ShaderCursor();
+}
+
+
+static int _peek(Slang::UnownedStringSlice const& slice)
+{
+ const char* b = slice.begin();
+ const char* e = slice.end();
+ if (b == e)
+ return -1;
+ return *b;
+}
+
+static int _get(Slang::UnownedStringSlice& slice)
+{
+ const char* b = slice.begin();
+ const char* e = slice.end();
+ if (b == e)
+ return -1;
+ auto result = *b++;
+ slice = Slang::UnownedStringSlice(b, e);
+ return result;
+}
+
+Result ShaderCursor::followPath(Slang::UnownedStringSlice const& path, ShaderCursor& ioCursor)
+{
+ ShaderCursor cursor = ioCursor;
+
+ enum
+ {
+ ALLOW_NAME = 0x1,
+ ALLOW_SUBSCRIPT = 0x2,
+ ALLOW_DOT = 0x4,
+ };
+ int state = ALLOW_NAME | ALLOW_SUBSCRIPT;
+
+ Slang::UnownedStringSlice rest = path;
+ for (;;)
+ {
+ int c = _peek(rest);
+
+ if (c == -1)
+ break;
+ else if (c == '.')
+ {
+ if (!(state & ALLOW_DOT))
+ return SLANG_E_INVALID_ARG;
+
+ _get(rest);
+ state = ALLOW_NAME;
+ continue;
+ }
+ else if (c == '[')
+ {
+ if (!(state & ALLOW_SUBSCRIPT))
+ return SLANG_E_INVALID_ARG;
+
+ _get(rest);
+ Slang::Index index = 0;
+ while (_peek(rest) != ']')
+ {
+ int d = _get(rest);
+ if (d >= '0' && d <= '9')
+ {
+ index = index * 10 + (d - '0');
+ }
+ else
+ {
+ return SLANG_E_INVALID_ARG;
+ }
+ }
+
+ if (_peek(rest) != ']')
+ return SLANG_E_INVALID_ARG;
+ _get(rest);
+
+ cursor = cursor.getElement(index);
+ state = ALLOW_DOT | ALLOW_SUBSCRIPT;
+ continue;
+ }
+ else
+ {
+ const char* nameBegin = rest.begin();
+ for (;;)
+ {
+ switch (_peek(rest))
+ {
+ default:
+ _get(rest);
+ continue;
+
+ case -1:
+ case '.':
+ case '[':
+ break;
+ }
+ break;
+ }
+ char const* nameEnd = rest.begin();
+ Slang::UnownedStringSlice name(nameBegin, nameEnd);
+ cursor = cursor.getField(name);
+ state = ALLOW_DOT | ALLOW_SUBSCRIPT;
+ continue;
+ }
+ }
+
+ ioCursor = cursor;
+ return SLANG_OK;
+}
+
+} // namespace gfx