summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--slang-gfx.h6
-rw-r--r--source/core/slang-token-reader.h9
-rw-r--r--tests/compute/array-existential-parameter.slang2
-rw-r--r--tests/compute/cbuffer-legalize.slang2
-rw-r--r--tests/compute/entry-point-uniform-params.slang4
-rw-r--r--tests/compute/global-type-param-in-entrypoint.slang2
-rw-r--r--tests/compute/interface-param-partial-specialize.slang11
-rw-r--r--tests/disabled-tests.txt2
-rw-r--r--tests/language-feature/shader-params/entry-point-uniform-params.slang2
-rw-r--r--tools/gfx-util/shader-cursor.cpp26
-rw-r--r--tools/gfx/d3d12/render-d3d12.cpp16
-rw-r--r--tools/gfx/vulkan/render-vk.cpp25
-rw-r--r--tools/render-test/render-test-main.cpp488
-rw-r--r--tools/render-test/shader-input-layout.cpp1111
-rw-r--r--tools/render-test/shader-input-layout.h190
-rw-r--r--tools/render-test/shader-renderer-util.cpp13
-rw-r--r--tools/render-test/shader-renderer-util.h1
-rw-r--r--tools/render-test/slang-support.cpp1
18 files changed, 1050 insertions, 861 deletions
diff --git a/slang-gfx.h b/slang-gfx.h
index 565580762..cdb9f38cb 100644
--- a/slang-gfx.h
+++ b/slang-gfx.h
@@ -197,6 +197,8 @@ public:
NonPixelShaderResource,
ShaderResource,
GenericRead,
+ CopySource,
+ CopyDest,
CountOf,
};
@@ -268,6 +270,10 @@ public:
return BindFlag::Enum(
BindFlag::PixelShaderResource |
BindFlag::NonPixelShaderResource);
+ case Usage::CopySource:
+ return BindFlag::Enum(0);
+ case Usage::CopyDest:
+ return BindFlag::Enum(0);
default:
return BindFlag::Enum(-1);
}
diff --git a/source/core/slang-token-reader.h b/source/core/slang-token-reader.h
index 0c2d390d2..f08c1674c 100644
--- a/source/core/slang-token-reader.h
+++ b/source/core/slang-token-reader.h
@@ -231,6 +231,15 @@ namespace Slang
return false;
}
}
+ bool AdvanceIf(String token)
+ {
+ if( LookAhead(token) )
+ {
+ ReadToken();
+ return true;
+ }
+ return false;
+ }
bool IsEnd()
{
return tokenPtr == (int)tokens.getCount();
diff --git a/tests/compute/array-existential-parameter.slang b/tests/compute/array-existential-parameter.slang
index f640ba752..fc697969d 100644
--- a/tests/compute/array-existential-parameter.slang
+++ b/tests/compute/array-existential-parameter.slang
@@ -1,6 +1,6 @@
// Test using existential shader parameter that is an interface array.
-//TEST(compute):COMPARE_COMPUTE:-cpu
+//DISABLED_TEST(compute):COMPARE_COMPUTE:-cpu
//DISABLE_TEST(compute):COMPARE_COMPUTE:-cuda
[anyValueSize(8)]
diff --git a/tests/compute/cbuffer-legalize.slang b/tests/compute/cbuffer-legalize.slang
index 3941a8de3..7233f71d6 100644
--- a/tests/compute/cbuffer-legalize.slang
+++ b/tests/compute/cbuffer-legalize.slang
@@ -1,7 +1,7 @@
//TEST(compute):COMPARE_COMPUTE:-cpu -shaderobj
//TEST(compute):COMPARE_COMPUTE:-shaderobj
-//TEST_INPUT: Uniform(data=[1 2 3 4]):name=C.p.c
+//TEST_INPUT: uniform(data=[1 2 3 4]):name=C.p.c
//TEST_INPUT: Texture2D(size=4, content = one):name=C.p.t
//TEST_INPUT: Sampler:name=C.p.s
//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
diff --git a/tests/compute/entry-point-uniform-params.slang b/tests/compute/entry-point-uniform-params.slang
index 1ed9a0646..f97874696 100644
--- a/tests/compute/entry-point-uniform-params.slang
+++ b/tests/compute/entry-point-uniform-params.slang
@@ -35,9 +35,9 @@ ConstantBuffer<Signs> signs;
[numthreads(4, 1, 1)]
void computeMain(
-//TEST_INPUT:root_constants(data=[2 0 0 0 3 0 0 0]):name=stuff
+//TEST_INPUT:uniform(data=[2]):name=stuff
uniform Stuff stuff,
-//TEST_INPUT:root_constants(data=[3]):onlyCPULikeBinding,name=things
+//TEST_INPUT:uniform(data=[3]):name=things
uniform Things things,
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
diff --git a/tests/compute/global-type-param-in-entrypoint.slang b/tests/compute/global-type-param-in-entrypoint.slang
index a82cd88bc..24ee113f5 100644
--- a/tests/compute/global-type-param-in-entrypoint.slang
+++ b/tests/compute/global-type-param-in-entrypoint.slang
@@ -1,6 +1,6 @@
//TEST(compute):COMPARE_RENDER_COMPUTE: -shaderobj
-//TEST_INPUT: cbuffer(data=[1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0], stride=16):name Uniforms
+//TEST_INPUT: cbuffer(data=[1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0]):name Uniforms
//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
//TEST_INPUT: global_type VertImpl
diff --git a/tests/compute/interface-param-partial-specialize.slang b/tests/compute/interface-param-partial-specialize.slang
index f81a1cdb7..9be22c6c4 100644
--- a/tests/compute/interface-param-partial-specialize.slang
+++ b/tests/compute/interface-param-partial-specialize.slang
@@ -3,8 +3,8 @@
// with __Dynamic. This verifies that the handling of
// "partially" specializing an existential type is correct.
-//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cuda -shaderobj
-//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cpu -shaderobj
+//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cuda -shaderobj
+//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cpu -shaderobj
[anyValueSize(8)]
interface IInterface
@@ -38,7 +38,12 @@ void compute(uint tid, Params p)
[numthreads(4, 1, 1)]
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID,
-//TEST_INPUT:ubuffer(data=[rtti(Impl) witness(Impl, IInterface) 1 0], stride=4):name=params.obj
+
+//TEST_INPUT:begin_buffer(stride=8):name=params.obj
+//TEST_INPUT:begin_object(type=Impl)
+//TEST_INPUT:uniform(data=[1]):name=val
+//TEST_INPUT:end
+//TEST_INPUT:end
uniform Params params)
{
uint tid = dispatchThreadID.x;
diff --git a/tests/disabled-tests.txt b/tests/disabled-tests.txt
index 69538a7de..ffc9736db 100644
--- a/tests/disabled-tests.txt
+++ b/tests/disabled-tests.txt
@@ -39,3 +39,5 @@ These tests will need to be re-enabled together with changes to the shader objec
* render/render0.hlsl
* render/tess.hlsl
* render/unused-discard.hlsl
+* compute/interface-param-partial-specialize.slang
+* compute/array-existential-parameter.slang
diff --git a/tests/language-feature/shader-params/entry-point-uniform-params.slang b/tests/language-feature/shader-params/entry-point-uniform-params.slang
index 9bcb36f27..5b0279bb5 100644
--- a/tests/language-feature/shader-params/entry-point-uniform-params.slang
+++ b/tests/language-feature/shader-params/entry-point-uniform-params.slang
@@ -23,7 +23,7 @@ int test(int val, int a, int b)
[shader("compute")]
void computeMain(
-//TEST_INPUT:root_constants(data=[256 1]):name=d
+//TEST_INPUT:uniform(data=[256 1]):name=d
uniform Data d,
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
diff --git a/tools/gfx-util/shader-cursor.cpp b/tools/gfx-util/shader-cursor.cpp
index 769643e75..c2c34f5a5 100644
--- a/tools/gfx-util/shader-cursor.cpp
+++ b/tools/gfx-util/shader-cursor.cpp
@@ -42,7 +42,7 @@ Result ShaderCursor::getField(const char* name, const char* nameEnd, ShaderCurso
//
SlangInt fieldIndex = m_typeLayout->findFieldIndexByName(name, nameEnd);
if (fieldIndex == -1)
- return SLANG_E_INVALID_ARG;
+ break;
// Once we know the index of the field being referenced,
// we create a cursor to point at the field, based on
@@ -115,6 +115,30 @@ Result ShaderCursor::getField(const char* name, const char* nameEnd, ShaderCurso
break;
}
+ // If a cursor is pointing at a root shader object (created for a
+ // program), then we will also iterate over the entry point shader
+ // objects attached to it and look for a matching parameter name
+ // on them.
+ //
+ // This is a bit of "do what I mean" logic and could potentially
+ // lead to problems if there could be multiple entry points with
+ // the same parameter name.
+ //
+ // TODO: figure out whether we should support this long-term.
+ //
+ auto entryPointCount = (gfx::Int) m_baseObject->getEntryPointCount();
+ for( gfx::Int e = 0; e < entryPointCount; ++e )
+ {
+ ComPtr<IShaderObject> entryPoint;
+ m_baseObject->getEntryPoint(e, entryPoint.writeRef());
+
+ ShaderCursor entryPointCursor(entryPoint);
+
+ auto result = entryPointCursor.getField(name, nameEnd, outCursor);
+ if(SLANG_SUCCEEDED(result))
+ return result;
+ }
+
return SLANG_E_INVALID_ARG;
}
diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp
index fb9b3d143..e2629dc53 100644
--- a/tools/gfx/d3d12/render-d3d12.cpp
+++ b/tools/gfx/d3d12/render-d3d12.cpp
@@ -2840,11 +2840,15 @@ public:
size_t srcOffset,
size_t size) override
{
- SLANG_UNUSED(dst);
- SLANG_UNUSED(srcOffset);
- SLANG_UNUSED(src);
- SLANG_UNUSED(dstOffset);
- SLANG_UNUSED(size);
+ auto dstBuffer = static_cast<BufferResourceImpl*>(dst);
+ auto srcBuffer = static_cast<BufferResourceImpl*>(src);
+
+ m_commandBuffer->m_cmdList->CopyBufferRegion(
+ dstBuffer->m_resource.getResource(),
+ dstOffset,
+ srcBuffer->m_resource.getResource(),
+ srcOffset,
+ size);
}
virtual SLANG_NO_THROW void SLANG_MCALL uploadBufferData(
IBufferResource* dst,
@@ -3810,6 +3814,8 @@ static D3D12_RESOURCE_STATES _calcResourceState(IResource::Usage usage)
case Usage::ShaderResource: return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE |
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
case Usage::GenericRead: return D3D12_RESOURCE_STATE_GENERIC_READ;
+ case Usage::CopySource: return D3D12_RESOURCE_STATE_COPY_SOURCE;
+ case Usage::CopyDest: return D3D12_RESOURCE_STATE_COPY_DEST;
default: return D3D12_RESOURCE_STATES(0);
}
}
diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp
index 763cea089..d4396429b 100644
--- a/tools/gfx/vulkan/render-vk.cpp
+++ b/tools/gfx/vulkan/render-vk.cpp
@@ -3116,11 +3116,26 @@ public:
size_t srcOffset,
size_t size) override
{
- SLANG_UNUSED(dst);
- SLANG_UNUSED(srcOffset);
- SLANG_UNUSED(src);
- SLANG_UNUSED(dstOffset);
- SLANG_UNUSED(size);
+ auto& vkAPI = m_commandBuffer->m_renderer->m_api;
+
+ auto dstBuffer = static_cast<BufferResourceImpl*>(dst);
+ auto srcBuffer = static_cast<BufferResourceImpl*>(src);
+
+ VkBufferCopy copyRegion;
+ copyRegion.dstOffset = dstOffset;
+ copyRegion.srcOffset = srcOffset;
+ copyRegion.size = size;
+
+ // Note: Vulkan puts the source buffer first in the copy
+ // command, going against the dominant tradition for copy
+ // operations in C/C++.
+ //
+ vkAPI.vkCmdCopyBuffer(
+ m_commandBuffer->m_commandBuffer,
+ srcBuffer->m_buffer.m_buffer,
+ dstBuffer->m_buffer.m_buffer,
+ /* regionCount: */ 1,
+ &copyRegion);
}
virtual SLANG_NO_THROW void SLANG_MCALL
uploadBufferData(IBufferResource* buffer, size_t offset, size_t size, void* data) override
diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp
index 02f20dd40..325f12e49 100644
--- a/tools/render-test/render-test-main.cpp
+++ b/tools/render-test/render-test-main.cpp
@@ -74,7 +74,6 @@ struct ShaderOutputPlan
{
struct Item
{
- Index inputLayoutEntryIndex;
ComPtr<IResource> resource;
slang::TypeLayoutReflection* typeLayout = nullptr;
};
@@ -82,25 +81,25 @@ struct ShaderOutputPlan
List<Item> items;
};
-class RenderTestApp : public RefObject
+class RenderTestApp
{
public:
Result update();
// At initialization time, we are going to load and compile our Slang shader
// code, and then create the API objects we need for rendering.
- virtual Result initialize(
+ Result initialize(
SlangSession* session,
IDevice* device,
const Options& options,
- const ShaderCompilerUtil::Input& input) = 0;
+ const ShaderCompilerUtil::Input& input);
void runCompute(IComputeCommandEncoder* encoder);
void renderFrame(IRenderCommandEncoder* encoder);
void finalize();
- virtual void applyBinding(PipelineType pipelineType, ICommandEncoder* encoder) = 0;
- virtual void setProjectionMatrix(IResourceCommandEncoder* encoder) = 0;
- virtual Result writeBindingOutput(const char* fileName) = 0;
+ void applyBinding(PipelineType pipelineType, ICommandEncoder* encoder);
+ void setProjectionMatrix(IResourceCommandEncoder* encoder);
+ Result writeBindingOutput(const char* fileName);
Result writeScreen(const char* filename);
@@ -112,7 +111,6 @@ protected:
Options::ShaderProgramType shaderType,
const ShaderCompilerUtil::Input& input);
void _initializeRenderPass();
- virtual void finalizeImpl();
uint64_t m_startTicks;
@@ -135,256 +133,253 @@ protected:
ShaderInputLayout m_shaderInputLayout; ///< The binding layout
Options m_options;
-};
-
-class ShaderObjectRenderTestApp : public RenderTestApp
-{
-public:
- virtual void applyBinding(PipelineType pipelineType, ICommandEncoder* encoder) SLANG_OVERRIDE;
- virtual void setProjectionMatrix(IResourceCommandEncoder* encoder) SLANG_OVERRIDE;
- virtual Result initialize(
- SlangSession* session,
- IDevice* device,
- const Options& options,
- const ShaderCompilerUtil::Input& input) SLANG_OVERRIDE;
- virtual Result writeBindingOutput(const char* fileName) override;
-
-protected:
- virtual void finalizeImpl() SLANG_OVERRIDE;
ComPtr<IShaderObject> m_programVars;
ShaderOutputPlan m_outputPlan;
};
-SlangResult _assignVarsFromLayout(
- IDevice* device,
- IShaderObject* shaderObject,
- ShaderInputLayout const& layout,
- ShaderOutputPlan& ioOutputPlan,
- slang::ProgramLayout* slangReflection)
+struct AssignValsFromLayoutContext
{
- ShaderCursor rootCursor = ShaderCursor(shaderObject);
-
- const int textureBindFlags = IResource::BindFlag::NonPixelShaderResource | IResource::BindFlag::PixelShaderResource;
-
- Index entryCount = layout.entries.getCount();
- for(Index entryIndex = 0; entryIndex < entryCount; ++entryIndex)
+ IDevice* device;
+ ShaderOutputPlan& outputPlan;
+ slang::ProgramLayout* slangReflection;
+
+ AssignValsFromLayoutContext(
+ IDevice* device,
+ ShaderOutputPlan& outputPlan,
+ slang::ProgramLayout* slangReflection)
+ : device(device)
+ , outputPlan(outputPlan)
+ , slangReflection(slangReflection)
+ {}
+
+ void maybeAddOutput(ShaderCursor const& dstCursor, ShaderInputLayout::Val* srcVal, IResource* resource)
{
- auto& entry = layout.entries[entryIndex];
- if(entry.name.getLength() == 0)
+ if(srcVal->isOutput)
{
- StdWriters::getError().print("error: entries in `ShaderInputLayout` must include a name\n");
- return SLANG_E_INVALID_ARG;
+ ShaderOutputPlan::Item item;
+ item.resource = resource;
+ item.typeLayout = dstCursor.getTypeLayout();
+ outputPlan.items.add(item);
}
+ }
- auto entryCursor = rootCursor.getPath(entry.name.getBuffer());
+ SlangResult assignData(ShaderCursor const& dstCursor, ShaderInputLayout::DataVal* srcVal)
+ {
+ const size_t bufferSize = srcVal->bufferData.getCount() * sizeof(uint32_t);
- if(!entryCursor.isValid())
+ ShaderCursor dataCursor = dstCursor;
+ switch(dataCursor.getTypeLayout()->getKind())
{
- for(gfx::UInt i = 0; i < shaderObject->getEntryPointCount(); i++)
- {
- entryCursor = ShaderCursor(shaderObject->getEntryPoint(i)).getPath(entry.name.getBuffer());
- if(entryCursor.isValid())
- break;
- }
+ case slang::TypeReflection::Kind::ConstantBuffer:
+ case slang::TypeReflection::Kind::ParameterBlock:
+ dataCursor = dataCursor.getDereferenced();
+ break;
+
+ default:
+ break;
+
}
+ SLANG_RETURN_ON_FAIL(dataCursor.setData(srcVal->bufferData.getBuffer(), bufferSize));
+ return SLANG_OK;
+ }
+
+ SlangResult assignBuffer(ShaderCursor const& dstCursor, ShaderInputLayout::BufferVal* srcVal)
+ {
+ const InputBufferDesc& srcBuffer = srcVal->bufferDesc;
+ auto& bufferData = srcVal->bufferData;
+ const size_t bufferSize = bufferData.getCount() * sizeof(uint32_t);
+
+ ComPtr<IBufferResource> bufferResource;
+ SLANG_RETURN_ON_FAIL(ShaderRendererUtil::createBufferResource(srcBuffer, /*entry.isOutput,*/ bufferSize, bufferData.getBuffer(), device, bufferResource));
+
+ IResourceView::Desc viewDesc;
+ viewDesc.type = IResourceView::Type::UnorderedAccess;
+ viewDesc.format = srcBuffer.format;
+ auto bufferView = device->createBufferView(
+ bufferResource,
+ viewDesc);
+ dstCursor.setResource(bufferView);
+ maybeAddOutput(dstCursor, srcVal, bufferResource);
+
+ return SLANG_OK;
+ }
+
+ SlangResult assignCombinedTextureSampler(ShaderCursor const& dstCursor, ShaderInputLayout::CombinedTextureSamplerVal* srcVal)
+ {
+ auto& textureEntry = srcVal->textureVal;
+ auto& samplerEntry = srcVal->samplerVal;
+
+ ComPtr<ITextureResource> texture;
+ SLANG_RETURN_ON_FAIL(ShaderRendererUtil::generateTextureResource(
+ textureEntry->textureDesc, textureBindFlags, device, texture));
- if(!entryCursor.isValid())
+ auto sampler = _createSamplerState(device, samplerEntry->samplerDesc);
+
+ IResourceView::Desc viewDesc;
+ viewDesc.type = IResourceView::Type::ShaderResource;
+ auto textureView = device->createTextureView(
+ texture,
+ viewDesc);
+
+ dstCursor.setCombinedTextureSampler(textureView, sampler);
+ maybeAddOutput(dstCursor, srcVal, texture);
+
+ return SLANG_OK;
+ }
+
+ static const int textureBindFlags = IResource::BindFlag::NonPixelShaderResource | IResource::BindFlag::PixelShaderResource;
+
+ SlangResult assignTexture(ShaderCursor const& dstCursor, ShaderInputLayout::TextureVal* srcVal)
+ {
+ ComPtr<ITextureResource> texture;
+ SLANG_RETURN_ON_FAIL(ShaderRendererUtil::generateTextureResource(
+ srcVal->textureDesc, textureBindFlags, device, texture));
+
+ // TODO: support UAV textures...
+
+ IResourceView::Desc viewDesc;
+ viewDesc.type = IResourceView::Type::ShaderResource;
+ viewDesc.format = texture->getDesc()->format;
+ auto textureView = device->createTextureView(
+ texture,
+ viewDesc);
+
+ if (!textureView)
{
- StdWriters::getError().print("error: could not find shader parameter matching '%s'\n", entry.name.begin());
- return SLANG_E_INVALID_ARG;
+ return SLANG_FAIL;
}
- slang::TypeLayoutReflection* typeLayout = entryCursor.getTypeLayout();
- ComPtr<IResource> resource;
- switch(entry.type)
- {
- case ShaderInputType::Uniform:
- {
- const size_t bufferSize = entry.bufferData.getCount() * sizeof(uint32_t);
+ dstCursor.setResource(textureView);
+ maybeAddOutput(dstCursor, srcVal, texture);
+ return SLANG_OK;
+ }
- ShaderCursor dataCursor = entryCursor;
- switch(dataCursor.getTypeLayout()->getKind())
- {
- case slang::TypeReflection::Kind::ConstantBuffer:
- case slang::TypeReflection::Kind::ParameterBlock:
- dataCursor = dataCursor.getDereferenced();
- break;
+ SlangResult assignSampler(ShaderCursor const& dstCursor, ShaderInputLayout::SamplerVal* srcVal)
+ {
+ auto sampler = _createSamplerState(device, srcVal->samplerDesc);
- default:
- break;
+ dstCursor.setSampler(sampler);
+ return SLANG_OK;
+ }
- }
+ SlangResult assignAggregate(ShaderCursor const& dstCursor, ShaderInputLayout::AggVal* srcVal)
+ {
+ Index fieldCount = srcVal->fields.getCount();
+ for(Index fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex)
+ {
+ auto& field = srcVal->fields[fieldIndex];
- dataCursor.setData(entry.bufferData.getBuffer(), bufferSize);
+ if(field.name.getLength() == 0)
+ {
+ StdWriters::getError().print("error: entries in `ShaderInputLayout` must include a name\n");
+ return SLANG_E_INVALID_ARG;
}
- break;
- case ShaderInputType::Buffer:
- {
- const InputBufferDesc& srcBuffer = entry.bufferDesc;
- const size_t bufferSize = entry.bufferData.getCount() * sizeof(uint32_t);
+ auto fieldCursor = dstCursor.getPath(field.name.getBuffer());
- switch(srcBuffer.type)
- {
- case InputBufferType::ConstantBuffer:
- {
- // A `cbuffer` input line actually represents the data we
- // want to write *into* the buffer, and shouldn't
- // allocate a buffer itself.
- //
- entryCursor.getDereferenced().setData(entry.bufferData.getBuffer(), bufferSize);
- }
- break;
-
- case InputBufferType::RootConstantBuffer:
- {
- // A `root_constants` input line actually represents the data we
- // want to write *into* the buffer, and shouldn't
- // allocate a buffer itself.
- //
- // Note: we are not doing `.getDereferenced()` here because the
- // `root_constant` line should be referring to a parameter value
- // inside the root-constant range, and not the range/buffer itself.
- //
- entryCursor.setData(entry.bufferData.getBuffer(), bufferSize);
- }
- break;
-
- default:
- {
-
- ComPtr<IBufferResource> bufferResource;
- SLANG_RETURN_ON_FAIL(ShaderRendererUtil::createBufferResource(entry.bufferDesc, entry.isOutput, bufferSize, entry.bufferData.getBuffer(), device, bufferResource));
- resource = bufferResource;
-
- IResourceView::Desc viewDesc;
- viewDesc.type = IResourceView::Type::UnorderedAccess;
- viewDesc.format = srcBuffer.format;
- auto bufferView = device->createBufferView(
- bufferResource,
- viewDesc);
- entryCursor.setResource(bufferView);
- }
- break;
- }
+ if(!fieldCursor.isValid())
+ {
+ StdWriters::getError().print("error: could not find shader parameter matching '%s'\n", field.name.begin());
+ return SLANG_E_INVALID_ARG;
}
- break;
- case ShaderInputType::CombinedTextureSampler:
- {
- ComPtr<ITextureResource> texture;
- SLANG_RETURN_ON_FAIL(ShaderRendererUtil::generateTextureResource(
- entry.textureDesc, textureBindFlags, device, texture));
- resource = texture;
+ assign(fieldCursor, field.val);
+ }
+ return SLANG_OK;
+ }
- auto sampler = _createSamplerState(device, entry.samplerDesc);
+ SlangResult assignObject(ShaderCursor const& dstCursor, ShaderInputLayout::ObjectVal* srcVal)
+ {
+ auto typeName = srcVal->typeName;
+ slang::TypeReflection* slangType = nullptr;
+ if(typeName.getLength() != 0)
+ {
+ // If the input line specified the name of the type
+ // to allocate, then we use it directly.
+ //
+ slangType = slangReflection->findTypeByName(typeName.getBuffer());
+ }
+ else
+ {
+ // if the user did not specify what type to allocate,
+ // then we will infer the type from the type of the
+ // value pointed to by `entryCursor`.
+ //
+ auto slangTypeLayout = dstCursor.getTypeLayout();
+ switch(slangTypeLayout->getKind())
+ {
+ default:
+ break;
+
+ case slang::TypeReflection::Kind::ConstantBuffer:
+ case slang::TypeReflection::Kind::ParameterBlock:
+ // If the cursor is pointing at a constant buffer
+ // or parameter block, then we assume the user
+ // actually means to allocate an object based on
+ // the element type of the block.
+ //
+ slangTypeLayout = slangTypeLayout->getElementTypeLayout();
+ break;
+ }
+ slangType = slangTypeLayout->getType();
+ }
- IResourceView::Desc viewDesc;
- viewDesc.type = IResourceView::Type::ShaderResource;
- auto textureView = device->createTextureView(
- texture,
- viewDesc);
+ ComPtr<IShaderObject> shaderObject = device->createShaderObject(slangType);
- entryCursor.setCombinedTextureSampler(textureView, sampler);
- }
- break;
+ assign(ShaderCursor(shaderObject), srcVal->contentVal);
- case ShaderInputType::Texture:
- {
- ComPtr<ITextureResource> texture;
- SLANG_RETURN_ON_FAIL(ShaderRendererUtil::generateTextureResource(
- entry.textureDesc, textureBindFlags, device, texture));
- resource = texture;
+ dstCursor.setObject(shaderObject);
+ return SLANG_OK;
+ }
- // TODO: support UAV textures...
+ SlangResult assign(ShaderCursor const& dstCursor, ShaderInputLayout::ValPtr const& srcVal)
+ {
+ auto& entryCursor = dstCursor;
+ switch(srcVal->kind)
+ {
+ case ShaderInputType::UniformData:
+ return assignData(dstCursor, (ShaderInputLayout::DataVal*) srcVal.Ptr());
- IResourceView::Desc viewDesc;
- viewDesc.type = IResourceView::Type::ShaderResource;
- viewDesc.format = texture->getDesc()->format;
- auto textureView = device->createTextureView(
- texture,
- viewDesc);
+ case ShaderInputType::Buffer:
+ return assignBuffer(dstCursor, (ShaderInputLayout::BufferVal*) srcVal.Ptr());
- if (!textureView)
- {
- return SLANG_FAIL;
- }
+ case ShaderInputType::CombinedTextureSampler:
+ return assignCombinedTextureSampler(dstCursor, (ShaderInputLayout::CombinedTextureSamplerVal*) srcVal.Ptr());
- entryCursor.setResource(textureView);
- }
- break;
+ case ShaderInputType::Texture:
+ return assignTexture(dstCursor, (ShaderInputLayout::TextureVal*) srcVal.Ptr());
case ShaderInputType::Sampler:
- {
- auto sampler = _createSamplerState(device, entry.samplerDesc);
-
- entryCursor.setSampler(sampler);
- }
- break;
+ return assignSampler(dstCursor, (ShaderInputLayout::SamplerVal*) srcVal.Ptr());
case ShaderInputType::Object:
- {
- auto typeName = entry.objectDesc.typeName;
- slang::TypeReflection* slangType = nullptr;
- if(typeName.getLength() != 0)
- {
- // If the input line specified the name of the type
- // to allocate, then we use it directly.
- //
- slangType = slangReflection->findTypeByName(typeName.getBuffer());
- }
- else
- {
- // if the user did not specify what type to allocate,
- // then we will infer the type from the type of the
- // value pointed to by `entryCursor`.
- //
- auto slangTypeLayout = entryCursor.getTypeLayout();
- switch(slangTypeLayout->getKind())
- {
- default:
- break;
-
- case slang::TypeReflection::Kind::ConstantBuffer:
- case slang::TypeReflection::Kind::ParameterBlock:
- // If the cursor is pointing at a constant buffer
- // or parameter block, then we assume the user
- // actually means to allocate an object based on
- // the element type of the block.
- //
- slangTypeLayout = slangTypeLayout->getElementTypeLayout();
- break;
- }
- slangType = slangTypeLayout->getType();
- }
+ return assignObject(dstCursor, (ShaderInputLayout::ObjectVal*) srcVal.Ptr());
- ComPtr<IShaderObject> shaderObject = device->createShaderObject(slangType);
-
- entryCursor.setObject(shaderObject);
- }
- break;
+ case ShaderInputType::Aggregate:
+ return assignAggregate(dstCursor, (ShaderInputLayout::AggVal*) srcVal.Ptr());
default:
assert(!"Unhandled type");
return SLANG_FAIL;
}
-
- if(entry.isOutput)
- {
- ShaderOutputPlan::Item item;
- item.inputLayoutEntryIndex = entryIndex;
- item.resource = resource;
- item.typeLayout = typeLayout;
- ioOutputPlan.items.add(item);
- }
-
}
- return SLANG_OK;
+};
+
+SlangResult _assignVarsFromLayout(
+ IDevice* device,
+ IShaderObject* shaderObject,
+ ShaderInputLayout const& layout,
+ ShaderOutputPlan& ioOutputPlan,
+ slang::ProgramLayout* slangReflection)
+{
+ AssignValsFromLayoutContext context(device, ioOutputPlan, slangReflection);
+ ShaderCursor rootCursor = ShaderCursor(shaderObject);
+ return context.assign(rootCursor, layout.rootVal);
}
-void ShaderObjectRenderTestApp::applyBinding(PipelineType pipelineType, ICommandEncoder* encoder)
+void RenderTestApp::applyBinding(PipelineType pipelineType, ICommandEncoder* encoder)
{
switch (pipelineType)
{
@@ -409,7 +404,7 @@ void ShaderObjectRenderTestApp::applyBinding(PipelineType pipelineType, ICommand
}
}
-SlangResult ShaderObjectRenderTestApp::initialize(
+SlangResult RenderTestApp::initialize(
SlangSession* session,
IDevice* device,
const Options& options,
@@ -507,12 +502,6 @@ SlangResult ShaderObjectRenderTestApp::initialize(
return m_pipelineState ? SLANG_OK : SLANG_FAIL;
}
-void ShaderObjectRenderTestApp::finalizeImpl()
-{
- m_programVars = nullptr;
- RenderTestApp::finalizeImpl();
-}
-
Result RenderTestApp::_initializeShaders(
SlangSession* session,
IDevice* device,
@@ -602,7 +591,7 @@ void RenderTestApp::_initializeRenderPass()
m_device->createRenderPassLayout(renderPassDesc, m_renderPass.writeRef());
}
-void ShaderObjectRenderTestApp::setProjectionMatrix(IResourceCommandEncoder* encoder)
+void RenderTestApp::setProjectionMatrix(IResourceCommandEncoder* encoder)
{
SLANG_UNUSED(encoder);
auto info = m_device->getDeviceInfo();
@@ -639,8 +628,7 @@ void RenderTestApp::runCompute(IComputeCommandEncoder* encoder)
void RenderTestApp::finalize()
{
- finalizeImpl();
-
+ m_programVars = nullptr;
m_inputLayout = nullptr;
m_vertexBuffer = nullptr;
m_shaderProgram = nullptr;
@@ -653,11 +641,7 @@ void RenderTestApp::finalize()
m_device = nullptr;
}
-void RenderTestApp::finalizeImpl()
-{
-}
-
-Result ShaderObjectRenderTestApp::writeBindingOutput(const char* fileName)
+Result RenderTestApp::writeBindingOutput(const char* fileName)
{
// Wait until everything is complete
m_queue->wait();
@@ -671,23 +655,51 @@ Result ShaderObjectRenderTestApp::writeBindingOutput(const char* fileName)
for(auto outputItem : m_outputPlan.items)
{
- auto& inputEntry = m_shaderInputLayout.entries[outputItem.inputLayoutEntryIndex];
- assert(inputEntry.isOutput);
-
auto resource = outputItem.resource;
if (resource && resource->getType() == IResource::Type::Buffer)
{
IBufferResource* bufferResource = static_cast<IBufferResource*>(resource.get());
- const size_t bufferSize = bufferResource->getDesc()->sizeInBytes;
+ auto bufferDesc = *bufferResource->getDesc();
+ const size_t bufferSize = bufferDesc.sizeInBytes;
ComPtr<ISlangBlob> blob;
- m_device->readBufferResource(bufferResource, 0, bufferSize, blob.writeRef());
+ if(bufferDesc.cpuAccessFlags & IResource::AccessFlag::Read)
+ {
+ // The buffer is already allocated for CPU access, so we can read it back directly.
+ //
+ m_device->readBufferResource(bufferResource, 0, bufferSize, blob.writeRef());
+ }
+ else
+ {
+ // The buffer is not CPU-readable, so we will copy it using a staging buffer.
+
+ auto stagingBufferDesc = bufferDesc;
+ stagingBufferDesc.cpuAccessFlags = IResource::AccessFlag::Read;
+ stagingBufferDesc.bindFlags = 0;
+
+ ComPtr<IBufferResource> stagingBuffer;
+ SLANG_RETURN_ON_FAIL(m_device->createBufferResource(IResource::Usage::CopyDest, stagingBufferDesc, nullptr, stagingBuffer.writeRef()));
+
+ ComPtr<ICommandBuffer> commandBuffer;
+ SLANG_RETURN_ON_FAIL(m_queue->createCommandBuffer(commandBuffer.writeRef()));
+
+ ComPtr<IResourceCommandEncoder> encoder;
+ commandBuffer->encodeResourceCommands(encoder.writeRef());
+ encoder->copyBuffer(stagingBuffer, 0, bufferResource, 0, bufferSize);
+ encoder->endEncoding();
+
+ commandBuffer->close();
+ m_queue->executeCommandBuffer(commandBuffer);
+ m_queue->wait();
+
+ m_device->readBufferResource(stagingBuffer, 0, bufferSize, blob.writeRef());
+ }
+
if (!blob)
{
return SLANG_FAIL;
}
const SlangResult res = ShaderInputLayout::writeBinding(
- inputEntry,
m_options.outputUsingType ? outputItem.typeLayout : nullptr, // TODO: always output using type
blob->getBufferPointer(),
bufferSize,
@@ -696,7 +708,8 @@ Result ShaderObjectRenderTestApp::writeBindingOutput(const char* fileName)
}
else
{
- printf("invalid output type at %d.\n", int(outputItem.inputLayoutEntryIndex));
+ auto typeName = outputItem.typeLayout->getName();
+ printf("invalid output type '%s'.\n", typeName ? typeName : "UNKNOWN");
}
}
return SLANG_OK;
@@ -1101,15 +1114,12 @@ static SlangResult _innerMain(Slang::StdWriters* stdWriters, SlangSession* sessi
}
{
- // TODO: We shouldn't need to heap-allocate the `ShaderObjectRenderTestApp`
- // since there is no longer any meaningful inheritance going on.
- //
- RefPtr<RenderTestApp> app = new ShaderObjectRenderTestApp();
+ RenderTestApp app;
renderDocBeginFrame();
- SLANG_RETURN_ON_FAIL(app->initialize(session, device, options, input));
- app->update();
+ SLANG_RETURN_ON_FAIL(app.initialize(session, device, options, input));
+ app.update();
renderDocEndFrame();
- app->finalize();
+ app.finalize();
return SLANG_OK;
}
}
diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp
index 071c694b5..5783c6eb8 100644
--- a/tools/render-test/shader-input-layout.cpp
+++ b/tools/render-test/shader-input-layout.cpp
@@ -42,596 +42,641 @@ namespace renderer_test
return SLANG_SCALAR_TYPE_NONE;
}
- Index ShaderInputLayout::findEntryIndexByName(const String& name) const
+ void ShaderInputLayout::AggVal::addField(ShaderInputLayout::Field const& field)
{
- const Index count = Index(entries.getCount());
- for (Index i = 0; i < count; ++i)
- {
- const auto& entry = entries[i];
- if (entry.name == name)
- {
- return Index(i);
- }
- }
- return -1;
+ fields.add(field);
}
- static bool _isCPULikeBindingTarget(SlangCompileTarget target)
+ void ShaderInputLayout::ArrayVal::addField(ShaderInputLayout::Field const& field)
{
- // CUDA and C++ are 'CPULike' in terms of their binding mechanism
- switch (target)
+ vals.add(field.val);
+ }
+
+ class ShaderInputLayoutFormatException : public Exception
+ {
+ public:
+ ShaderInputLayoutFormatException(String message)
+ : Exception(message)
+ {}
+ };
+
+ struct ShaderInputLayoutParser
+ {
+ ShaderInputLayout* layout;
+ RandomGenerator* rand;
+
+ ShaderInputLayoutParser(ShaderInputLayout* layout, RandomGenerator* rand)
+ : layout(layout)
+ , rand(rand)
+ {}
+
+ RefPtr<ShaderInputLayout::ParentVal> parentVal;
+ List<RefPtr<ShaderInputLayout::ParentVal>> parentValStack;
+
+ SlangResult parseOption(TokenReader& parser, String const& word, ShaderInputLayout::TextureVal* val)
{
- case SLANG_C_SOURCE:
- case SLANG_CPP_SOURCE:
- case SLANG_EXECUTABLE:
- case SLANG_SHARED_LIBRARY:
- case SLANG_HOST_CALLABLE:
- case SLANG_CUDA_SOURCE:
- case SLANG_PTX:
+ if (word == "depth")
+ {
+ val->textureDesc.isDepthTexture = true;
+ }
+ else if (word == "arrayLength")
+ {
+ parser.Read("=");
+ val->textureDesc.arrayLength = parser.ReadInt();
+ }
+ else if (word == "size")
{
- return true;
+ parser.Read("=");
+ auto size = parser.ReadInt();
+ val->textureDesc.size = size;
}
- default: return false;
+ else if (word == "content")
+ {
+ parser.Read("=");
+ auto contentWord = parser.ReadWord();
+ if (contentWord == "zero")
+ val->textureDesc.content = InputTextureContent::Zero;
+ else if (contentWord == "one")
+ val->textureDesc.content = InputTextureContent::One;
+ else if (contentWord == "chessboard")
+ val->textureDesc.content = InputTextureContent::ChessBoard;
+ else
+ val->textureDesc.content = InputTextureContent::Gradient;
+ }
+ else if(word == "mipMaps")
+ {
+ parser.Read("=");
+ val->textureDesc.mipMapCount = int(parser.ReadInt());
+ }
+ else if(word == "format")
+ {
+ val->textureDesc.format = parseFormatOption(parser);
+ }
+ else
+ {
+ return SLANG_FAIL;
+ }
+ return SLANG_OK;
}
- }
- void ShaderInputLayout::updateForTarget(SlangCompileTarget target)
- {
- if (!_isCPULikeBindingTarget(target))
+ SlangResult parseOption(TokenReader& parser, String const& word, ShaderInputLayout::SamplerVal* val)
{
- int count = int(entries.getCount());
- for (int i = 0; i < count; ++i)
+ if (word == "depthCompare")
{
- auto& entry = entries[i];
- if (entry.onlyCPULikeBinding)
- {
- entries.removeAt(i);
- i--;
- count--;
- }
+ val->samplerDesc.isCompareSampler = true;
}
+ else
+ {
+ return SLANG_FAIL;
+ }
+ return SLANG_OK;
}
- }
- void ShaderInputLayout::parse(RandomGenerator* rand, const char * source)
- {
- entries.clear();
- globalSpecializationArgs.clear();
- entryPointSpecializationArgs.clear();
- auto lines = Split(source, '\n');
- for (auto & line : lines)
+ SlangResult parseOption(TokenReader& parser, String const& word, ShaderInputLayout::DataValBase* val)
{
- if (line.startsWith("//TEST_INPUT:"))
+ if (word == "data")
{
- auto lineContent = line.subString(13, line.getLength() - 13);
- TokenReader parser(lineContent);
- try
+ parser.Read("=");
+
+ parser.Read("[");
+ uint32_t offset = 0;
+ while (!parser.IsEnd() && !parser.LookAhead("]"))
{
- if (parser.LookAhead("entryPointSpecializationArg")
- || parser.LookAhead("type")
- || parser.LookAhead("entryPointExistentialType"))
+ bool negate = false;
+ if(parser.NextToken().Type == TokenType::OpSub)
{
parser.ReadToken();
- StringBuilder typeExp;
- while (!parser.IsEnd())
- typeExp << parser.ReadToken().Content;
- entryPointSpecializationArgs.add(typeExp);
+ negate = true;
}
- else if (parser.LookAhead("globalSpecializationArg")
- || parser.LookAhead("global_type")
- || parser.LookAhead("globalExistentialType"))
+
+ if (parser.NextToken().Type == TokenType::IntLiteral)
{
- parser.ReadToken();
- StringBuilder typeExp;
- while (!parser.IsEnd())
- typeExp << parser.ReadToken().Content;
- globalSpecializationArgs.add(typeExp);
+ uint32_t value = parser.ReadUInt();
+ if(negate) value = uint32_t(-int32_t(value));
+ val->bufferData.add(value);
}
else
{
- ShaderInputLayoutEntry entry;
+ auto floatNum = parser.ReadFloat();
+ if(negate) floatNum = -floatNum;
+ val->bufferData.add(*(unsigned int*)&floatNum);
+ }
+ offset += 4;
+ }
+ parser.Read("]");
+ }
+ else
+ {
+ return SLANG_FAIL;
+ }
+ return SLANG_OK;
+ }
- if (parser.LookAhead("array"))
- {
- entry.type = ShaderInputType::Array;
- }
- else if (parser.LookAhead("cbuffer"))
- {
- entry.type = ShaderInputType::Buffer;
- entry.bufferDesc.type = InputBufferType::ConstantBuffer;
- }
- else if (parser.LookAhead("object"))
- {
- entry.type = ShaderInputType::Object;
- }
- else if (parser.LookAhead("root_constants"))
- {
- entry.type = ShaderInputType::Buffer;
- entry.bufferDesc.type = InputBufferType::RootConstantBuffer;
- }
- else if (parser.LookAhead("Uniform"))
- {
- entry.type = ShaderInputType::Uniform;
- }
- else if (parser.LookAhead("ubuffer"))
- {
- entry.type = ShaderInputType::Buffer;
- entry.bufferDesc.type = InputBufferType::StorageBuffer;
- }
- else if (parser.LookAhead("Texture1D"))
- {
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 1;
- }
- else if (parser.LookAhead("Texture2D"))
- {
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 2;
- }
- else if (parser.LookAhead("Texture3D"))
- {
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 3;
- }
- else if (parser.LookAhead("TextureCube"))
- {
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 2;
- entry.textureDesc.isCube = true;
- }
- else if (parser.LookAhead("RWTexture1D"))
- {
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 1;
- entry.textureDesc.isRWTexture = true;
- }
- else if (parser.LookAhead("RWTexture2D"))
- {
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 2;
- entry.textureDesc.isRWTexture = true;
- }
- else if (parser.LookAhead("RWTexture3D"))
+ SlangResult parseOption(TokenReader& parser, String const& word, ShaderInputLayout::BufferVal* val)
+ {
+ if (word == "stride")
+ {
+ parser.Read("=");
+ val->bufferDesc.stride = parser.ReadInt();
+ }
+ else if (word == "random")
+ {
+ parser.Read("(");
+ // Read the type
+ String type = parser.ReadWord();
+ SlangScalarType scalarType = _getScalarType(type.getUnownedSlice());
+ if (scalarType == SLANG_SCALAR_TYPE_NONE)
+ {
+ StringBuilder scalarTypeNames;
+ for (const auto& info : g_scalarTypeInfos)
+ {
+ if (scalarTypeNames.getLength() != 0)
{
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 3;
- entry.textureDesc.isRWTexture = true;
+ scalarTypeNames << ", ";
}
- else if (parser.LookAhead("RWTextureCube"))
+ scalarTypeNames << info.name;
+ }
+
+ throw ShaderInputLayoutFormatException(StringBuilder() << "Expecting " << scalarTypeNames << " " << parser.NextToken().Position.Line);
+ }
+
+ parser.Read(",");
+ const int size = int(parser.ReadUInt());
+
+ switch (scalarType)
+ {
+ case SLANG_SCALAR_TYPE_INT32:
+ {
+ bool hasRange = false;
+
+ int32_t minValue = -0x7fffffff - 1;
+ int32_t maxValue = 0x7fffffff;
+
+ if (parser.LookAhead(","))
{
- entry.type = ShaderInputType::Texture;
- entry.textureDesc.dimension = 2;
- entry.textureDesc.isCube = true;
- entry.textureDesc.isRWTexture = true;
+ hasRange = true;
+ parser.ReadToken();
+ minValue = parser.ReadInt();
+
+ if (parser.LookAhead(","))
+ {
+ parser.ReadToken();
+ maxValue = parser.ReadInt();
+ }
}
- else if (parser.LookAhead("Sampler"))
+ SLANG_ASSERT(minValue <= maxValue);
+ maxValue = (maxValue >= minValue) ? maxValue : minValue;
+
+ // Generate the data
+ val->bufferData.setCount(size);
+
+ int32_t* dst = (int32_t*)val->bufferData.getBuffer();
+ for (int i = 0; i < size; ++i)
{
- entry.type = ShaderInputType::Sampler;
+ dst[i] = hasRange ? rand->nextInt32InRange(minValue, maxValue) : rand->nextInt32();
}
- else if (parser.LookAhead("Sampler1D"))
+ break;
+ }
+ case SLANG_SCALAR_TYPE_UINT32:
+ {
+ bool hasRange = false;
+ uint32_t minValue = 0;
+ uint32_t maxValue = 0xffffffff;
+
+ if (parser.LookAhead(","))
{
- entry.type = ShaderInputType::CombinedTextureSampler;
- entry.textureDesc.dimension = 1;
+ parser.ReadToken();
+ minValue = parser.ReadUInt();
+
+ hasRange = true;
+
+ if (parser.LookAhead(","))
+ {
+ parser.ReadToken();
+ maxValue = parser.ReadUInt();
+ }
}
- else if (parser.LookAhead("Sampler2D"))
+
+ SLANG_ASSERT(minValue <= maxValue);
+ maxValue = (maxValue >= minValue) ? maxValue : minValue;
+
+ // Generate the data
+ val->bufferData.setCount(size);
+
+ uint32_t* dst = (uint32_t*)val->bufferData.getBuffer();
+ for (int i = 0; i < size; ++i)
{
- entry.type = ShaderInputType::CombinedTextureSampler;
- entry.textureDesc.dimension = 2;
+ dst[i] = hasRange ? rand->nextUInt32InRange(minValue, maxValue) : rand->nextUInt32();
}
- else if (parser.LookAhead("Sampler3D"))
+
+ break;
+ }
+ case SLANG_SCALAR_TYPE_FLOAT32:
+ {
+ float minValue = -1.0f;
+ float maxValue = 1.0f;
+
+ if (parser.LookAhead(","))
{
- entry.type = ShaderInputType::CombinedTextureSampler;
- entry.textureDesc.dimension = 3;
+ parser.ReadToken();
+ minValue = parser.ReadFloat();
+
+ if (parser.LookAhead(","))
+ {
+ parser.ReadToken();
+ maxValue = parser.ReadFloat();
+ }
}
- else if (parser.LookAhead("SamplerCube"))
+
+ SLANG_ASSERT(minValue <= maxValue);
+ maxValue = (maxValue >= minValue) ? maxValue : minValue;
+
+ // Generate the data
+ val->bufferData.setCount(size);
+
+ float* dst = (float*)val->bufferData.getBuffer();
+ for (int i = 0; i < size; ++i)
{
- entry.type = ShaderInputType::CombinedTextureSampler;
- entry.textureDesc.dimension = 2;
- entry.textureDesc.isCube = true;
+ dst[i] = (rand->nextUnitFloat32() * (maxValue - minValue)) + minValue;
}
- else if (parser.LookAhead("render_targets"))
+ break;
+ }
+ }
+
+ // Read the range
+
+ parser.Read(")");
+ }
+ else if(word == "format")
+ {
+ val->bufferDesc.format = parseFormatOption(parser);
+ }
+ else
+ {
+ return parseOption(parser, word, static_cast<ShaderInputLayout::DataValBase*>(val));
+ }
+ return SLANG_OK;
+ }
+
+ SlangResult parseOption(TokenReader& parser, String const& word, ShaderInputLayout::ObjectVal* val)
+ {
+ if( word == "type" )
+ {
+ parser.Read("=");
+ val->typeName = parser.ReadWord();
+ }
+ else
+ {
+ return SLANG_FAIL;
+ }
+ return SLANG_OK;
+ }
+
+ Format parseFormatOption(TokenReader& parser)
+ {
+ Format format = Format::Unknown;
+
+ parser.Read("=");
+ auto formatWord = parser.ReadWord();
+ if(formatWord == "R_UInt32")
+ {
+ format = Format::R_UInt32;
+ }
+ else if (formatWord == "R_Float32")
+ {
+ format = Format::R_Float32;
+ }
+ else if (formatWord == "RGBA_Unorm_UInt8")
+ {
+ format = Format::RGBA_Unorm_UInt8;
+ }
+ else
+ {
+ // TODO: an error message here
+ }
+ return format;
+ }
+
+ template<typename T>
+ void maybeParseOptions(TokenReader& parser, T* val)
+ {
+ // parse options
+ if (parser.LookAhead("("))
+ {
+ parser.Read("(");
+ while (!parser.IsEnd() && !parser.LookAhead(")"))
+ {
+ auto word = parser.ReadWord();
+ if( SLANG_FAILED(parseOption(parser, word, val)) )
+ {
+ throw ShaderInputLayoutFormatException(String("Unsupported option '") + word + String("' at line ") + String(parser.NextToken().Position.Line));
+ }
+
+ if (parser.LookAhead(","))
+ parser.Read(",");
+ else
+ break;
+ }
+ parser.Read(")");
+ }
+ }
+
+ RefPtr<ShaderInputLayout::Val> parseVal(TokenReader& parser)
+ {
+ auto word = parser.NextToken().Content;
+ if (parser.AdvanceIf("begin_array"))
+ {
+ RefPtr<ShaderInputLayout::ArrayVal> val = new ShaderInputLayout::ArrayVal;
+ pushParentVal(val);
+ return val;
+ }
+ else if (parser.AdvanceIf("begin_object"))
+ {
+ RefPtr<ShaderInputLayout::ObjectVal> val = new ShaderInputLayout::ObjectVal;
+ maybeParseOptions(parser, val.Ptr());
+
+ RefPtr<ShaderInputLayout::AggVal> contentVal = new ShaderInputLayout::AggVal;
+ val->contentVal = contentVal;
+ pushParentVal(contentVal);
+
+ return val;
+ }
+ else if (parser.AdvanceIf("uniform"))
+ {
+ RefPtr<ShaderInputLayout::DataVal> val = new ShaderInputLayout::DataVal;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("cbuffer"))
+ {
+ // A `cbuffer` is basically just an object where the content of
+ // the object is being provided by `uniform` data instead.
+
+ RefPtr<ShaderInputLayout::ObjectVal> objVal = new ShaderInputLayout::ObjectVal;
+
+ RefPtr<ShaderInputLayout::DataVal> dataVal = new ShaderInputLayout::DataVal;
+ maybeParseOptions(parser, dataVal.Ptr());
+
+ objVal->contentVal = dataVal;
+
+ return objVal;
+ }
+ else if (parser.AdvanceIf("ubuffer"))
+ {
+ RefPtr<ShaderInputLayout::BufferVal> val = new ShaderInputLayout::BufferVal;
+ val->bufferDesc.type = InputBufferType::StorageBuffer;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("Texture1D"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 1;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("Texture2D"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 2;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("Texture3D"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 3;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("TextureCube"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 2;
+ val->textureDesc.isCube = true;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("RWTexture1D"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 1;
+ val->textureDesc.isRWTexture = true;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("RWTexture2D"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 2;
+ val->textureDesc.isRWTexture = true;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("RWTexture3D"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 3;
+ val->textureDesc.isRWTexture = true;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("RWTextureCube"))
+ {
+ RefPtr<ShaderInputLayout::TextureVal> val = new ShaderInputLayout::TextureVal;
+ val->textureDesc.dimension = 2;
+ val->textureDesc.isCube = true;
+ val->textureDesc.isRWTexture = true;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ else if (parser.AdvanceIf("Sampler"))
+ {
+ RefPtr<ShaderInputLayout::SamplerVal> val = new ShaderInputLayout::SamplerVal;
+ maybeParseOptions(parser, val.Ptr());
+ return val;
+ }
+ // TODO: We can include combined texture/sampler cases
+ // here, but we don't really have tests for them and
+ // it might be better to save it for a point where
+ // we support hierarchical binding values more directly.
+ else
+ {
+ throw ShaderInputLayoutFormatException(String("Unknown shader input type '") + word + String("' at line") + String(parser.NextToken().Position.Line));
+ }
+ parser.ReadToken();
+ }
+
+ void parseFieldBindings(TokenReader& parser, ShaderInputLayout::Field& ioField)
+ {
+ // parse bindings
+ if (parser.LookAhead(":"))
+ {
+ parser.Read(":");
+ while (!parser.IsEnd())
+ {
+ if (parser.AdvanceIf("out"))
+ {
+ ioField.val->isOutput = true;
+ }
+ else if (parser.AdvanceIf("name"))
+ {
+ // Optionally consume '='
+ if (parser.NextToken().Type == TokenType::OpAssign)
{
- numRenderTargets = parser.ReadInt();
- continue;
+ parser.ReadToken();
}
- else
+
+ StringBuilder builder;
+
+ Token nameToken = parser.ReadToken();
+ if (nameToken.Type != TokenType::Identifier)
{
- throw TextFormatException(String("Invalid input syntax at line ") + String(parser.NextToken().Position.Line));
+ throw ShaderInputLayoutFormatException(StringBuilder() << "Invalid input syntax at line " << parser.NextToken().Position.Line);
}
- parser.ReadToken();
- // parse options
- if (parser.LookAhead("("))
+ builder << nameToken.Content;
+
+ while (!parser.IsEnd())
{
- parser.Read("(");
- while (!parser.IsEnd() && !parser.LookAhead(")"))
+ Token token = parser.NextToken(0);
+
+ if (token.Type == TokenType::LBracket)
{
- auto word = parser.ReadWord();
- if (word == "depth")
- {
- entry.textureDesc.isDepthTexture = true;
- }
- else if (word == "depthCompare")
- {
- entry.samplerDesc.isCompareSampler = true;
- }
- else if (word == "arrayLength")
- {
- parser.Read("=");
- entry.textureDesc.arrayLength = parser.ReadInt();
- }
- else if (word == "stride")
- {
- parser.Read("=");
- entry.bufferDesc.stride = parser.ReadInt();
- }
- else if (word == "size")
- {
- parser.Read("=");
- auto size = parser.ReadInt();
- if (entry.type == ShaderInputType::Array)
- {
- entry.arrayDesc.size = size;
- }
- else
- {
- entry.textureDesc.size = size;
- }
- }
- else if (word == "random")
- {
- parser.Read("(");
- // Read the type
- String type = parser.ReadWord();
- SlangScalarType scalarType = _getScalarType(type.getUnownedSlice());
- if (scalarType == SLANG_SCALAR_TYPE_NONE)
- {
- StringBuilder scalarTypeNames;
- for (const auto& info : g_scalarTypeInfos)
- {
- if (scalarTypeNames.getLength() != 0)
- {
- scalarTypeNames << ", ";
- }
- scalarTypeNames << info.name;
- }
-
- throw TextFormatException(StringBuilder() << "Expecting " << scalarTypeNames << " " << parser.NextToken().Position.Line);
- }
-
- parser.Read(",");
- const int size = int(parser.ReadUInt());
-
- switch (scalarType)
- {
- case SLANG_SCALAR_TYPE_INT32:
- {
- bool hasRange = false;
-
- int32_t minValue = -0x7fffffff - 1;
- int32_t maxValue = 0x7fffffff;
-
- if (parser.LookAhead(","))
- {
- hasRange = true;
- parser.ReadToken();
- minValue = parser.ReadInt();
-
- if (parser.LookAhead(","))
- {
- parser.ReadToken();
- maxValue = parser.ReadInt();
- }
- }
- SLANG_ASSERT(minValue <= maxValue);
- maxValue = (maxValue >= minValue) ? maxValue : minValue;
-
- // Generate the data
- entry.bufferData.setCount(size);
-
- int32_t* dst = (int32_t*)entry.bufferData.getBuffer();
- for (int i = 0; i < size; ++i)
- {
- dst[i] = hasRange ? rand->nextInt32InRange(minValue, maxValue) : rand->nextInt32();
- }
- break;
- }
- case SLANG_SCALAR_TYPE_UINT32:
- {
- bool hasRange = false;
- uint32_t minValue = 0;
- uint32_t maxValue = 0xffffffff;
-
- if (parser.LookAhead(","))
- {
- parser.ReadToken();
- minValue = parser.ReadUInt();
-
- hasRange = true;
-
- if (parser.LookAhead(","))
- {
- parser.ReadToken();
- maxValue = parser.ReadUInt();
- }
- }
-
- SLANG_ASSERT(minValue <= maxValue);
- maxValue = (maxValue >= minValue) ? maxValue : minValue;
-
- // Generate the data
- entry.bufferData.setCount(size);
-
- uint32_t* dst = (uint32_t*)entry.bufferData.getBuffer();
- for (int i = 0; i < size; ++i)
- {
- dst[i] = hasRange ? rand->nextUInt32InRange(minValue, maxValue) : rand->nextUInt32();
- }
-
- break;
- }
- case SLANG_SCALAR_TYPE_FLOAT32:
- {
- float minValue = -1.0f;
- float maxValue = 1.0f;
-
- if (parser.LookAhead(","))
- {
- parser.ReadToken();
- minValue = parser.ReadFloat();
-
- if (parser.LookAhead(","))
- {
- parser.ReadToken();
- maxValue = parser.ReadFloat();
- }
- }
-
- SLANG_ASSERT(minValue <= maxValue);
- maxValue = (maxValue >= minValue) ? maxValue : minValue;
-
- // Generate the data
- entry.bufferData.setCount(size);
-
- float* dst = (float*)entry.bufferData.getBuffer();
- for (int i = 0; i < size; ++i)
- {
- dst[i] = (rand->nextUnitFloat32() * (maxValue - minValue)) + minValue;
- }
- break;
- }
- }
-
- // Read the range
-
- parser.Read(")");
- }
- else if (word == "data")
- {
- parser.Read("=");
-
- parser.Read("[");
- uint32_t offset = 0;
- while (!parser.IsEnd() && !parser.LookAhead("]"))
- {
- RTTIDataEntry rttiEntry;
- if (parser.LookAhead("rtti"))
- {
- parser.ReadToken();
- parser.Read("(");
- rttiEntry.type = RTTIDataEntryType::RTTIObject;
- rttiEntry.typeName = parser.ReadWord();
- rttiEntry.offset = offset;
- parser.Read(")");
- offset += 8;
- entry.rttiEntries.add(rttiEntry);
- entry.bufferData.add(0);
- entry.bufferData.add(0);
- continue;
- }
- else if (parser.LookAhead("witness"))
- {
- parser.ReadToken();
- parser.Read("(");
- rttiEntry.type = RTTIDataEntryType::WitnessTable;
- rttiEntry.typeName = parser.ReadWord();
- parser.Read(",");
- rttiEntry.interfaceName = parser.ReadWord();
- rttiEntry.offset = offset;
- parser.Read(")");
- offset += 8;
- entry.rttiEntries.add(rttiEntry);
- entry.bufferData.add(0);
- entry.bufferData.add(0);
- continue;
- }
- else if (parser.LookAhead("handle"))
- {
- BindlessHandleDataEntry handleEntry;
- parser.ReadToken();
- parser.Read("(");
- handleEntry.name = parser.ReadWord();
- handleEntry.offset = offset;
- parser.Read(")");
- offset += 8;
- entry.bindlessHandleEntry.add(handleEntry);
- entry.bufferData.add(0);
- entry.bufferData.add(0);
- continue;
- }
-
- bool negate = false;
- if(parser.NextToken().Type == TokenType::OpSub)
- {
- parser.ReadToken();
- negate = true;
- }
-
- if (parser.NextToken().Type == TokenType::IntLiteral)
- {
- uint32_t val = parser.ReadUInt();
- if(negate) val = uint32_t(-int32_t(val));
- entry.bufferData.add(val);
- }
- else
- {
- auto floatNum = parser.ReadFloat();
- if(negate) floatNum = -floatNum;
- entry.bufferData.add(*(unsigned int*)&floatNum);
- }
- offset += 4;
- }
- parser.Read("]");
- }
- else if (word == "content")
- {
- parser.Read("=");
- auto contentWord = parser.ReadWord();
- if (contentWord == "zero")
- entry.textureDesc.content = InputTextureContent::Zero;
- else if (contentWord == "one")
- entry.textureDesc.content = InputTextureContent::One;
- else if (contentWord == "chessboard")
- entry.textureDesc.content = InputTextureContent::ChessBoard;
- else
- entry.textureDesc.content = InputTextureContent::Gradient;
- }
- else if(word == "format")
- {
- Format format = Format::Unknown;
-
- parser.Read("=");
- auto formatWord = parser.ReadWord();
- if(formatWord == "R_UInt32")
- {
- format = Format::R_UInt32;
- }
- else if (formatWord == "R_Float32")
- {
- format = Format::R_Float32;
- }
- else if (formatWord == "RGBA_Unorm_UInt8")
- {
- format = Format::RGBA_Unorm_UInt8;
- }
-
- entry.textureDesc.format = format;
- entry.bufferDesc.format = format;
- }
- else if(word == "mipMaps")
- {
- parser.Read("=");
- entry.textureDesc.mipMapCount = int(parser.ReadInt());
- }
- else if( word == "type" )
- {
- parser.Read("=");
- entry.objectDesc.typeName = parser.ReadWord();
- }
-
- if (parser.LookAhead(","))
- parser.Read(",");
- else
- break;
+ parser.ReadToken();
+ int index = parser.ReadInt();
+ SLANG_ASSERT(index >= 0);
+ parser.ReadMatchingToken(TokenType::RBracket);
+
+ builder << "[" << index << "]";
}
- parser.Read(")");
- }
- // parse bindings
- if (parser.LookAhead(":"))
- {
- parser.Read(":");
- while (!parser.IsEnd())
+ else if (token.Type == TokenType::Dot)
+ {
+ parser.ReadToken();
+ Token identifierToken = parser.ReadMatchingToken(TokenType::Identifier);
+
+ builder << "." << identifierToken.Content;
+ }
+ else if (token.Type == TokenType::Comma)
+ {
+ // Break out
+ break;
+ }
+ else
{
- if (parser.LookAhead("onlyCPULikeBinding"))
- {
- entry.onlyCPULikeBinding = true;
- parser.ReadToken();
- }
- else if (parser.LookAhead("out"))
- {
- parser.ReadToken();
- entry.isOutput = true;
- }
- else if (parser.LookAhead("name"))
- {
- parser.ReadToken();
-
- // Optionally consume '='
- if (parser.NextToken().Type == TokenType::OpAssign)
- {
- parser.ReadToken();
- }
-
- StringBuilder builder;
-
- Token nameToken = parser.ReadToken();
- if (nameToken.Type != TokenType::Identifier)
- {
- throw TextFormatException(StringBuilder() << "Invalid input syntax at line " << parser.NextToken().Position.Line);
- }
- builder << nameToken.Content;
-
- while (!parser.IsEnd())
- {
- Token token = parser.NextToken(0);
-
- if (token.Type == TokenType::LBracket)
- {
- parser.ReadToken();
- int index = parser.ReadInt();
- SLANG_ASSERT(index >= 0);
- parser.ReadMatchingToken(TokenType::RBracket);
-
- builder << "[" << index << "]";
- }
- else if (token.Type == TokenType::Dot)
- {
- parser.ReadToken();
- Token identifierToken = parser.ReadMatchingToken(TokenType::Identifier);
-
- builder << "." << identifierToken.Content;
- }
- else if (token.Type == TokenType::Comma)
- {
- // Break out
- break;
- }
- else
- {
- throw TextFormatException(StringBuilder() << "Invalid input syntax at line " << parser.NextToken().Position.Line);
- }
- }
-
- entry.name = builder;
- }
- else if (parser.LookAhead("bindless"))
- {
- parser.ReadToken();
- entry.isBindlessObject = true;
- }
- else
- {
- fprintf(stderr, "Invalid TEST_INPUT syntax '%s'\n", parser.NextToken().Content.getBuffer());
- break;
- }
-
- if (parser.LookAhead(","))
- parser.Read(",");
+ throw ShaderInputLayoutFormatException(StringBuilder() << "Invalid input syntax at line " << parser.NextToken().Position.Line);
}
}
- entries.add(entry);
+
+ ioField.name = builder;
}
+ else
+ {
+ fprintf(stderr, "Invalid TEST_INPUT syntax '%s'\n", parser.NextToken().Content.getBuffer());
+ break;
+ }
+
+ if (parser.LookAhead(","))
+ parser.Read(",");
}
- catch (const TextFormatException&)
+ }
+ }
+
+ void pushParentVal(ShaderInputLayout::ParentVal* val)
+ {
+ parentValStack.add(parentVal);
+ parentVal = val;
+ }
+
+ void parseValEntry(TokenReader& parser)
+ {
+ auto parentForNewVal = parentVal;
+
+ ShaderInputLayout::Field field;
+ field.val = parseVal(parser);
+ parseFieldBindings(parser, field);
+
+ parentForNewVal->addField(field);
+ }
+
+ void parseLine(TokenReader& parser)
+ {
+ if (parser.LookAhead("entryPointSpecializationArg")
+ || parser.LookAhead("type")
+ || parser.LookAhead("entryPointExistentialType"))
+ {
+ parser.ReadToken();
+ StringBuilder typeExp;
+ while (!parser.IsEnd())
+ typeExp << parser.ReadToken().Content;
+ layout->entryPointSpecializationArgs.add(typeExp);
+ }
+ else if (parser.LookAhead("globalSpecializationArg")
+ || parser.LookAhead("global_type")
+ || parser.LookAhead("globalExistentialType"))
+ {
+ parser.ReadToken();
+ StringBuilder typeExp;
+ while (!parser.IsEnd())
+ typeExp << parser.ReadToken().Content;
+ layout->globalSpecializationArgs.add(typeExp);
+ }
+ else if (parser.AdvanceIf("render_targets"))
+ {
+ layout->numRenderTargets = parser.ReadInt();
+ }
+ else if( parser.AdvanceIf("end") )
+ {
+ parentVal = parentValStack.getLast();
+ parentValStack.removeLast();
+ }
+ else
+ {
+ parseValEntry(parser);
+ }
+ }
+
+ RefPtr<ShaderInputLayout::AggVal> parse(const char * source)
+ {
+ RefPtr<ShaderInputLayout::AggVal> rootVal = new ShaderInputLayout::AggVal;
+ parentVal = rootVal;
+
+ auto lines = Split(source, '\n');
+ for (auto & line : lines)
+ {
+ if (line.startsWith("//TEST_INPUT:"))
{
- StringBuilder msg;
- msg << "Invalid input syntax at line " << parser.NextToken().Position.Line;
- throw TextFormatException(msg);
+ auto lineContent = line.subString(13, line.getLength() - 13);
+ TokenReader parser(lineContent);
+ try
+ {
+ parseLine(parser);
+ }
+ catch (const TextFormatException&)
+ {
+ StringBuilder msg;
+ msg << "Invalid input syntax at line " << parser.NextToken().Position.Line;
+ throw ShaderInputLayoutFormatException(msg);
+ }
}
}
+
+ // TODO: check that stack has been maintained correctly...
+
+ return rootVal;
}
+ };
+
+ void ShaderInputLayout::parse(RandomGenerator* rand, const char * source)
+ {
+ rootVal = nullptr;
+ globalSpecializationArgs.clear();
+ entryPointSpecializationArgs.clear();
+
+ ShaderInputLayoutParser parser(this, rand);
+ rootVal = parser.parse(source);
}
- /* static */SlangResult ShaderInputLayout::writeBinding(const ShaderInputLayoutEntry& entry, slang::TypeLayoutReflection* typeLayout, const void* data, size_t sizeInBytes, WriterHelper writer)
+ /* static */SlangResult ShaderInputLayout::writeBinding(slang::TypeLayoutReflection* typeLayout, const void* data, size_t sizeInBytes, WriterHelper writer)
{
typedef slang::TypeReflection::ScalarType ScalarType;
diff --git a/tools/render-test/shader-input-layout.h b/tools/render-test/shader-input-layout.h
index 01ef5c443..60582aed8 100644
--- a/tools/render-test/shader-input-layout.h
+++ b/tools/render-test/shader-input-layout.h
@@ -14,8 +14,14 @@ using namespace gfx;
enum class ShaderInputType
{
- Buffer, Texture, Sampler, CombinedTextureSampler, Array, Uniform,
+ Buffer,
+ Texture,
+ Sampler,
+ CombinedTextureSampler,
+ Array,
+ UniformData,
Object,
+ Aggregate,
};
enum class InputTextureContent
@@ -40,13 +46,14 @@ struct InputTextureDesc
enum class InputBufferType
{
- ConstantBuffer, StorageBuffer,
- RootConstantBuffer,
+// ConstantBuffer,
+ StorageBuffer,
+// RootConstantBuffer,
};
struct InputBufferDesc
{
- InputBufferType type = InputBufferType::ConstantBuffer;
+ InputBufferType type = InputBufferType::StorageBuffer;
int stride = 0; // stride == 0 indicates an unstructured buffer.
Format format = Format::Unknown;
};
@@ -56,52 +63,6 @@ struct InputSamplerDesc
bool isCompareSampler = false;
};
-struct ArrayDesc
-{
- int size = 0;
-};
-
-enum class RTTIDataEntryType
-{
- RTTIObject, WitnessTable
-};
-struct RTTIDataEntry
-{
- RTTIDataEntryType type;
- Slang::String typeName;
- Slang::String interfaceName;
- unsigned int offset;
-};
-
-struct BindlessHandleDataEntry
-{
- unsigned int offset;
- Slang::String name;
-};
-
-struct InputObjectDesc
-{
- Slang::String typeName;
-};
-
-class ShaderInputLayoutEntry
-{
-public:
- ShaderInputType type;
- Slang::List<unsigned int> bufferData;
- Slang::List<RTTIDataEntry> rttiEntries;
- Slang::List<BindlessHandleDataEntry> bindlessHandleEntry;
- InputTextureDesc textureDesc;
- InputBufferDesc bufferDesc;
- InputSamplerDesc samplerDesc;
- ArrayDesc arrayDesc;
- InputObjectDesc objectDesc;
- bool isOutput = false;
- bool onlyCPULikeBinding = false; ///< If true, only use on targets that have 'uniform' or 'CPU like' binding, like CPU and CUDA
- bool isBindlessObject = false; ///< If true, this is a bindless object with no associated binding point in the shader.
- Slang::String name; ///< Optional name. Useful for binding through reflection.
-};
-
struct TextureData
{
Slang::List<Slang::List<unsigned int>> dataBuffer;
@@ -113,19 +74,140 @@ struct TextureData
class ShaderInputLayout
{
public:
- Slang::List<ShaderInputLayoutEntry> entries;
+ class Val : public Slang::RefObject
+ {
+ public:
+ Val(ShaderInputType kind)
+ : kind(kind)
+ {}
+
+ ShaderInputType kind;
+ bool isOutput = false;
+ };
+ typedef Slang::RefPtr<Val> ValPtr;
+
+ class TextureVal : public Val
+ {
+ public:
+ TextureVal()
+ : Val(ShaderInputType::Texture)
+ {}
+
+ InputTextureDesc textureDesc;
+ };
+
+ class DataValBase : public Val
+ {
+ public:
+ DataValBase(ShaderInputType kind)
+ : Val(kind)
+ {}
+
+ Slang::List<unsigned int> bufferData;
+ };
+
+ class BufferVal : public DataValBase
+ {
+ public:
+ BufferVal()
+ : DataValBase(ShaderInputType::Buffer)
+ {}
+
+ InputBufferDesc bufferDesc;
+ };
+
+ class DataVal : public DataValBase
+ {
+ public:
+ DataVal()
+ : DataValBase(ShaderInputType::UniformData)
+ {}
+ };
+
+ class SamplerVal : public Val
+ {
+ public:
+ SamplerVal()
+ : Val(ShaderInputType::Sampler)
+ {}
+
+ InputSamplerDesc samplerDesc;
+ };
+
+ class CombinedTextureSamplerVal : public Val
+ {
+ public:
+ CombinedTextureSamplerVal()
+ : Val(ShaderInputType::CombinedTextureSampler)
+ {}
+
+ Slang::RefPtr<TextureVal> textureVal;
+ Slang::RefPtr<SamplerVal> samplerVal;
+ };
+
+ struct Field
+ {
+ Slang::String name;
+ ValPtr val;
+ };
+ typedef Field Entry;
+
+ class ParentVal : public Val
+ {
+ public:
+ ParentVal(ShaderInputType kind)
+ : Val(kind)
+ {}
+
+ virtual void addField(Field const& field) = 0;
+ };
+
+ class AggVal : public ParentVal
+ {
+ public:
+ AggVal(ShaderInputType kind = ShaderInputType::Aggregate)
+ : ParentVal(kind)
+ {}
+
+ Slang::List<Field> fields;
+
+ virtual void addField(Field const& field) override;
+ };
+
+ class ObjectVal : public Val
+ {
+ public:
+ ObjectVal()
+ : Val(ShaderInputType::Object)
+ {}
+
+ Slang::String typeName;
+ ValPtr contentVal;
+ };
+
+ class ArrayVal : public ParentVal
+ {
+ public:
+ ArrayVal()
+ : ParentVal(ShaderInputType::Array)
+ {}
+
+ Slang::List<ValPtr> vals;
+
+ virtual void addField(Field const& field) override;
+ };
+
+ Slang::RefPtr<AggVal> rootVal;
Slang::List<Slang::String> globalSpecializationArgs;
Slang::List<Slang::String> entryPointSpecializationArgs;
int numRenderTargets = 1;
Slang::Index findEntryIndexByName(const Slang::String& name) const;
- void updateForTarget(SlangCompileTarget target);
-
void parse(Slang::RandomGenerator* rand, const char* source);
/// Writes a binding, if bindRoot is set, will try to honor the underlying type when outputting. If not will dump as uint32_t hex.
- static SlangResult writeBinding(const ShaderInputLayoutEntry& entry, slang::TypeLayoutReflection* typeLayout, const void* data, size_t sizeInBytes, Slang::WriterHelper writer);
+ static SlangResult writeBinding(slang::TypeLayoutReflection* typeLayout, const void* data, size_t sizeInBytes, Slang::WriterHelper writer);
};
void generateTextureDataRGB8(TextureData& output, const InputTextureDesc& desc);
diff --git a/tools/render-test/shader-renderer-util.cpp b/tools/render-test/shader-renderer-util.cpp
index ede744445..d6441d3ac 100644
--- a/tools/render-test/shader-renderer-util.cpp
+++ b/tools/render-test/shader-renderer-util.cpp
@@ -93,7 +93,6 @@ using Slang::Result;
/* static */ Result ShaderRendererUtil::createBufferResource(
const InputBufferDesc& inputDesc,
- bool isOutput,
size_t bufferSize,
const void* initData,
IDevice* device,
@@ -106,24 +105,12 @@ using Slang::Result;
srcDesc.format = inputDesc.format;
int bindFlags = 0;
- if (inputDesc.type == InputBufferType::ConstantBuffer)
- {
- bindFlags |= IResource::BindFlag::ConstantBuffer;
- srcDesc.cpuAccessFlags |= IResource::AccessFlag::Write;
- initialUsage = IResource::Usage::ConstantBuffer;
- }
- else
{
bindFlags |= IResource::BindFlag::UnorderedAccess | IResource::BindFlag::PixelShaderResource | IResource::BindFlag::NonPixelShaderResource;
srcDesc.elementSize = inputDesc.stride;
initialUsage = IResource::Usage::UnorderedAccess;
}
- if (isOutput)
- {
- srcDesc.cpuAccessFlags |= IResource::AccessFlag::Read;
- }
-
srcDesc.bindFlags = bindFlags;
ComPtr<IBufferResource> bufferResource =
diff --git a/tools/render-test/shader-renderer-util.h b/tools/render-test/shader-renderer-util.h
index 8771d21f6..b4028fd06 100644
--- a/tools/render-test/shader-renderer-util.h
+++ b/tools/render-test/shader-renderer-util.h
@@ -31,7 +31,6 @@ struct ShaderRendererUtil
/// Create the BufferResource using the renderer from the contents of inputDesc
static Slang::Result createBufferResource(
const InputBufferDesc& inputDesc,
- bool isOutput,
size_t bufferSize,
const void* initData,
IDevice* device,
diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp
index 72732363e..aca354763 100644
--- a/tools/render-test/slang-support.cpp
+++ b/tools/render-test/slang-support.cpp
@@ -363,7 +363,6 @@ void ShaderCompilerUtil::Output::reset()
// Parse the layout
layout.parse(rand, sourceText.getBuffer());
- layout.updateForTarget(input.target);
// Setup SourceInfo
ShaderCompileRequest::SourceInfo sourceInfo;