summaryrefslogtreecommitdiffstats
path: root/tools/render-test/render-test-main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/render-test/render-test-main.cpp')
-rw-r--r--tools/render-test/render-test-main.cpp488
1 files changed, 249 insertions, 239 deletions
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;
}
}