summaryrefslogtreecommitdiff
path: root/tools/gfx/render-graphics-common.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gfx/render-graphics-common.cpp')
-rw-r--r--tools/gfx/render-graphics-common.cpp292
1 files changed, 111 insertions, 181 deletions
diff --git a/tools/gfx/render-graphics-common.cpp b/tools/gfx/render-graphics-common.cpp
index adc943d1d..fb01867d8 100644
--- a/tools/gfx/render-graphics-common.cpp
+++ b/tools/gfx/render-graphics-common.cpp
@@ -6,64 +6,9 @@ using namespace Slang;
namespace gfx
{
-const Slang::Guid GfxGUID::IID_ISlangUnknown = SLANG_UUID_ISlangUnknown;
-const Slang::Guid GfxGUID::IID_IDescriptorSetLayout = SLANG_UUID_IDescriptorSetLayout;
-const Slang::Guid GfxGUID::IID_IDescriptorSet = SLANG_UUID_IDescriptorSet;
-const Slang::Guid GfxGUID::IID_IShaderProgram = SLANG_UUID_IShaderProgram;
-const Slang::Guid GfxGUID::IID_IPipelineLayout = SLANG_UUID_IPipelineLayout;
-const Slang::Guid GfxGUID::IID_IInputLayout = SLANG_UUID_IInputLayout;
-const Slang::Guid GfxGUID::IID_IPipelineState = SLANG_UUID_IPipelineState;
-const Slang::Guid GfxGUID::IID_IResourceView = SLANG_UUID_IResourceView;
-const Slang::Guid GfxGUID::IID_ISamplerState = SLANG_UUID_ISamplerState;
-const Slang::Guid GfxGUID::IID_IResource = SLANG_UUID_IResource;
-const Slang::Guid GfxGUID::IID_IBufferResource = SLANG_UUID_IBufferResource;
-const Slang::Guid GfxGUID::IID_ITextureResource = SLANG_UUID_ITextureResource;
-const Slang::Guid GfxGUID::IID_IRenderer = SLANG_UUID_IRenderer;
-const Slang::Guid GfxGUID::IID_IShaderObjectLayout = SLANG_UUID_IShaderObjectLayout;
-const Slang::Guid GfxGUID::IID_IShaderObject = SLANG_UUID_IShaderObject;
-
-gfx::StageType translateStage(SlangStage slangStage)
-{
- switch (slangStage)
- {
- default:
- SLANG_ASSERT(!"unhandled case");
- return gfx::StageType::Unknown;
-
-#define CASE(FROM, TO) \
- case SLANG_STAGE_##FROM: \
- return gfx::StageType::TO
-
- CASE(VERTEX, Vertex);
- CASE(HULL, Hull);
- CASE(DOMAIN, Domain);
- CASE(GEOMETRY, Geometry);
- CASE(FRAGMENT, Fragment);
-
- CASE(COMPUTE, Compute);
-
- CASE(RAY_GENERATION, RayGeneration);
- CASE(INTERSECTION, Intersection);
- CASE(ANY_HIT, AnyHit);
- CASE(CLOSEST_HIT, ClosestHit);
- CASE(MISS, Miss);
- CASE(CALLABLE, Callable);
-
-#undef CASE
- }
-}
-
-class GraphicsCommonShaderObjectLayout : public IShaderObjectLayout, public RefObject
+class GraphicsCommonShaderObjectLayout : public ShaderObjectLayoutBase
{
public:
- SLANG_REF_OBJECT_IUNKNOWN_ALL
- IShaderObjectLayout* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IShaderObjectLayout)
- return static_cast<IShaderObjectLayout*>(this);
- return nullptr;
- }
-public:
struct BindingRangeInfo
{
slang::BindingType bindingType;
@@ -71,7 +16,12 @@ public:
Index baseIndex;
Index descriptorSetIndex;
Index rangeIndexInDescriptorSet;
- // Index subObjectRangeIndex = -1;
+
+ // Returns true if this binding range consumes a specialization argument slot.
+ bool isSpecializationArg() const
+ {
+ return bindingType == slang::BindingType::ExistentialValue;
+ }
};
struct SubObjectRangeInfo
@@ -91,10 +41,13 @@ public:
struct Builder
{
public:
- Builder(IRenderer* renderer)
+ Builder(RendererBase* renderer)
: m_renderer(renderer)
{}
+ RendererBase* m_renderer;
+ slang::TypeLayoutReflection* m_elementTypeLayout;
+
List<BindingRangeInfo> m_bindingRanges;
List<SubObjectRangeInfo> m_subObjectRanges;
@@ -196,6 +149,15 @@ public:
for (SlangInt r = 0; r < descriptorRangeCount; ++r)
{
auto slangBindingType = typeLayout->getDescriptorSetDescriptorRangeType(s, r);
+
+ switch (slangBindingType)
+ {
+ case slang::BindingType::ExistentialValue:
+ continue;
+ default:
+ break;
+ }
+
auto gfxDescriptorType = _mapDescriptorType(slangBindingType);
IDescriptorSetLayout::SlotRangeDesc descriptorRangeDesc;
@@ -284,9 +246,6 @@ public:
BindingRangeInfo bindingRangeInfo;
bindingRangeInfo.bindingType = slangBindingType;
bindingRangeInfo.count = count;
- // bindingRangeInfo.descriptorSetIndex = descriptorSetIndex;
- // bindingRangeInfo.rangeIndexInDescriptorSet = slotRangeIndex;
- // bindingRangeInfo.subObjectRangeIndex = subObjectRangeIndex;
bindingRangeInfo.baseIndex = baseIndex;
bindingRangeInfo.descriptorSetIndex = descriptorSetIndex;
bindingRangeInfo.rangeIndexInDescriptorSet = rangeIndexInDescriptorSet;
@@ -364,13 +323,10 @@ public:
*outLayout = layout.detach();
return SLANG_OK;
}
-
- IRenderer* m_renderer = nullptr;
- slang::TypeLayoutReflection* m_elementTypeLayout = nullptr;
};
static Result createForElementType(
- IRenderer* renderer,
+ RendererBase* renderer,
slang::TypeLayoutReflection* elementType,
GraphicsCommonShaderObjectLayout** outLayout)
{
@@ -397,15 +353,19 @@ public:
SubObjectRangeInfo const& getSubObjectRange(Index index) { return m_subObjectRanges[index]; }
List<SubObjectRangeInfo> const& getSubObjectRanges() { return m_subObjectRanges; }
- IRenderer* getRenderer() { return m_renderer; }
+ RendererBase* getRenderer() { return m_renderer; }
+ slang::TypeReflection* getType()
+ {
+ return m_elementTypeLayout->getType();
+ }
protected:
Result _init(Builder const* builder)
{
auto renderer = builder->m_renderer;
- m_renderer = renderer;
- m_elementTypeLayout = builder->m_elementTypeLayout;
+ initBase(renderer, builder->m_elementTypeLayout);
+
m_bindingRanges = builder->m_bindingRanges;
for (auto descriptorSetBuildInfo : builder->m_descriptorSetBuildInfos)
@@ -430,16 +390,12 @@ protected:
m_samplerCount = builder->m_samplerCount;
m_combinedTextureSamplerCount = builder->m_combinedTextureSamplerCount;
m_subObjectCount = builder->m_subObjectCount;
-
m_subObjectRanges = builder->m_subObjectRanges;
-
return SLANG_OK;
}
- IRenderer* m_renderer;
List<RefPtr<DescriptorSetInfo>> m_descriptorSets;
List<BindingRangeInfo> m_bindingRanges;
- slang::TypeLayoutReflection* m_elementTypeLayout;
Index m_resourceViewCount = 0;
Index m_samplerCount = 0;
Index m_combinedTextureSamplerCount = 0;
@@ -461,7 +417,7 @@ public:
struct Builder : Super::Builder
{
Builder(IRenderer* renderer)
- : Super::Builder(renderer)
+ : Super::Builder(static_cast<RendererBase*>(renderer))
{}
Result build(EntryPointLayout** outLayout)
@@ -566,7 +522,7 @@ public:
struct Builder : Super::Builder
{
Builder(IRenderer* renderer)
- : Super::Builder(renderer)
+ : Super::Builder(static_cast<RendererBase*>(renderer))
{}
Result build(GraphicsCommonProgramLayout** outLayout)
@@ -709,18 +665,9 @@ protected:
ComPtr<IPipelineLayout> m_pipelineLayout;
};
-class GraphicsCommonShaderObject : public IShaderObject, public RefObject
+class GraphicsCommonShaderObject : public ShaderObjectBase
{
public:
- SLANG_REF_OBJECT_IUNKNOWN_ALL
- IShaderObject* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IShaderObject)
- return static_cast<IShaderObject*>(this);
- return nullptr;
- }
-
-public:
static Result create(
IRenderer* renderer,
GraphicsCommonShaderObjectLayout* layout,
@@ -733,7 +680,7 @@ public:
return SLANG_OK;
}
- IRenderer* getRenderer() { return m_layout->getRenderer(); }
+ RendererBase* getRenderer() { return m_layout->getRenderer(); }
SLANG_NO_THROW UInt SLANG_MCALL getEntryPointCount() SLANG_OVERRIDE { return 0; }
@@ -746,7 +693,7 @@ public:
GraphicsCommonShaderObjectLayout* getLayout()
{
- return m_layout;
+ return static_cast<GraphicsCommonShaderObjectLayout*>(m_layout.Ptr());
}
SLANG_NO_THROW slang::TypeLayoutReflection* SLANG_MCALL getElementTypeLayout() SLANG_OVERRIDE
@@ -772,29 +719,20 @@ public:
{
if (offset.bindingRangeIndex < 0)
return SLANG_E_INVALID_ARG;
- if (offset.bindingRangeIndex >= m_layout->getBindingRangeCount())
+ auto layout = getLayout();
+ if (offset.bindingRangeIndex >= layout->getBindingRangeCount())
return SLANG_E_INVALID_ARG;
- auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex);
-
- // TODO: Is this reasonable to store the base index directly in the binding range?
- m_objects[bindingRange.baseIndex + offset.bindingArrayIndex] =
- reinterpret_cast<GraphicsCommonShaderObject*>(object);
- // auto& subObjectRange =
- // m_layout->getSubObjectRange(bindingRange.subObjectRangeIndex);
- // m_objects[subObjectRange.baseIndex + offset.bindingArrayIndex] = object;
+ auto subObject = static_cast<GraphicsCommonShaderObject*>(object);
+ if (!subObject->m_bindingFinalized)
+ return SLANG_E_INVALID_ARG;
-#if 0
+ auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex);
- SLANG_ASSERT(bindingRange.descriptorSetIndex >= 0);
- SLANG_ASSERT(bindingRange.descriptorSetIndex < m_descriptorSets.getCount());
- auto& descriptorSet = m_descriptorSets[bindingRange.descriptorSetIndex];
+ // TODO: Is this reasonable to store the base index directly in the binding range?
+ m_objects[bindingRange.baseIndex + offset.bindingArrayIndex] = subObject;
- descriptorSet->setConstantBuffer(bindingRange.rangeIndexInDescriptorSet, offset.bindingArrayIndex, buffer);
- return SLANG_OK;
-#else
return SLANG_E_NOT_IMPLEMENTED;
-#endif
}
virtual SLANG_NO_THROW Result SLANG_MCALL
@@ -804,9 +742,10 @@ public:
SLANG_ASSERT(outObject);
if (offset.bindingRangeIndex < 0)
return SLANG_E_INVALID_ARG;
- if (offset.bindingRangeIndex >= m_layout->getBindingRangeCount())
+ auto layout = getLayout();
+ if (offset.bindingRangeIndex >= layout->getBindingRangeCount())
return SLANG_E_INVALID_ARG;
- auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex);
+ auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex);
auto object = m_objects[bindingRange.baseIndex + offset.bindingArrayIndex].Ptr();
object->addRef();
@@ -833,9 +772,10 @@ public:
{
if (offset.bindingRangeIndex < 0)
return SLANG_E_INVALID_ARG;
- if (offset.bindingRangeIndex >= m_layout->getBindingRangeCount())
+ auto layout = getLayout();
+ if (offset.bindingRangeIndex >= layout->getBindingRangeCount())
return SLANG_E_INVALID_ARG;
- auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex);
+ auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex);
m_resourceViews[bindingRange.baseIndex + offset.bindingArrayIndex] = resourceView;
return SLANG_OK;
@@ -846,9 +786,10 @@ public:
{
if (offset.bindingRangeIndex < 0)
return SLANG_E_INVALID_ARG;
- if (offset.bindingRangeIndex >= m_layout->getBindingRangeCount())
+ auto layout = getLayout();
+ if (offset.bindingRangeIndex >= layout->getBindingRangeCount())
return SLANG_E_INVALID_ARG;
- auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex);
+ auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex);
m_samplers[bindingRange.baseIndex + offset.bindingArrayIndex] = sampler;
return SLANG_OK;
@@ -859,9 +800,10 @@ public:
{
if (offset.bindingRangeIndex < 0)
return SLANG_E_INVALID_ARG;
- if (offset.bindingRangeIndex >= m_layout->getBindingRangeCount())
+ auto layout = getLayout();
+ if (offset.bindingRangeIndex >= layout->getBindingRangeCount())
return SLANG_E_INVALID_ARG;
- auto& bindingRange = m_layout->getBindingRange(offset.bindingRangeIndex);
+ auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex);
auto& slot = m_combinedTextureSamplers[bindingRange.baseIndex + offset.bindingArrayIndex];
slot.textureView = textureView;
@@ -869,6 +811,55 @@ public:
return SLANG_OK;
}
+public:
+ // Appends all types that are used to specialize the element type of this shader object in `args` list.
+ virtual Result collectSpecializationArgs(ExtendedShaderObjectTypeList& args) override
+ {
+ if (!m_bindingFinalized)
+ return SLANG_FAIL;
+ auto& subObjectRanges = getLayout()->getSubObjectRanges();
+ // The following logic is built on the assumption that all fields that involve existential types (and
+ // therefore require specialization) will results in a sub-object range in the type layout.
+ // This allows us to simply scan the sub-object ranges to find out all specialization arguments.
+ for (Index subObjIndex = 0; subObjIndex < subObjectRanges.getCount(); subObjIndex++)
+ {
+ // Retrieve the corresponding binding range of the sub object.
+ auto bindingRange = getLayout()->getBindingRange(subObjectRanges[subObjIndex].bindingRangeIndex);
+ switch (bindingRange.bindingType)
+ {
+ case slang::BindingType::ExistentialValue:
+ {
+ // A binding type of `ExistentialValue` means the sub-object represents a interface-typed field.
+ // In this case the specialization argument for this field is the actual specialized type of the bound
+ // shader object. If the shader object's type is an ordinary type without existential fields, then the
+ // type argument will simply be the ordinary type. But if the sub object's type is itself a specialized
+ // type, we need to make sure to use that type as the specialization argument.
+
+ // TODO: need to implement the case where the field is an array of existential values.
+ SLANG_ASSERT(bindingRange.count == 1);
+ ExtendedShaderObjectType specializedSubObjType;
+ SLANG_RETURN_ON_FAIL(m_objects[subObjIndex]->getSpecializedShaderObjectType(&specializedSubObjType));
+ args.add(specializedSubObjType);
+ break;
+ }
+ case slang::BindingType::ParameterBlock:
+ case slang::BindingType::ConstantBuffer:
+ // Currently we only handle the case where the field's type is
+ // `ParameterBlock<SomeStruct>` or `ConstantBuffer<SomeStruct>`, where `SomeStruct` is a struct type
+ // (not directly an interface type). In this case, we just recursively collect the specialization arguments
+ // from the bound sub object.
+ SLANG_RETURN_ON_FAIL(m_objects[subObjIndex]->collectSpecializationArgs(args));
+ // TODO: we need to handle the case where the field is of the form `ParameterBlock<IFoo>`. We should treat
+ // this case the same way as the `ExistentialValue` case here, but currently we lack a mechanism to distinguish
+ // the two scenarios.
+ break;
+ }
+ // TODO: need to handle another case where specialization happens on resources fields e.g. `StructuredBuffer<IFoo>`.
+ }
+ return SLANG_OK;
+ }
+
+
protected:
friend class ProgramVars;
@@ -953,7 +944,7 @@ protected:
IPipelineLayout* pipelineLayout,
Index& ioRootIndex)
{
- GraphicsCommonShaderObjectLayout* layout = m_layout;
+ GraphicsCommonShaderObjectLayout* layout = getLayout();
// Create the descritpor sets required by the layout...
//
@@ -979,7 +970,7 @@ protected:
Result _bindIntoDescriptorSet(
IDescriptorSet* descriptorSet, Index baseRangeIndex, Index subObjectRangeArrayIndex)
{
- GraphicsCommonShaderObjectLayout* layout = m_layout;
+ GraphicsCommonShaderObjectLayout* layout = getLayout();
if (m_buffer)
{
@@ -1063,7 +1054,7 @@ protected:
public:
virtual Result _bindIntoDescriptorSets(ComPtr<IDescriptorSet>* descriptorSets)
{
- GraphicsCommonShaderObjectLayout* layout = m_layout;
+ GraphicsCommonShaderObjectLayout* layout = getLayout();
if (m_buffer)
{
@@ -1134,7 +1125,6 @@ public:
return SLANG_OK;
}
- RefPtr<GraphicsCommonShaderObjectLayout> m_layout = nullptr;
ComPtr<IBufferResource> m_buffer;
List<ComPtr<IResourceView>> m_resourceViews;
@@ -1333,8 +1323,7 @@ Result GraphicsAPIRenderer::initProgramCommon(
SLANG_RETURN_ON_FAIL(builder.build(programLayout.writeRef()));
}
-
- program->m_slangProgram = slangProgram;
+ program->slangProgram = slangProgram;
program->m_layout = programLayout;
return SLANG_OK;
@@ -1347,68 +1336,16 @@ Result SLANG_MCALL
if (!programVars)
return SLANG_E_INVALID_HANDLE;
- programVars->apply(this, pipelineType);
- return SLANG_OK;
-}
+ SLANG_RETURN_ON_FAIL(maybeSpecializePipeline(programVars));
-SLANG_NO_THROW Result SLANG_MCALL
- gfx::GraphicsAPIRenderer::getFeatures(
- const char** outFeatures, UInt bufferSize, UInt* outFeatureCount)
-{
- if (bufferSize >= (UInt)m_features.getCount())
- {
- for (Index i = 0; i < m_features.getCount(); i++)
- {
- outFeatures[i] = m_features[i].getUnownedSlice().begin();
- }
- }
- if (outFeatureCount)
- *outFeatureCount = (UInt)m_features.getCount();
- return SLANG_OK;
-}
-
-SLANG_NO_THROW bool SLANG_MCALL gfx::GraphicsAPIRenderer::hasFeature(const char* featureName)
-{
- return m_features.findFirstIndex([&](Slang::String x) { return x == featureName; }) != -1;
-}
-
-SLANG_NO_THROW Result SLANG_MCALL gfx::GraphicsAPIRenderer::getSlangSession(slang::ISession** outSlangSession)
-{
- *outSlangSession = slangContext.session.get();
- slangContext.session->addRef();
+ // Apply shader parameter bindings.
+ programVars->apply(this, pipelineType);
return SLANG_OK;
}
-GraphicsCommonShaderProgram::~GraphicsCommonShaderProgram()
-{
- // Note: It might not seem like this destructor is needed at all, since
- // it is empty.
- //
- // In pratice, though, it seems to be required because the `m_layout`
- // field is declared in the coresponding header before the `GraphicsCommonProgramLayout`
- // is declared (we only have a forward declaration).
- //
- // `m_layout` is a `RefPtr`, and it seems that the compiler (or at least
- // the Visual Studio compiler) either cannot synthesize a destructor for
- // the type that properly destructs the field, or it simply synthesizes
- // an incorect destructor.
- //
- // I suspect that part of the problem stems from the way that `GraphicsCommonProgramLayout`
- // inherits from `RefObject` via multiple inheritance.
- //
- // No matter what, defining the destructor here in a file where
- // the declaration of `GraphicsCommonProgramLayout` is visible
- // seems to result in a correct destructor being emitted.
- //
- // TODO: Ther simpler and more robust fix would be to move the declaration
- // of `GraphicsCommonProgramLayout` and related types to the header.
-}
-
-IShaderProgram* GraphicsCommonShaderProgram::getInterface(const Guid& guid)
+GraphicsCommonProgramLayout* gfx::GraphicsCommonShaderProgram::getLayout() const
{
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IShaderProgram)
- return static_cast<IShaderProgram*>(this);
- return nullptr;
+ return static_cast<GraphicsCommonProgramLayout*>(m_layout.Ptr());
}
void GraphicsAPIRenderer::preparePipelineDesc(GraphicsPipelineStateDesc& desc)
@@ -1432,11 +1369,4 @@ void GraphicsAPIRenderer::preparePipelineDesc(ComputePipelineStateDesc& desc)
}
}
-IRenderer* gfx::GraphicsAPIRenderer::getInterface(const Guid& guid)
-{
- return (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IRenderer)
- ? static_cast<IRenderer*>(this)
- : nullptr;
-}
-
}