summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorEllie Hermaszewska <ellieh@nvidia.com>2024-10-29 14:49:26 +0800
committerGitHub <noreply@github.com>2024-10-29 14:49:26 +0800
commitf65d756bff8d4c5cbc15bd0322a2ae8e6b896a21 (patch)
treeea1d61342cd29368e19135000ec2948813096205 /examples
parenta729c15e9dce9f5116a38afc66329ab2ca4cea54 (diff)
format
* format * Minor test fixes * enable checking cpp format in ci
Diffstat (limited to 'examples')
-rw-r--r--examples/autodiff-texture/main.cpp272
-rw-r--r--examples/cpu-com-example/main.cpp54
-rw-r--r--examples/cpu-hello-world/main.cpp66
-rw-r--r--examples/example-base/example-base.cpp87
-rw-r--r--examples/example-base/example-base.h42
-rw-r--r--examples/example-base/test-base.cpp15
-rw-r--r--examples/example-base/test-base.h14
-rw-r--r--examples/gpu-printing/gpu-printing.cpp159
-rw-r--r--examples/gpu-printing/gpu-printing.h50
-rw-r--r--examples/gpu-printing/main.cpp209
-rw-r--r--examples/hello-world/main.cpp46
-rw-r--r--examples/hello-world/vulkan-api.cpp30
-rw-r--r--examples/hello-world/vulkan-api.h12
-rw-r--r--examples/model-viewer/main.cpp605
-rw-r--r--examples/nv-aftermath-example/main.cpp264
-rw-r--r--examples/platform-test/main.cpp188
-rw-r--r--examples/ray-tracing-pipeline/main.cpp1076
-rw-r--r--examples/ray-tracing/main.cpp1006
-rw-r--r--examples/shader-object/main.cpp31
-rw-r--r--examples/shader-toy/main.cpp635
-rw-r--r--examples/triangle/main.cpp629
21 files changed, 2911 insertions, 2579 deletions
diff --git a/examples/autodiff-texture/main.cpp b/examples/autodiff-texture/main.cpp
index 8bffadd84..d09b7dbac 100644
--- a/examples/autodiff-texture/main.cpp
+++ b/examples/autodiff-texture/main.cpp
@@ -2,10 +2,10 @@
#include "gfx-util/shader-cursor.h"
#include "slang-com-ptr.h"
#include "slang-gfx.h"
+#include "slang.h"
#include "source/core/slang-basic.h"
#include "tools/platform/vector-math.h"
#include "tools/platform/window.h"
-#include "slang.h"
using namespace gfx;
using namespace Slang;
@@ -41,14 +41,18 @@ struct AutoDiffTexture : public WindowedAppBase
}
gfx::Result loadRenderProgram(
- gfx::IDevice* device, const char* fileName, const char* fragmentShader, gfx::IShaderProgram** outProgram)
+ gfx::IDevice* device,
+ const char* fileName,
+ const char* fragmentShader,
+ gfx::IShaderProgram** outProgram)
{
ComPtr<slang::ISession> slangSession;
slangSession = device->getSlangSession();
ComPtr<slang::IBlob> diagnosticsBlob;
Slang::String path = resourceBase.resolveResource(fileName);
- slang::IModule* module = slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef());
+ slang::IModule* module =
+ slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef());
diagnoseIfNeeded(diagnosticsBlob);
if (!module)
return SLANG_FAIL;
@@ -91,14 +95,17 @@ struct AutoDiffTexture : public WindowedAppBase
}
gfx::Result loadComputeProgram(
- gfx::IDevice* device, const char* fileName, gfx::IShaderProgram** outProgram)
+ gfx::IDevice* device,
+ const char* fileName,
+ gfx::IShaderProgram** outProgram)
{
ComPtr<slang::ISession> slangSession;
slangSession = device->getSlangSession();
ComPtr<slang::IBlob> diagnosticsBlob;
Slang::String path = resourceBase.resolveResource(fileName);
- slang::IModule* module = slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef());
+ slang::IModule* module =
+ slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef());
diagnoseIfNeeded(diagnosticsBlob);
if (!module)
return SLANG_FAIL;
@@ -174,7 +181,11 @@ struct AutoDiffTexture : public WindowedAppBase
ClearValue kClearValue;
bool resetLearntTexture = false;
- ComPtr<gfx::ITextureResource> createRenderTargetTexture(gfx::Format format, int w, int h, int levels)
+ ComPtr<gfx::ITextureResource> createRenderTargetTexture(
+ gfx::Format format,
+ int w,
+ int h,
+ int levels)
{
gfx::ITextureResource::Desc textureDesc = {};
textureDesc.allowedStates.add(ResourceState::ShaderResource);
@@ -239,7 +250,8 @@ struct AutoDiffTexture : public WindowedAppBase
return gDevice->createTextureView(tex, rtvDesc);
}
ComPtr<gfx::IPipelineState> createRenderPipelineState(
- IInputLayout* inputLayout, IShaderProgram* program)
+ IInputLayout* inputLayout,
+ IShaderProgram* program)
{
GraphicsPipelineStateDesc desc;
desc.inputLayout = inputLayout;
@@ -269,7 +281,7 @@ struct AutoDiffTexture : public WindowedAppBase
desc.subresourceRange.layerCount = 1;
desc.subresourceRange.mipLevel = level;
desc.subresourceRange.baseArrayLayer = 0;
- return gDevice->createTextureView(texture,desc);
+ return gDevice->createTextureView(texture, desc);
}
Slang::Result initialize()
{
@@ -320,20 +332,29 @@ struct AutoDiffTexture : public WindowedAppBase
{
ComPtr<IShaderProgram> shaderProgram;
- SLANG_RETURN_ON_FAIL(
- loadRenderProgram(gDevice, "train.slang", "fragmentMain", shaderProgram.writeRef()));
+ SLANG_RETURN_ON_FAIL(loadRenderProgram(
+ gDevice,
+ "train.slang",
+ "fragmentMain",
+ shaderProgram.writeRef()));
gRefPipelineState = createRenderPipelineState(inputLayout, shaderProgram);
}
{
ComPtr<IShaderProgram> shaderProgram;
- SLANG_RETURN_ON_FAIL(
- loadRenderProgram(gDevice, "train.slang", "diffFragmentMain", shaderProgram.writeRef()));
+ SLANG_RETURN_ON_FAIL(loadRenderProgram(
+ gDevice,
+ "train.slang",
+ "diffFragmentMain",
+ shaderProgram.writeRef()));
gIterPipelineState = createRenderPipelineState(inputLayout, shaderProgram);
}
{
ComPtr<IShaderProgram> shaderProgram;
- SLANG_RETURN_ON_FAIL(
- loadRenderProgram(gDevice, "draw-quad.slang", "fragmentMain", shaderProgram.writeRef()));
+ SLANG_RETURN_ON_FAIL(loadRenderProgram(
+ gDevice,
+ "draw-quad.slang",
+ "fragmentMain",
+ shaderProgram.writeRef()));
gDrawQuadPipelineState = createRenderPipelineState(inputLayout, shaderProgram);
}
{
@@ -344,17 +365,20 @@ struct AutoDiffTexture : public WindowedAppBase
}
{
ComPtr<IShaderProgram> shaderProgram;
- SLANG_RETURN_ON_FAIL(loadComputeProgram(gDevice, "convert.slang", shaderProgram.writeRef()));
+ SLANG_RETURN_ON_FAIL(
+ loadComputeProgram(gDevice, "convert.slang", shaderProgram.writeRef()));
gConvertPipelineState = createComputePipelineState(shaderProgram);
}
{
ComPtr<IShaderProgram> shaderProgram;
- SLANG_RETURN_ON_FAIL(loadComputeProgram(gDevice, "buildmip.slang", shaderProgram.writeRef()));
+ SLANG_RETURN_ON_FAIL(
+ loadComputeProgram(gDevice, "buildmip.slang", shaderProgram.writeRef()));
gBuildMipPipelineState = createComputePipelineState(shaderProgram);
}
{
ComPtr<IShaderProgram> shaderProgram;
- SLANG_RETURN_ON_FAIL(loadComputeProgram(gDevice, "learnmip.slang", shaderProgram.writeRef()));
+ SLANG_RETURN_ON_FAIL(
+ loadComputeProgram(gDevice, "learnmip.slang", shaderProgram.writeRef()));
gLearnMipPipelineState = createComputePipelineState(shaderProgram);
}
@@ -394,7 +418,7 @@ struct AutoDiffTexture : public WindowedAppBase
gDiffTextureUAVs.add(createUAV(gDiffTexture, i));
gfx::ISamplerState::Desc samplerDesc = {};
- //samplerDesc.maxLOD = 0.0f;
+ // samplerDesc.maxLOD = 0.0f;
gSampler = gDevice->createSamplerState(samplerDesc);
gDepthTexture = createDepthTexture();
@@ -404,7 +428,8 @@ struct AutoDiffTexture : public WindowedAppBase
gRefImageRTV = createRTV(gRefImage, Format::R8G8B8A8_UNORM);
gRefImageSRV = createSRV(gRefImage);
- gIterImage = createRenderTargetTexture(Format::R8G8B8A8_UNORM, windowWidth, windowHeight, 1);
+ gIterImage =
+ createRenderTargetTexture(Format::R8G8B8A8_UNORM, windowWidth, windowHeight, 1);
gIterImageRTV = createRTV(gIterImage, Format::R8G8B8A8_UNORM);
gIterImageSRV = createSRV(gIterImage);
@@ -414,17 +439,38 @@ struct AutoDiffTexture : public WindowedAppBase
{
ComPtr<ICommandBuffer> commandBuffer = gTransientHeaps[0]->createCommandBuffer();
auto encoder = commandBuffer->encodeResourceCommands();
- encoder->textureBarrier(gLearningTexture, ResourceState::RenderTarget, ResourceState::UnorderedAccess);
- encoder->textureBarrier(gDiffTexture, ResourceState::RenderTarget, ResourceState::UnorderedAccess);
- encoder->textureBarrier(gRefImage, ResourceState::RenderTarget, ResourceState::ShaderResource);
- encoder->textureBarrier(gIterImage, ResourceState::RenderTarget, ResourceState::ShaderResource);
+ encoder->textureBarrier(
+ gLearningTexture,
+ ResourceState::RenderTarget,
+ ResourceState::UnorderedAccess);
+ encoder->textureBarrier(
+ gDiffTexture,
+ ResourceState::RenderTarget,
+ ResourceState::UnorderedAccess);
+ encoder->textureBarrier(
+ gRefImage,
+ ResourceState::RenderTarget,
+ ResourceState::ShaderResource);
+ encoder->textureBarrier(
+ gIterImage,
+ ResourceState::RenderTarget,
+ ResourceState::ShaderResource);
for (int i = 0; i < gLearningTextureUAVs.getCount(); i++)
{
ClearValue clearValue = {};
- encoder->clearResourceView(gLearningTextureUAVs[i], &clearValue, ClearResourceViewFlags::None);
- encoder->clearResourceView(gDiffTextureUAVs[i], &clearValue, ClearResourceViewFlags::None);
+ encoder->clearResourceView(
+ gLearningTextureUAVs[i],
+ &clearValue,
+ ClearResourceViewFlags::None);
+ encoder->clearResourceView(
+ gDiffTextureUAVs[i],
+ &clearValue,
+ ClearResourceViewFlags::None);
}
- encoder->textureBarrier(gLearningTexture, ResourceState::UnorderedAccess, ResourceState::ShaderResource);
+ encoder->textureBarrier(
+ gLearningTexture,
+ ResourceState::UnorderedAccess,
+ ResourceState::ShaderResource);
encoder->endEncoding();
commandBuffer->close();
@@ -453,7 +499,10 @@ struct AutoDiffTexture : public WindowedAppBase
float rotX = (rand() / (float)RAND_MAX) * 0.3f;
float rotY = (rand() / (float)RAND_MAX) * 0.2f;
glm::mat4x4 matProj = glm::perspectiveRH_ZO(
- glm::radians(60.0f), (float)windowWidth / (float)windowHeight, 0.1f, 1000.0f);
+ glm::radians(60.0f),
+ (float)windowWidth / (float)windowHeight,
+ 0.1f,
+ 1000.0f);
auto identity = glm::mat4(1.0f);
auto translate = glm::translate(
identity,
@@ -468,9 +517,11 @@ struct AutoDiffTexture : public WindowedAppBase
return transformMatrix;
}
- template <typename SetupPipelineFunc>
+ template<typename SetupPipelineFunc>
void renderImage(
- int transientHeapIndex, IFramebuffer* fb, const SetupPipelineFunc& setupPipeline)
+ int transientHeapIndex,
+ IFramebuffer* fb,
+ const SetupPipelineFunc& setupPipeline)
{
ComPtr<ICommandBuffer> commandBuffer =
gTransientHeaps[transientHeapIndex]->createCommandBuffer();
@@ -496,9 +547,13 @@ struct AutoDiffTexture : public WindowedAppBase
void renderReferenceImage(int transientHeapIndex, glm::mat4x4 transformMatrix)
{
{
- ComPtr<ICommandBuffer> commandBuffer = gTransientHeaps[transientHeapIndex]->createCommandBuffer();
+ ComPtr<ICommandBuffer> commandBuffer =
+ gTransientHeaps[transientHeapIndex]->createCommandBuffer();
auto encoder = commandBuffer->encodeResourceCommands();
- encoder->textureBarrier(gRefImage, ResourceState::ShaderResource, ResourceState::RenderTarget);
+ encoder->textureBarrier(
+ gRefImage,
+ ResourceState::ShaderResource,
+ ResourceState::RenderTarget);
encoder->endEncoding();
commandBuffer->close();
gQueue->executeCommandBuffer(commandBuffer);
@@ -512,12 +567,16 @@ struct AutoDiffTexture : public WindowedAppBase
auto rootObject = encoder->bindPipeline(gRefPipelineState);
ShaderCursor rootCursor(rootObject);
rootCursor["Uniforms"]["modelViewProjection"].setData(
- &transformMatrix, sizeof(float) * 16);
+ &transformMatrix,
+ sizeof(float) * 16);
rootCursor["Uniforms"]["bwdTexture"]["texture"].setResource(gTexView);
rootCursor["Uniforms"]["sampler"].setSampler(gSampler);
- rootCursor["Uniforms"]["mipOffset"].setData(mipMapOffset.getBuffer(), sizeof(uint32_t) * mipMapOffset.getCount());
+ rootCursor["Uniforms"]["mipOffset"].setData(
+ mipMapOffset.getBuffer(),
+ sizeof(uint32_t) * mipMapOffset.getCount());
rootCursor["Uniforms"]["texRef"].setResource(gTexView);
- rootCursor["Uniforms"]["bwdTexture"]["accumulateBuffer"].setResource(gAccumulateBufferView);
+ rootCursor["Uniforms"]["bwdTexture"]["accumulateBuffer"].setResource(
+ gAccumulateBufferView);
});
}
@@ -527,25 +586,52 @@ struct AutoDiffTexture : public WindowedAppBase
frameCount++;
auto transformMatrix = getTransformMatrix();
renderReferenceImage(frameBufferIndex, transformMatrix);
-
+
// Barriers.
{
ComPtr<ICommandBuffer> commandBuffer =
gTransientHeaps[frameBufferIndex]->createCommandBuffer();
auto resEncoder = commandBuffer->encodeResourceCommands();
ClearValue clearValue = {};
- resEncoder->bufferBarrier(gAccumulateBuffer, ResourceState::Undefined, ResourceState::UnorderedAccess);
- resEncoder->bufferBarrier(gReconstructBuffer, ResourceState::Undefined, ResourceState::UnorderedAccess);
- resEncoder->textureBarrier(gRefImage, ResourceState::Present, ResourceState::ShaderResource);
- resEncoder->textureBarrier(gIterImage, ResourceState::ShaderResource, ResourceState::RenderTarget);
- resEncoder->clearResourceView(gAccumulateBufferView, &clearValue, ClearResourceViewFlags::None);
- resEncoder->clearResourceView(gReconstructBufferView, &clearValue, ClearResourceViewFlags::None);
+ resEncoder->bufferBarrier(
+ gAccumulateBuffer,
+ ResourceState::Undefined,
+ ResourceState::UnorderedAccess);
+ resEncoder->bufferBarrier(
+ gReconstructBuffer,
+ ResourceState::Undefined,
+ ResourceState::UnorderedAccess);
+ resEncoder->textureBarrier(
+ gRefImage,
+ ResourceState::Present,
+ ResourceState::ShaderResource);
+ resEncoder->textureBarrier(
+ gIterImage,
+ ResourceState::ShaderResource,
+ ResourceState::RenderTarget);
+ resEncoder->clearResourceView(
+ gAccumulateBufferView,
+ &clearValue,
+ ClearResourceViewFlags::None);
+ resEncoder->clearResourceView(
+ gReconstructBufferView,
+ &clearValue,
+ ClearResourceViewFlags::None);
if (resetLearntTexture)
{
- resEncoder->textureBarrier(gLearningTexture, ResourceState::ShaderResource, ResourceState::UnorderedAccess);
- for (Index i =0; i <gLearningTextureUAVs.getCount(); i++)
- resEncoder->clearResourceView(gLearningTextureUAVs[i], &clearValue, ClearResourceViewFlags::None);
- resEncoder->textureBarrier(gLearningTexture, ResourceState::UnorderedAccess, ResourceState::ShaderResource);
+ resEncoder->textureBarrier(
+ gLearningTexture,
+ ResourceState::ShaderResource,
+ ResourceState::UnorderedAccess);
+ for (Index i = 0; i < gLearningTextureUAVs.getCount(); i++)
+ resEncoder->clearResourceView(
+ gLearningTextureUAVs[i],
+ &clearValue,
+ ClearResourceViewFlags::None);
+ resEncoder->textureBarrier(
+ gLearningTexture,
+ ResourceState::UnorderedAccess,
+ ResourceState::ShaderResource);
resetLearntTexture = false;
}
resEncoder->endEncoding();
@@ -561,16 +647,19 @@ struct AutoDiffTexture : public WindowedAppBase
{
auto rootObject = encoder->bindPipeline(gIterPipelineState);
ShaderCursor rootCursor(rootObject);
-
+
rootCursor["Uniforms"]["modelViewProjection"].setData(
- &transformMatrix, sizeof(float) * 16);
+ &transformMatrix,
+ sizeof(float) * 16);
rootCursor["Uniforms"]["bwdTexture"]["texture"].setResource(gLearningTextureSRV);
rootCursor["Uniforms"]["sampler"].setSampler(gSampler);
- rootCursor["Uniforms"]["mipOffset"].setData(mipMapOffset.getBuffer(), sizeof(uint32_t) * mipMapOffset.getCount());
+ rootCursor["Uniforms"]["mipOffset"].setData(
+ mipMapOffset.getBuffer(),
+ sizeof(uint32_t) * mipMapOffset.getCount());
rootCursor["Uniforms"]["texRef"].setResource(gRefImageSRV);
- rootCursor["Uniforms"]["bwdTexture"]["accumulateBuffer"].setResource(gAccumulateBufferView);
+ rootCursor["Uniforms"]["bwdTexture"]["accumulateBuffer"].setResource(
+ gAccumulateBufferView);
rootCursor["Uniforms"]["bwdTexture"]["minLOD"].setData(5.0);
-
});
// Propagete gradients through mip map layers from top (lowest res) to bottom (highest res).
@@ -578,12 +667,17 @@ struct AutoDiffTexture : public WindowedAppBase
ComPtr<ICommandBuffer> commandBuffer =
gTransientHeaps[frameBufferIndex]->createCommandBuffer();
auto encoder = commandBuffer->encodeComputeCommands();
- encoder->textureBarrier(gLearningTexture, ResourceState::ShaderResource, ResourceState::UnorderedAccess);
+ encoder->textureBarrier(
+ gLearningTexture,
+ ResourceState::ShaderResource,
+ ResourceState::UnorderedAccess);
auto rootObject = encoder->bindPipeline(gReconstructPipelineState);
for (int i = (int)mipMapOffset.getCount() - 2; i >= 0; i--)
{
ShaderCursor rootCursor(rootObject);
- rootCursor["Uniforms"]["mipOffset"].setData(mipMapOffset.getBuffer(), sizeof(uint32_t) * mipMapOffset.getCount());
+ rootCursor["Uniforms"]["mipOffset"].setData(
+ mipMapOffset.getBuffer(),
+ sizeof(uint32_t) * mipMapOffset.getCount());
rootCursor["Uniforms"]["dstLayer"].setData(i);
rootCursor["Uniforms"]["layerCount"].setData(mipMapOffset.getCount() - 1);
rootCursor["Uniforms"]["width"].setData(textureWidth);
@@ -591,22 +685,31 @@ struct AutoDiffTexture : public WindowedAppBase
rootCursor["Uniforms"]["accumulateBuffer"].setResource(gAccumulateBufferView);
rootCursor["Uniforms"]["dstBuffer"].setResource(gReconstructBufferView);
encoder->dispatchCompute(
- ((textureWidth >> i) + 15) / 16, ((textureHeight >> i) + 15) / 16, 1);
- encoder->bufferBarrier(gReconstructBuffer, ResourceState::UnorderedAccess, ResourceState::UnorderedAccess);
+ ((textureWidth >> i) + 15) / 16,
+ ((textureHeight >> i) + 15) / 16,
+ 1);
+ encoder->bufferBarrier(
+ gReconstructBuffer,
+ ResourceState::UnorderedAccess,
+ ResourceState::UnorderedAccess);
}
// Convert bottom layer mip from buffer to texture.
rootObject = encoder->bindPipeline(gConvertPipelineState);
ShaderCursor rootCursor(rootObject);
- rootCursor["Uniforms"]["mipOffset"].setData(mipMapOffset.getBuffer(), sizeof(uint32_t) * mipMapOffset.getCount());
+ rootCursor["Uniforms"]["mipOffset"].setData(
+ mipMapOffset.getBuffer(),
+ sizeof(uint32_t) * mipMapOffset.getCount());
rootCursor["Uniforms"]["dstLayer"].setData(0);
rootCursor["Uniforms"]["width"].setData(textureWidth);
rootCursor["Uniforms"]["height"].setData(textureHeight);
rootCursor["Uniforms"]["srcBuffer"].setResource(gReconstructBufferView);
rootCursor["Uniforms"]["dstTexture"].setResource(gDiffTextureUAVs[0]);
- encoder->dispatchCompute(
- (textureWidth + 15) / 16, (textureHeight + 15) / 16, 1);
- encoder->textureBarrier(gDiffTexture, ResourceState::UnorderedAccess, ResourceState::UnorderedAccess);
+ encoder->dispatchCompute((textureWidth + 15) / 16, (textureHeight + 15) / 16, 1);
+ encoder->textureBarrier(
+ gDiffTexture,
+ ResourceState::UnorderedAccess,
+ ResourceState::UnorderedAccess);
// Build higher level mip map layers.
rootObject = encoder->bindPipeline(gBuildMipPipelineState);
@@ -615,11 +718,16 @@ struct AutoDiffTexture : public WindowedAppBase
ShaderCursor rootCursor(rootObject);
rootCursor["Uniforms"]["dstWidth"].setData(textureWidth >> i);
rootCursor["Uniforms"]["dstHeight"].setData(textureHeight >> i);
- rootCursor["Uniforms"]["srcTexture"].setResource(gDiffTextureUAVs[i-1]);
+ rootCursor["Uniforms"]["srcTexture"].setResource(gDiffTextureUAVs[i - 1]);
rootCursor["Uniforms"]["dstTexture"].setResource(gDiffTextureUAVs[i]);
encoder->dispatchCompute(
- ((textureWidth >> i) + 15) / 16, ((textureHeight >> i) + 15) / 16, 1);
- encoder->textureBarrier(gDiffTexture, ResourceState::UnorderedAccess, ResourceState::UnorderedAccess);
+ ((textureWidth >> i) + 15) / 16,
+ ((textureHeight >> i) + 15) / 16,
+ 1);
+ encoder->textureBarrier(
+ gDiffTexture,
+ ResourceState::UnorderedAccess,
+ ResourceState::UnorderedAccess);
}
// Accumulate gradients to learnt texture.
@@ -633,10 +741,18 @@ struct AutoDiffTexture : public WindowedAppBase
rootCursor["Uniforms"]["srcTexture"].setResource(gDiffTextureUAVs[i]);
rootCursor["Uniforms"]["dstTexture"].setResource(gLearningTextureUAVs[i]);
encoder->dispatchCompute(
- ((textureWidth >> i) + 15) / 16, ((textureHeight >> i) + 15) / 16, 1);
+ ((textureWidth >> i) + 15) / 16,
+ ((textureHeight >> i) + 15) / 16,
+ 1);
}
- encoder->textureBarrier(gLearningTexture, ResourceState::UnorderedAccess, ResourceState::ShaderResource);
- encoder->textureBarrier(gIterImage, ResourceState::Present, ResourceState::ShaderResource);
+ encoder->textureBarrier(
+ gLearningTexture,
+ ResourceState::UnorderedAccess,
+ ResourceState::ShaderResource);
+ encoder->textureBarrier(
+ gIterImage,
+ ResourceState::Present,
+ ResourceState::ShaderResource);
encoder->endEncoding();
commandBuffer->close();
@@ -647,12 +763,25 @@ struct AutoDiffTexture : public WindowedAppBase
{
ComPtr<ICommandBuffer> commandBuffer =
gTransientHeaps[frameBufferIndex]->createCommandBuffer();
- auto renderEncoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]);
+ auto renderEncoder =
+ commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]);
drawTexturedQuad(renderEncoder, 0, 0, textureWidth, textureHeight, gLearningTextureSRV);
int refImageWidth = windowWidth - textureWidth - 10;
int refImageHeight = refImageWidth * windowHeight / windowWidth;
- drawTexturedQuad(renderEncoder, textureWidth + 10, 0, refImageWidth, refImageHeight, gRefImageSRV);
- drawTexturedQuad(renderEncoder, textureWidth + 10, refImageHeight + 10, refImageWidth, refImageHeight, gIterImageSRV);
+ drawTexturedQuad(
+ renderEncoder,
+ textureWidth + 10,
+ 0,
+ refImageWidth,
+ refImageHeight,
+ gRefImageSRV);
+ drawTexturedQuad(
+ renderEncoder,
+ textureWidth + 10,
+ refImageHeight + 10,
+ refImageWidth,
+ refImageHeight,
+ gIterImageSRV);
renderEncoder->endEncoding();
commandBuffer->close();
gQueue->executeCommandBuffer(commandBuffer);
@@ -664,7 +793,13 @@ struct AutoDiffTexture : public WindowedAppBase
}
}
- void drawTexturedQuad(IRenderCommandEncoder* renderEncoder, int x, int y, int w, int h, IResourceView* srv)
+ void drawTexturedQuad(
+ IRenderCommandEncoder* renderEncoder,
+ int x,
+ int y,
+ int w,
+ int h,
+ IResourceView* srv)
{
gfx::Viewport viewport = {};
viewport.maxZ = 1.0f;
@@ -686,7 +821,6 @@ struct AutoDiffTexture : public WindowedAppBase
renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleStrip);
renderEncoder->draw(4);
}
-
};
PLATFORM_UI_MAIN(innerMain<AutoDiffTexture>)
diff --git a/examples/cpu-com-example/main.cpp b/examples/cpu-com-example/main.cpp
index 62a01d17f..382b3cacd 100644
--- a/examples/cpu-com-example/main.cpp
+++ b/examples/cpu-com-example/main.cpp
@@ -1,11 +1,10 @@
// main.cpp
-#include <stdio.h>
-
+#include "slang-com-helper.h"
+#include "slang-com-ptr.h"
#include "slang.h"
-#include "slang-com-ptr.h"
-#include "slang-com-helper.h"
+#include <stdio.h>
// This includes a useful small function for setting up the prelude (described more further below).
#include "../../source/core/slang-test-tool-util.h"
@@ -17,9 +16,9 @@ using namespace Slang;
static const ExampleResources resourceBase("cpu-com-example");
-// For the moment we have to explicitly write the Slang COM interface in C++ code. It *MUST* match
+// For the moment we have to explicitly write the Slang COM interface in C++ code. It *MUST* match
// the interface in the slang source
-// As it stands all interfaces need to derive from ISlangUnknown (or IUnknown).
+// As it stands all interfaces need to derive from ISlangUnknown (or IUnknown).
class IDoThings : public ISlangUnknown
{
public:
@@ -43,19 +42,33 @@ class DoThings : public IDoThings
{
public:
// We don't need queryInterface for this impl, or ref counting
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE { return SLANG_E_NOT_IMPLEMENTED; }
- virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; }
- virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; }
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL
+ queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE
+ {
+ return SLANG_E_NOT_IMPLEMENTED;
+ }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; }
+ virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; }
// IDoThings
- virtual SLANG_NO_THROW int SLANG_MCALL doThing(int a, int b) SLANG_OVERRIDE { return a + b + 1; }
- virtual SLANG_NO_THROW int SLANG_MCALL calcHash(const char* in) SLANG_OVERRIDE { return (int)_calcHash(in); }
- virtual SLANG_NO_THROW void SLANG_MCALL printMessage(const char* in) SLANG_OVERRIDE { printf("%s\n", in); }
+ virtual SLANG_NO_THROW int SLANG_MCALL doThing(int a, int b) SLANG_OVERRIDE
+ {
+ return a + b + 1;
+ }
+ virtual SLANG_NO_THROW int SLANG_MCALL calcHash(const char* in) SLANG_OVERRIDE
+ {
+ return (int)_calcHash(in);
+ }
+ virtual SLANG_NO_THROW void SLANG_MCALL printMessage(const char* in) SLANG_OVERRIDE
+ {
+ printf("%s\n", in);
+ }
};
static SlangResult _innerMain(int argc, char** argv)
{
- // NOTE! This example only works if `slang-llvm` or a C++ compiler that Slang supports is available.
+ // NOTE! This example only works if `slang-llvm` or a C++ compiler that Slang supports is
+ // available.
// Create the session
ComPtr<slang::IGlobalSession> slangSession;
@@ -72,16 +85,17 @@ static SlangResult _innerMain(int argc, char** argv)
SLANG_ALLOW_DEPRECATED_END
// We want to compile to 'HOST_CALLABLE' here such that we can execute the Slang code.
- //
- // Note that it is possible to use HOST_HOST_CALLABLE, but this currently only works with 'regular' C++ compilers
- // not with `slang-llvm`.
+ //
+ // Note that it is possible to use HOST_HOST_CALLABLE, but this currently only works with
+ // 'regular' C++ compilers not with `slang-llvm`.
const int targetIndex = request->addCodeGenTarget(SLANG_SHADER_HOST_CALLABLE);
// Set the target flag to indicate that we want to compile all into a library.
request->setTargetFlags(targetIndex, SLANG_TARGET_FLAG_GENERATE_WHOLE_PROGRAM);
// Add the translation unit
- const int translationUnitIndex = request->addTranslationUnit(SLANG_SOURCE_LANGUAGE_SLANG, nullptr);
+ const int translationUnitIndex =
+ request->addTranslationUnit(SLANG_SOURCE_LANGUAGE_SLANG, nullptr);
// Set the source file for the translation unit
Slang::String path = resourceBase.resolveResource("shader.slang");
@@ -93,13 +107,13 @@ static SlangResult _innerMain(int argc, char** argv)
// compiler may have produced "diagnostic" output such as warnings.
// We will go ahead and print that output here.
//
- if(auto diagnostics = request->getDiagnosticOutput())
+ if (auto diagnostics = request->getDiagnosticOutput())
{
printf("%s", diagnostics);
}
- // Get the 'shared library' (note that this doesn't necessarily have to be implemented as a shared library
- // it's just an interface to executable code).
+ // Get the 'shared library' (note that this doesn't necessarily have to be implemented as a
+ // shared library it's just an interface to executable code).
ComPtr<ISlangSharedLibrary> sharedLibrary;
SLANG_RETURN_ON_FAIL(request->getTargetHostCallable(0, sharedLibrary.writeRef()));
diff --git a/examples/cpu-hello-world/main.cpp b/examples/cpu-hello-world/main.cpp
index 059efc8d3..60a24fa8c 100644
--- a/examples/cpu-hello-world/main.cpp
+++ b/examples/cpu-hello-world/main.cpp
@@ -3,7 +3,7 @@
#include <stdio.h>
// This file implements an extremely simple example of loading and
-// executing a Slang shader program on the CPU.
+// executing a Slang shader program on the CPU.
//
// More information about generation C++ or CPU code can be found in docs/cpu-target.md
//
@@ -20,7 +20,7 @@
// Allows use of ComPtr - which we can use to scope any 'com-like' pointers easily
#include "slang-com-ptr.h"
-// Provides macros for handling SlangResult values easily
+// Provides macros for handling SlangResult values easily
#include "slang-com-helper.h"
// This includes a useful small function for setting up the prelude (described more further below).
@@ -34,10 +34,10 @@ using namespace Slang;
// Slang source is converted into C++ code which is compiled by a backend compiler.
// That process uses a 'prelude' which defines types and functions that are needed
// for everything else to work.
-//
+//
// We include the prelude here, so we can directly use the types as were used by the
// compiled code. It is not necessary to include the prelude, as long as memory is
-// laid out in the manner that the generated slang code expects.
+// laid out in the manner that the generated slang code expects.
#define SLANG_PRELUDE_NAMESPACE CPPPrelude
#include "../../prelude/slang-cpp-types.h"
@@ -75,11 +75,13 @@ static SlangResult _innerMain(int argc, char** argv)
//
// Most downstream C++ compilers work on files. In that case slang may generate temporary
// files that contain the generated code. Typically the generated files will not be in the
- // same directory as the original source so handling includes becomes awkward. The mechanism used here
- // is for the prelude code to be an *absolute* path to the 'slang-cpp-prelude.h' - which means
- // this will work wherever the generated code is, and allows accessing other files via relative paths.
+ // same directory as the original source so handling includes becomes awkward. The mechanism
+ // used here is for the prelude code to be an *absolute* path to the 'slang-cpp-prelude.h' -
+ // which means this will work wherever the generated code is, and allows accessing other files
+ // via relative paths.
//
- // Look at the source to TestToolUtil::setSessionDefaultPreludeFromExePath to see what's involed.
+ // Look at the source to TestToolUtil::setSessionDefaultPreludeFromExePath to see what's
+ // involed.
TestToolUtil::setSessionDefaultPreludeFromExePath(argv[0], slangSession);
slang::SessionDesc sessionDesc = {};
@@ -122,13 +124,16 @@ static SlangResult _innerMain(int argc, char** argv)
SLANG_RETURN_ON_FAIL(result);
}
- // Get the 'shared library' (note that this doesn't necessarily have to be implemented as a shared library
- // it's just an interface to executable code).
+ // Get the 'shared library' (note that this doesn't necessarily have to be implemented as a
+ // shared library it's just an interface to executable code).
ComPtr<ISlangSharedLibrary> sharedLibrary;
{
ComPtr<slang::IBlob> diagnosticsBlob;
SlangResult result = composedProgram->getEntryPointHostCallable(
- 0, 0, sharedLibrary.writeRef(), diagnosticsBlob.writeRef());
+ 0,
+ 0,
+ sharedLibrary.writeRef(),
+ diagnosticsBlob.writeRef());
diagnoseIfNeeded(diagnosticsBlob);
SLANG_RETURN_ON_FAIL(result);
if (testBase.isTestMode())
@@ -137,55 +142,58 @@ static SlangResult _innerMain(int argc, char** argv)
}
}
// Once we have the sharedLibrary, we no longer need the request
- // unless we want to use reflection, to for example workout how 'UniformState' and 'UniformEntryPointParams' are laid out
- // at runtime. We don't do that here - as we hard code the structures.
+ // unless we want to use reflection, to for example workout how 'UniformState' and
+ // 'UniformEntryPointParams' are laid out at runtime. We don't do that here - as we hard code
+ // the structures.
// Get the function we are going to execute
const char entryPointName[] = "computeMain";
- CPPPrelude::ComputeFunc func = (CPPPrelude::ComputeFunc)sharedLibrary->findFuncByName(entryPointName);
+ CPPPrelude::ComputeFunc func =
+ (CPPPrelude::ComputeFunc)sharedLibrary->findFuncByName(entryPointName);
if (!func)
{
return SLANG_FAIL;
}
// Define the uniform state structure that is *specific* to our shader defined in shader.slang
- // That the layout of the structure can be determined through reflection, or can be inferred from
- // the original slang source. Look at the documentation in docs/cpu-target.md which describes
- // how different resources map.
- // The order of the resources is in the order that they are defined in the source.
+ // That the layout of the structure can be determined through reflection, or can be inferred
+ // from the original slang source. Look at the documentation in docs/cpu-target.md which
+ // describes how different resources map. The order of the resources is in the order that they
+ // are defined in the source.
struct UniformState
{
CPPPrelude::RWStructuredBuffer<float> ioBuffer;
};
- // the uniformState will be passed as a pointer to the CPU code
+ // the uniformState will be passed as a pointer to the CPU code
UniformState uniformState;
// The contents of the buffer are modified, so we'll copy it
- const float startBufferContents[] = { 2.0f, -10.0f, -3.0f, 5.0f };
+ const float startBufferContents[] = {2.0f, -10.0f, -3.0f, 5.0f};
float bufferContents[SLANG_COUNT_OF(startBufferContents)];
memcpy(bufferContents, startBufferContents, sizeof(startBufferContents));
// Set up the ioBuffer such that it uses bufferContents. It is important to set the .count
- // such that bounds checking can be performed in the kernel.
+ // such that bounds checking can be performed in the kernel.
uniformState.ioBuffer.data = bufferContents;
uniformState.ioBuffer.count = SLANG_COUNT_OF(bufferContents);
- // In shader.slang, then entry point is attributed with `[numthreads(4, 1, 1)]` meaning each group
- // consists of 4 'thread' in x. Our input buffer is 4 wide, and we index the input array via `SV_DispatchThreadID`
- // so we only need to run a single group to execute over all of the 4 elements here.
- // The group range from { 0, 0, 0 } -> { 1, 1, 1 } means it will execute over the single group { 0, 0, 0 }.
+ // In shader.slang, then entry point is attributed with `[numthreads(4, 1, 1)]` meaning each
+ // group consists of 4 'thread' in x. Our input buffer is 4 wide, and we index the input array
+ // via `SV_DispatchThreadID` so we only need to run a single group to execute over all of the 4
+ // elements here. The group range from { 0, 0, 0 } -> { 1, 1, 1 } means it will execute over the
+ // single group { 0, 0, 0 }.
- const CPPPrelude::uint3 startGroupID = { 0, 0, 0};
- const CPPPrelude::uint3 endGroupID = { 1, 1, 1 };
+ const CPPPrelude::uint3 startGroupID = {0, 0, 0};
+ const CPPPrelude::uint3 endGroupID = {1, 1, 1};
CPPPrelude::ComputeVaryingInput varyingInput;
varyingInput.startGroupID = startGroupID;
varyingInput.endGroupID = endGroupID;
// We don't have any entry point parameters so that's passed as NULL
- // We need to cast our definition of the uniform state to the undefined CPPPrelude::UniformState as
- // that type is just a name to indicate what kind of thing needs to be passed in.
+ // We need to cast our definition of the uniform state to the undefined CPPPrelude::UniformState
+ // as that type is just a name to indicate what kind of thing needs to be passed in.
func(&varyingInput, NULL, &uniformState);
// bufferContents holds the output
diff --git a/examples/example-base/example-base.cpp b/examples/example-base/example-base.cpp
index 344611bed..9951d7cf2 100644
--- a/examples/example-base/example-base.cpp
+++ b/examples/example-base/example-base.cpp
@@ -1,4 +1,5 @@
#include "example-base.h"
+
#include <chrono>
#ifdef _WIN32
@@ -123,7 +124,11 @@ void WindowedAppBase::offlineRender()
gTransientHeaps[0]->finish();
}
-void WindowedAppBase::createFramebuffers(uint32_t width, uint32_t height, gfx::Format colorFormat, uint32_t frameBufferCount)
+void WindowedAppBase::createFramebuffers(
+ uint32_t width,
+ uint32_t height,
+ gfx::Format colorFormat,
+ uint32_t frameBufferCount)
{
for (uint32_t i = 0; i < frameBufferCount; i++)
{
@@ -150,7 +155,8 @@ void WindowedAppBase::createFramebuffers(uint32_t width, uint32_t height, gfx::F
colorBufferDesc.size.depth = 1;
colorBufferDesc.format = colorFormat;
colorBufferDesc.defaultState = ResourceState::RenderTarget;
- colorBufferDesc.allowedStates = ResourceStateSet(ResourceState::RenderTarget, ResourceState::CopyDestination);
+ colorBufferDesc.allowedStates =
+ ResourceStateSet(ResourceState::RenderTarget, ResourceState::CopyDestination);
colorBuffer = gDevice->createTextureResource(colorBufferDesc, nullptr);
}
else
@@ -194,14 +200,21 @@ void WindowedAppBase::createOfflineFramebuffers()
void WindowedAppBase::createSwapchainFramebuffers()
{
gFramebuffers.clear();
- createFramebuffers(gSwapchain->getDesc().width, gSwapchain->getDesc().height,
- gSwapchain->getDesc().format, kSwapchainImageCount);
+ createFramebuffers(
+ gSwapchain->getDesc().width,
+ gSwapchain->getDesc().height,
+ gSwapchain->getDesc().format,
+ kSwapchainImageCount);
}
-ComPtr<gfx::IResourceView> WindowedAppBase::createTextureFromFile(String fileName, int& textureWidth, int& textureHeight)
+ComPtr<gfx::IResourceView> WindowedAppBase::createTextureFromFile(
+ String fileName,
+ int& textureWidth,
+ int& textureHeight)
{
int channelsInFile = 0;
- auto textureContent = stbi_load(fileName.getBuffer(), &textureWidth, &textureHeight, &channelsInFile, 4);
+ auto textureContent =
+ stbi_load(fileName.getBuffer(), &textureWidth, &textureHeight, &channelsInFile, 4);
gfx::ITextureResource::Desc textureDesc = {};
textureDesc.allowedStates.add(ResourceState::ShaderResource);
textureDesc.format = gfx::Format::R8G8B8A8_UNORM;
@@ -222,9 +235,22 @@ ComPtr<gfx::IResourceView> WindowedAppBase::createTextureFromFile(String fileNam
subresData[0].strideZ = textureWidth * textureHeight * 4;
// Build mipmaps.
- struct RGBA { uint8_t v[4]; };
- auto castToRGBA = [](uint32_t v) { RGBA result; memcpy(&result, &v, 4); return result; };
- auto castToUint = [](RGBA v) { uint32_t result; memcpy(&result, &v, 4); return result; };
+ struct RGBA
+ {
+ uint8_t v[4];
+ };
+ auto castToRGBA = [](uint32_t v)
+ {
+ RGBA result;
+ memcpy(&result, &v, 4);
+ return result;
+ };
+ auto castToUint = [](RGBA v)
+ {
+ uint32_t result;
+ memcpy(&result, &v, 4);
+ return result;
+ };
int lastMipWidth = textureWidth;
int lastMipHeight = textureHeight;
@@ -248,7 +274,8 @@ ComPtr<gfx::IResourceView> WindowedAppBase::createTextureFromFile(String fileNam
RGBA pix;
for (int c = 0; c < 4; c++)
{
- pix.v[c] = (uint8_t)(((uint32_t)pix1.v[c] + pix2.v[c] + pix3.v[c] + pix4.v[c]) / 4);
+ pix.v[c] =
+ (uint8_t)(((uint32_t)pix1.v[c] + pix2.v[c] + pix3.v[c] + pix4.v[c]) / 4);
}
mipMapData[m][y * w + x] = castToUint(pix);
}
@@ -286,40 +313,35 @@ void WindowedAppBase::windowSizeChanged()
}
}
-int64_t getCurrentTime() { return std::chrono::high_resolution_clock::now().time_since_epoch().count(); }
+int64_t getCurrentTime()
+{
+ return std::chrono::high_resolution_clock::now().time_since_epoch().count();
+}
-int64_t getTimerFrequency() { return std::chrono::high_resolution_clock::period::den; }
+int64_t getTimerFrequency()
+{
+ return std::chrono::high_resolution_clock::period::den;
+}
class DebugCallback : public IDebugCallback
{
public:
virtual SLANG_NO_THROW void SLANG_MCALL
- handleMessage(DebugMessageType type, DebugMessageSource source, const char* message) override
+ handleMessage(DebugMessageType type, DebugMessageSource source, const char* message) override
{
const char* typeStr = "";
switch (type)
{
- case DebugMessageType::Info:
- typeStr = "INFO: ";
- break;
- case DebugMessageType::Warning:
- typeStr = "WARNING: ";
- break;
- case DebugMessageType::Error:
- typeStr = "ERROR: ";
- break;
- default:
- break;
+ case DebugMessageType::Info: typeStr = "INFO: "; break;
+ case DebugMessageType::Warning: typeStr = "WARNING: "; break;
+ case DebugMessageType::Error: typeStr = "ERROR: "; break;
+ default: break;
}
const char* sourceStr = "[GraphicsLayer]: ";
switch (source)
{
- case DebugMessageSource::Slang:
- sourceStr = "[Slang]: ";
- break;
- case DebugMessageSource::Driver:
- sourceStr = "[Driver]: ";
- break;
+ case DebugMessageSource::Slang: sourceStr = "[Slang]: "; break;
+ case DebugMessageSource::Driver: sourceStr = "[Driver]: "; break;
}
printf("%s%s%s\n", sourceStr, typeStr, message);
#ifdef _WIN32
@@ -338,5 +360,8 @@ void initDebugCallback()
}
#ifdef _WIN32
-void _Win32OutputDebugString(const char* str) { OutputDebugStringW(Slang::String(str).toWString().begin()); }
+void _Win32OutputDebugString(const char* str)
+{
+ OutputDebugStringW(Slang::String(str).toWString().begin());
+}
#endif
diff --git a/examples/example-base/example-base.h b/examples/example-base/example-base.h
index b97728e17..c10231c14 100644
--- a/examples/example-base/example-base.h
+++ b/examples/example-base/example-base.h
@@ -1,10 +1,10 @@
#pragma once
#include "slang-gfx.h"
-#include "tools/platform/window.h"
#include "source/core/slang-basic.h"
#include "source/core/slang-io.h"
#include "test-base.h"
+#include "tools/platform/window.h"
#ifdef _WIN32
void _Win32OutputDebugString(const char* str);
@@ -34,38 +34,52 @@ protected:
int height,
gfx::DeviceType deviceType = gfx::DeviceType::Default);
- void createFramebuffers(uint32_t width, uint32_t height, gfx::Format colorFormat, uint32_t frameBufferCount);
+ void createFramebuffers(
+ uint32_t width,
+ uint32_t height,
+ gfx::Format colorFormat,
+ uint32_t frameBufferCount);
void createSwapchainFramebuffers();
void createOfflineFramebuffers();
void mainLoop();
- Slang::ComPtr<gfx::IResourceView> createTextureFromFile(Slang::String fileName, int& textureWidth, int& textureHeight);
+ Slang::ComPtr<gfx::IResourceView> createTextureFromFile(
+ Slang::String fileName,
+ int& textureWidth,
+ int& textureHeight);
virtual void windowSizeChanged();
protected:
virtual void renderFrame(int framebufferIndex) = 0;
+
public:
platform::Window* getWindow() { return gWindow.Ptr(); }
virtual void finalize() { gQueue->waitOnHost(); }
void offlineRender();
};
-struct ExampleResources {
+struct ExampleResources
+{
Slang::String baseDir;
- ExampleResources(const Slang::String &dir) : baseDir(dir) {}
-
- Slang::String resolveResource(const char* fileName) const {
- static const Slang::List<Slang::String> directories {
+ ExampleResources(const Slang::String& dir)
+ : baseDir(dir)
+ {
+ }
+
+ Slang::String resolveResource(const char* fileName) const
+ {
+ static const Slang::List<Slang::String> directories{
"examples",
"../examples",
"../../examples",
};
-
- for (const Slang::String& dir : directories) {
+
+ for (const Slang::String& dir : directories)
+ {
Slang::StringBuilder pathSb;
- pathSb << dir << "/" << baseDir << "/" << fileName;
+ pathSb << dir << "/" << baseDir << "/" << fileName;
if (Slang::File::exists(pathSb.getBuffer()))
return pathSb.toString();
}
@@ -77,7 +91,8 @@ struct ExampleResources {
int64_t getCurrentTime();
int64_t getTimerFrequency();
-template<typename ... TArgs> inline void reportError(const char* format, TArgs... args)
+template<typename... TArgs>
+inline void reportError(const char* format, TArgs... args)
{
printf(format, args...);
#ifdef _WIN32
@@ -87,7 +102,8 @@ template<typename ... TArgs> inline void reportError(const char* format, TArgs..
#endif
}
-template <typename... TArgs> inline void log(const char* format, TArgs... args)
+template<typename... TArgs>
+inline void log(const char* format, TArgs... args)
{
reportError(format, args...);
}
diff --git a/examples/example-base/test-base.cpp b/examples/example-base/test-base.cpp
index 9d8ec8ce6..5d40f2d80 100644
--- a/examples/example-base/test-base.cpp
+++ b/examples/example-base/test-base.cpp
@@ -30,23 +30,30 @@ int TestBase::parseOption(int argc, char** argv)
return 0;
}
-void TestBase::printEntrypointHashes(int entryPointCount, int targetCount, ComPtr<slang::IComponentType>& composedProgram)
+void TestBase::printEntrypointHashes(
+ int entryPointCount,
+ int targetCount,
+ ComPtr<slang::IComponentType>& composedProgram)
{
for (int targetIndex = 0; targetIndex < targetCount; targetIndex++)
{
for (int entryPointIndex = 0; entryPointIndex < entryPointCount; entryPointIndex++)
{
ComPtr<slang::IBlob> entryPointHashBlob;
- composedProgram->getEntryPointHash(entryPointIndex, targetIndex, entryPointHashBlob.writeRef());
+ composedProgram->getEntryPointHash(
+ entryPointIndex,
+ targetIndex,
+ entryPointHashBlob.writeRef());
Slang::StringBuilder strBuilder;
- strBuilder << "callIdx: " << m_globalCounter << ", entrypoint: "<< entryPointIndex << ", target: " << targetIndex << ", hash: ";
+ strBuilder << "callIdx: " << m_globalCounter << ", entrypoint: " << entryPointIndex
+ << ", target: " << targetIndex << ", hash: ";
m_globalCounter++;
uint8_t* buffer = (uint8_t*)entryPointHashBlob->getBufferPointer();
for (size_t i = 0; i < entryPointHashBlob->getBufferSize(); i++)
{
- strBuilder<<Slang::StringUtil::makeStringWithFormat("%.2X", buffer[i]);
+ strBuilder << Slang::StringUtil::makeStringWithFormat("%.2X", buffer[i]);
}
fprintf(stdout, "%s\n", strBuilder.begin());
}
diff --git a/examples/example-base/test-base.h b/examples/example-base/test-base.h
index cdd72c580..3f600eae7 100644
--- a/examples/example-base/test-base.h
+++ b/examples/example-base/test-base.h
@@ -1,22 +1,26 @@
#pragma once
-#include "slang.h"
#include "slang-com-ptr.h"
+#include "slang.h"
#include "source/core/slang-string-util.h"
using Slang::ComPtr;
-class TestBase {
+class TestBase
+{
public:
// Parses command line options. This example only has one option for testing purpose.
int parseOption(int argc, char** argv);
- void printEntrypointHashes(int entryPointCount, int targetCount, ComPtr<slang::IComponentType>& composedProgram);
+ void printEntrypointHashes(
+ int entryPointCount,
+ int targetCount,
+ ComPtr<slang::IComponentType>& composedProgram);
bool isTestMode() const { return m_isTestMode; }
private:
- bool m_isTestMode = false;
- uint64_t m_globalCounter = 0;
+ bool m_isTestMode = false;
+ uint64_t m_globalCounter = 0;
};
diff --git a/examples/gpu-printing/gpu-printing.cpp b/examples/gpu-printing/gpu-printing.cpp
index aeca7aa9a..f71578554 100644
--- a/examples/gpu-printing/gpu-printing.cpp
+++ b/examples/gpu-printing/gpu-printing.cpp
@@ -2,7 +2,6 @@
#include "gpu-printing.h"
#include <assert.h>
-
#include <string.h>
// This file implements the CPU side of a simple GPU printing
@@ -39,7 +38,7 @@ void GPUPrinting::loadStrings(slang::ProgramLayout* slangReflection)
// that appear in the linked program.
//
SlangUInt hashedStringCount = slangReflection->getHashedStringCount();
- for( SlangUInt ii = 0; ii < hashedStringCount; ++ii )
+ for (SlangUInt ii = 0; ii < hashedStringCount; ++ii)
{
// For each string we can fetch its bytes from the Slang
// reflection data.
@@ -59,7 +58,8 @@ void GPUPrinting::loadStrings(slang::ProgramLayout* slangReflection)
// The `GPUPrinting` implementation will store the mapping
// from hash codes back to strings in a simple STL `map`.
//
- m_hashedStrings.insert(std::make_pair(hash, std::string(stringData, stringData + stringSize)));
+ m_hashedStrings.insert(
+ std::make_pair(hash, std::string(stringData, stringData + stringSize)));
}
}
@@ -73,12 +73,12 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// a granularity of 32-bits words, so we start by computing
// how many words, total, will fit in the buffer.
//
- uint32_t dataWordCount = uint32_t(dataSize/ sizeof(uint32_t));
+ uint32_t dataWordCount = uint32_t(dataSize / sizeof(uint32_t));
//
// If the buffer doesn't even have enough space for the leading counter,
// then there is nothing to print.
//
- if( dataWordCount < 1 )
+ if (dataWordCount < 1)
{
fprintf(stderr, "error: expected at least 4 bytes in GPU printing buffer\n");
return;
@@ -87,7 +87,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// Otherwise, we set ourselves up to start reading data from the buffer
// at a granularity of 32-bit words.
//
- const uint32_t* dataCursor = (const uint32_t*) data;
+ const uint32_t* dataCursor = (const uint32_t*)data;
// The first word of a printing buffer gives us the total number of
// words that were appended by GPU printing operations.
@@ -106,20 +106,25 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// larger buffer.
//
size_t totalBytesWritten = sizeof(uint32_t) * (wordsAppended + 1);
- if( totalBytesWritten > dataSize )
+ if (totalBytesWritten > dataSize)
{
- fprintf(stderr, "warning: GPU code attempted to write %llu bytes to the printing buffer, but only %llu bytes were available\n", (unsigned long long)totalBytesWritten, (unsigned long long)dataSize);
+ fprintf(
+ stderr,
+ "warning: GPU code attempted to write %llu bytes to the printing buffer, but only %llu "
+ "bytes were available\n",
+ (unsigned long long)totalBytesWritten,
+ (unsigned long long)dataSize);
// If the buffer is full, then we only want to read through
// to the end of what is available.
//
- dataEnd = ((const uint32_t*) data) + dataWordCount;
+ dataEnd = ((const uint32_t*)data) + dataWordCount;
}
// We will now proceed to read off "commands" from the buffer,
// and execute those commands to print things to `stdout`.
//
- while( dataCursor < dataEnd )
+ while (dataCursor < dataEnd)
{
// The first word of each command is encoded to hold both
// an "opcode" for the command, and the number of "payload"
@@ -135,7 +140,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// avoid crashes from a command trying to fetch data past
// the end of the buffer.
//
- if( payloadWordCount > size_t(dataCursor - dataEnd) )
+ if (payloadWordCount > size_t(dataCursor - dataEnd))
{
break;
}
@@ -149,7 +154,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
dataCursor += payloadWordCount;
// What to do with a command depends a lot on which "op" was selected.
- switch( op )
+ switch (op)
{
default:
// If we encounter an op that we don't understand, there is a change
@@ -176,21 +181,21 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// We will use a macro to avoid duplication the code shared
// between these cases.
//
- #define CASE(OP, FORMAT, TYPE) \
- case GPUPrintingOp::OP: \
- { \
- TYPE value; \
- assert(payloadWordCount >= (sizeof(value) / sizeof(uint32_t))); \
- memcpy(&value, payloadWords, sizeof(value)); \
- printf(FORMAT, value); \
- } \
- break
-
- CASE(Int32, "%d", int);
- CASE(UInt32, "%u", unsigned int);
- CASE(Float32, "%f", float);
-
- #undef CASE
+#define CASE(OP, FORMAT, TYPE) \
+ case GPUPrintingOp::OP: \
+ { \
+ TYPE value; \
+ assert(payloadWordCount >= (sizeof(value) / sizeof(uint32_t))); \
+ memcpy(&value, payloadWords, sizeof(value)); \
+ printf(FORMAT, value); \
+ } \
+ break
+
+ CASE(Int32, "%d", int);
+ CASE(UInt32, "%u", unsigned int);
+ CASE(Float32, "%f", float);
+
+#undef CASE
case GPUPrintingOp::String:
{
@@ -214,7 +219,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// to appear in the GPU code.
//
auto iter = m_hashedStrings.find(hash);
- if(iter == m_hashedStrings.end())
+ if (iter == m_hashedStrings.end())
{
// If we didn't have a string to match that hash code in
// our map, we can continue trying to print, but it is
@@ -230,7 +235,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
//
// TODO: This code isn't robust against strings with
// embeded null bytes.
- //s
+ // s
printf("%s", iter->second.c_str());
}
break;
@@ -248,7 +253,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
StringHash formatHash = *payloadWords++;
auto iter = m_hashedStrings.find(formatHash);
- if(iter == m_hashedStrings.end())
+ if (iter == m_hashedStrings.end())
{
// If we didn't have a string to match that hash code in
// our map, we can continue trying to print, but it is
@@ -270,14 +275,14 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
//
const char* cursor = format.c_str();
const char* end = cursor + format.length();
- while( cursor != end )
+ while (cursor != end)
{
int c = *cursor++;
// If we see a byte other than `%`, then we can just
// output it directly and keep scanning the format string.
//
- if( c != '%' )
+ if (c != '%')
{
putchar(c);
continue;
@@ -289,7 +294,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// If we are somehow at the end of the format
// string, then the format was bad.
//
- if( cursor == end )
+ if (cursor == end)
{
fprintf(stderr, "error: unexpected '%%' at and of format string\n");
break;
@@ -299,7 +304,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// the `%` character, then it is an escaped
// `%` so we should just emit it as-is and move along.
//
- if( *cursor == '%' )
+ if (*cursor == '%')
{
putchar(*cursor++);
continue;
@@ -317,52 +322,56 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// read a single-byte specifier.
//
int specifier = *cursor++;
- switch( specifier )
+ switch (specifier)
{
default:
- fprintf(stderr, "error: unexpected format specifier '%c' (0x%X)\n", specifier, specifier);
+ fprintf(
+ stderr,
+ "error: unexpected format specifier '%c' (0x%X)\n",
+ specifier,
+ specifier);
break;
- // When processing each format speecifier, we will
- // read words from the payload, as necessary
- // to yield a value of the expected type.
- //
- // To reduce the amount of boilerplate, we will
- // use a macro to capture the shared code for
- // common cases.
- //
- #define CASE(CHAR, FORMAT, TYPE) \
- case CHAR: \
- { \
- assert(payloadWords != payloadWordsEnd); \
- TYPE value; \
- memcpy(&value, payloadWords, sizeof(value)); \
- payloadWords += sizeof(value) / sizeof(uint32_t); \
- printf(FORMAT, value); \
- } \
- break
+ // When processing each format speecifier, we will
+ // read words from the payload, as necessary
+ // to yield a value of the expected type.
+ //
+ // To reduce the amount of boilerplate, we will
+ // use a macro to capture the shared code for
+ // common cases.
+ //
+#define CASE(CHAR, FORMAT, TYPE) \
+ case CHAR: \
+ { \
+ assert(payloadWords != payloadWordsEnd); \
+ TYPE value; \
+ memcpy(&value, payloadWords, sizeof(value)); \
+ payloadWords += sizeof(value) / sizeof(uint32_t); \
+ printf(FORMAT, value); \
+ } \
+ break
case 'i': // `%i` is just an alias for `%d`
- CASE('d', "%d", int);
- CASE('u', "%u", unsigned int);
- CASE('x', "%x", unsigned int);
- CASE('X', "%X", unsigned int);
-
- // Note: all of our printing support for floating-point
- // values will use the `float` type instead of `double`.
- // This isn't compatible with C rules, but makes more sense
- // for GPU code.
- //
- CASE('f', "%f", float);
- CASE('F', "%F", float);
- CASE('e', "%e", float);
- CASE('E', "%E", float);
- CASE('g', "%g", float);
- CASE('G', "%G", float);
- CASE('c', "%c", int);
-
- #undef CASE
+ CASE('d', "%d", int);
+ CASE('u', "%u", unsigned int);
+ CASE('x', "%x", unsigned int);
+ CASE('X', "%X", unsigned int);
+
+ // Note: all of our printing support for floating-point
+ // values will use the `float` type instead of `double`.
+ // This isn't compatible with C rules, but makes more sense
+ // for GPU code.
+ //
+ CASE('f', "%f", float);
+ CASE('F', "%F", float);
+ CASE('e', "%e", float);
+ CASE('E', "%E", float);
+ CASE('g', "%g", float);
+ CASE('G', "%G", float);
+ CASE('c', "%c", int);
+
+#undef CASE
case 's':
{
@@ -373,7 +382,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
assert(payloadWords != payloadWordsEnd);
StringHash hash = *payloadWords++;
auto iter = m_hashedStrings.find(hash);
- if(iter == m_hashedStrings.end())
+ if (iter == m_hashedStrings.end())
{
fprintf(stderr, "error: string with unknown hash 0x%x\n", hash);
continue;
@@ -387,6 +396,4 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
break;
}
}
-
-
}
diff --git a/examples/gpu-printing/gpu-printing.h b/examples/gpu-printing/gpu-printing.h
index 64eaf770a..84c036548 100644
--- a/examples/gpu-printing/gpu-printing.h
+++ b/examples/gpu-printing/gpu-printing.h
@@ -19,39 +19,39 @@
#include <map>
#include <string>
- /// Stores state used for executing print commands generated by GPU shaders
+/// Stores state used for executing print commands generated by GPU shaders
struct GPUPrinting
{
public:
- /// Load any string literals used by a Slang program.
- ///
- /// The `slangReflection` should be the layout and reflection
- /// object for a Slang shader program that might need to produce
- /// printed output. This function will load any strings
- /// referenced by the program into its database for mapping
- /// string hashes back to the original strings.
- ///
+ /// Load any string literals used by a Slang program.
+ ///
+ /// The `slangReflection` should be the layout and reflection
+ /// object for a Slang shader program that might need to produce
+ /// printed output. This function will load any strings
+ /// referenced by the program into its database for mapping
+ /// string hashes back to the original strings.
+ ///
void loadStrings(slang::ProgramLayout* slangReflection);
- /// Process a buffer of GPU printing commands and write output to `stdout`.
- ///
- /// This function attempts to read print commands from the buffer
- /// pointed to by `data` and execute them to produce output.
- ///
- /// The buffer pointed at by `data` (of size `dataSize`) should be allocated
- /// in host-visible memory.
- ///
- /// Before executing GPU work, the first four bytes pointed to by `data`
- /// should have been cleared to zero.
- ///
- /// If GPU work has attempted to write more data than the buffer
- /// can fit, a warning will be printed to `stderr`, and printing commands
- /// that could not fit completely in the buffer will be skipped.
- ///
+ /// Process a buffer of GPU printing commands and write output to `stdout`.
+ ///
+ /// This function attempts to read print commands from the buffer
+ /// pointed to by `data` and execute them to produce output.
+ ///
+ /// The buffer pointed at by `data` (of size `dataSize`) should be allocated
+ /// in host-visible memory.
+ ///
+ /// Before executing GPU work, the first four bytes pointed to by `data`
+ /// should have been cleared to zero.
+ ///
+ /// If GPU work has attempted to write more data than the buffer
+ /// can fit, a warning will be printed to `stderr`, and printing commands
+ /// that could not fit completely in the buffer will be skipped.
+ ///
void processGPUPrintCommands(const void* data, size_t dataSize);
private:
typedef int StringHash;
- std::map<StringHash, std::string> m_hashedStrings;
+ std::map<StringHash, std::string> m_hashedStrings;
};
diff --git a/examples/gpu-printing/main.cpp b/examples/gpu-printing/main.cpp
index fd15661dd..fa9f919dc 100644
--- a/examples/gpu-printing/main.cpp
+++ b/examples/gpu-printing/main.cpp
@@ -1,17 +1,16 @@
// main.cpp
-#include <string>
-
+#include "slang-com-ptr.h"
#include "slang.h"
-#include "slang-com-ptr.h"
+#include <string>
using Slang::ComPtr;
+#include "examples/example-base/example-base.h"
+#include "gfx-util/shader-cursor.h"
#include "gpu-printing.h"
#include "slang-gfx.h"
-#include "gfx-util/shader-cursor.h"
-#include "tools/platform/window.h"
#include "source/core/slang-basic.h"
-#include "examples/example-base/example-base.h"
+#include "tools/platform/window.h"
using namespace gfx;
@@ -23,7 +22,9 @@ ComPtr<slang::ISession> createSlangSession(gfx::IDevice* device)
return slangSession;
}
-ComPtr<slang::IModule> compileShaderModuleFromFile(slang::ISession* slangSession, char const* filePath)
+ComPtr<slang::IModule> compileShaderModuleFromFile(
+ slang::ISession* slangSession,
+ char const* filePath)
{
ComPtr<slang::IModule> slangModule;
ComPtr<slang::IBlob> diagnosticBlob;
@@ -34,113 +35,121 @@ ComPtr<slang::IModule> compileShaderModuleFromFile(slang::ISession* slangSession
return slangModule;
}
-struct ExampleProgram: public TestBase
+struct ExampleProgram : public TestBase
{
-int gWindowWidth = 640;
-int gWindowHeight = 480;
+ int gWindowWidth = 640;
+ int gWindowHeight = 480;
-ComPtr<gfx::IDevice> gDevice;
+ ComPtr<gfx::IDevice> gDevice;
-ComPtr<slang::ISession> gSlangSession;
-ComPtr<slang::IModule> gSlangModule;
-ComPtr<gfx::IShaderProgram> gProgram;
+ ComPtr<slang::ISession> gSlangSession;
+ ComPtr<slang::IModule> gSlangModule;
+ ComPtr<gfx::IShaderProgram> gProgram;
-ComPtr<gfx::IPipelineState> gPipelineState;
+ ComPtr<gfx::IPipelineState> gPipelineState;
-Slang::Dictionary<int, std::string> gHashedStrings;
+ Slang::Dictionary<int, std::string> gHashedStrings;
-GPUPrinting gGPUPrinting;
+ GPUPrinting gGPUPrinting;
-ComPtr<gfx::IShaderProgram> loadComputeProgram(slang::IModule* slangModule, char const* entryPointName)
-{
- ComPtr<slang::IEntryPoint> entryPoint;
- slangModule->findEntryPointByName(entryPointName, entryPoint.writeRef());
-
- ComPtr<slang::IComponentType> linkedProgram;
- entryPoint->link(linkedProgram.writeRef());
-
- if (isTestMode())
+ ComPtr<gfx::IShaderProgram> loadComputeProgram(
+ slang::IModule* slangModule,
+ char const* entryPointName)
{
- printEntrypointHashes(1, 1, linkedProgram);
- }
+ ComPtr<slang::IEntryPoint> entryPoint;
+ slangModule->findEntryPointByName(entryPointName, entryPoint.writeRef());
- gGPUPrinting.loadStrings(linkedProgram->getLayout());
+ ComPtr<slang::IComponentType> linkedProgram;
+ entryPoint->link(linkedProgram.writeRef());
- gfx::IShaderProgram::Desc programDesc = {};
- programDesc.slangGlobalScope = linkedProgram;
+ if (isTestMode())
+ {
+ printEntrypointHashes(1, 1, linkedProgram);
+ }
- auto shaderProgram = gDevice->createProgram(programDesc);
+ gGPUPrinting.loadStrings(linkedProgram->getLayout());
- return shaderProgram;
-}
+ gfx::IShaderProgram::Desc programDesc = {};
+ programDesc.slangGlobalScope = linkedProgram;
-Result execute(int argc, char* argv[])
-{
- parseOption(argc, argv);
- IDevice::Desc deviceDesc;
- Result res = gfxCreateDevice(&deviceDesc, gDevice.writeRef());
- if(SLANG_FAILED(res)) return res;
-
- Slang::String path = resourceBase.resolveResource("kernels.slang");
-
- gSlangSession = createSlangSession(gDevice);
- gSlangModule = compileShaderModuleFromFile(gSlangSession, path.getBuffer());
- if(!gSlangModule)
- return SLANG_FAIL;
-
- gProgram = loadComputeProgram(gSlangModule, "computeMain");
- if(!gProgram)
- return SLANG_FAIL;
-
- ComputePipelineStateDesc desc;
- desc.program = gProgram;
- auto pipelineState = gDevice->createComputePipelineState(desc);
- if(!pipelineState) return SLANG_FAIL;
-
- gPipelineState = pipelineState;
-
- size_t printBufferSize = 4 * 1024; // use a small-ish (4KB) buffer for print output
-
- IBufferResource::Desc printBufferDesc = {};
- printBufferDesc.type = IResource::Type::Buffer;
- printBufferDesc.sizeInBytes = printBufferSize;
- printBufferDesc.elementSize = sizeof(uint32_t);
- printBufferDesc.defaultState = ResourceState::UnorderedAccess;
- printBufferDesc.allowedStates = ResourceStateSet(
- ResourceState::CopySource, ResourceState::CopyDestination, ResourceState::UnorderedAccess);
- printBufferDesc.memoryType = MemoryType::DeviceLocal;
- auto printBuffer = gDevice->createBufferResource(printBufferDesc);
-
- IResourceView::Desc printBufferViewDesc = {};
- printBufferViewDesc.type = IResourceView::Type::UnorderedAccess;
- printBufferViewDesc.format = Format::Unknown;
- auto printBufferView = gDevice->createBufferView(printBuffer, nullptr, printBufferViewDesc);
-
- ITransientResourceHeap::Desc transientResourceHeapDesc = {};
- transientResourceHeapDesc.constantBufferSize = 256;
- auto transientHeap = gDevice->createTransientResourceHeap(transientResourceHeapDesc);
-
- ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics};
- auto queue = gDevice->createCommandQueue(queueDesc);
- auto commandBuffer = transientHeap->createCommandBuffer();
- auto encoder = commandBuffer->encodeComputeCommands();
- auto rootShaderObject = encoder->bindPipeline(gPipelineState);
- auto cursor = ShaderCursor(rootShaderObject);
- cursor["gPrintBuffer"].setResource(printBufferView);
- encoder->dispatchCompute(1, 1, 1);
- encoder->bufferBarrier(printBuffer, ResourceState::UnorderedAccess, ResourceState::CopySource);
- encoder->endEncoding();
- commandBuffer->close();
- queue->executeCommandBuffer(commandBuffer);
-
- ComPtr<ISlangBlob> blob;
- gDevice->readBufferResource(printBuffer, 0, printBufferSize, blob.writeRef());
-
- gGPUPrinting.processGPUPrintCommands(blob->getBufferPointer(), printBufferSize);
-
- return SLANG_OK;
-}
+ auto shaderProgram = gDevice->createProgram(programDesc);
+
+ return shaderProgram;
+ }
+ Result execute(int argc, char* argv[])
+ {
+ parseOption(argc, argv);
+ IDevice::Desc deviceDesc;
+ Result res = gfxCreateDevice(&deviceDesc, gDevice.writeRef());
+ if (SLANG_FAILED(res))
+ return res;
+
+ Slang::String path = resourceBase.resolveResource("kernels.slang");
+
+ gSlangSession = createSlangSession(gDevice);
+ gSlangModule = compileShaderModuleFromFile(gSlangSession, path.getBuffer());
+ if (!gSlangModule)
+ return SLANG_FAIL;
+
+ gProgram = loadComputeProgram(gSlangModule, "computeMain");
+ if (!gProgram)
+ return SLANG_FAIL;
+
+ ComputePipelineStateDesc desc;
+ desc.program = gProgram;
+ auto pipelineState = gDevice->createComputePipelineState(desc);
+ if (!pipelineState)
+ return SLANG_FAIL;
+
+ gPipelineState = pipelineState;
+
+ size_t printBufferSize = 4 * 1024; // use a small-ish (4KB) buffer for print output
+
+ IBufferResource::Desc printBufferDesc = {};
+ printBufferDesc.type = IResource::Type::Buffer;
+ printBufferDesc.sizeInBytes = printBufferSize;
+ printBufferDesc.elementSize = sizeof(uint32_t);
+ printBufferDesc.defaultState = ResourceState::UnorderedAccess;
+ printBufferDesc.allowedStates = ResourceStateSet(
+ ResourceState::CopySource,
+ ResourceState::CopyDestination,
+ ResourceState::UnorderedAccess);
+ printBufferDesc.memoryType = MemoryType::DeviceLocal;
+ auto printBuffer = gDevice->createBufferResource(printBufferDesc);
+
+ IResourceView::Desc printBufferViewDesc = {};
+ printBufferViewDesc.type = IResourceView::Type::UnorderedAccess;
+ printBufferViewDesc.format = Format::Unknown;
+ auto printBufferView = gDevice->createBufferView(printBuffer, nullptr, printBufferViewDesc);
+
+ ITransientResourceHeap::Desc transientResourceHeapDesc = {};
+ transientResourceHeapDesc.constantBufferSize = 256;
+ auto transientHeap = gDevice->createTransientResourceHeap(transientResourceHeapDesc);
+
+ ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics};
+ auto queue = gDevice->createCommandQueue(queueDesc);
+ auto commandBuffer = transientHeap->createCommandBuffer();
+ auto encoder = commandBuffer->encodeComputeCommands();
+ auto rootShaderObject = encoder->bindPipeline(gPipelineState);
+ auto cursor = ShaderCursor(rootShaderObject);
+ cursor["gPrintBuffer"].setResource(printBufferView);
+ encoder->dispatchCompute(1, 1, 1);
+ encoder->bufferBarrier(
+ printBuffer,
+ ResourceState::UnorderedAccess,
+ ResourceState::CopySource);
+ encoder->endEncoding();
+ commandBuffer->close();
+ queue->executeCommandBuffer(commandBuffer);
+
+ ComPtr<ISlangBlob> blob;
+ gDevice->readBufferResource(printBuffer, 0, printBufferSize, blob.writeRef());
+
+ gGPUPrinting.processGPUPrintCommands(blob->getBufferPointer(), printBufferSize);
+
+ return SLANG_OK;
+ }
};
int main(int argc, char* argv[])
diff --git a/examples/hello-world/main.cpp b/examples/hello-world/main.cpp
index 87d440901..e9585bde9 100644
--- a/examples/hello-world/main.cpp
+++ b/examples/hello-world/main.cpp
@@ -7,13 +7,12 @@
// The goal is to demonstrate how to use the Slang API to cross compile
// shader code.
//
-#include "slang.h"
-#include "slang-com-ptr.h"
-
-#include "vulkan-api.h"
#include "examples/example-base/example-base.h"
#include "examples/example-base/test-base.h"
+#include "slang-com-ptr.h"
+#include "slang.h"
#include "source/core/slang-string-util.h"
+#include "vulkan-api.h"
using Slang::ComPtr;
@@ -65,7 +64,6 @@ struct HelloWorldExample : public TestBase
int run();
~HelloWorldExample();
-
};
int main(int argc, char* argv[])
@@ -102,8 +100,7 @@ int HelloWorldExample::initVulkanInstanceAndDevice()
poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolCreateInfo.queueFamilyIndex = vkAPI.queueFamilyIndex;
- RETURN_ON_FAIL(vkAPI.vkCreateCommandPool(
- vkAPI.device, &poolCreateInfo, nullptr, &commandPool));
+ RETURN_ON_FAIL(vkAPI.vkCreateCommandPool(vkAPI.device, &poolCreateInfo, nullptr, &commandPool));
vkAPI.vkGetDeviceQueue(vkAPI.device, vkAPI.queueFamilyIndex, 0, &queue);
return 0;
@@ -204,7 +201,10 @@ int HelloWorldExample::createComputePipelineFromShader()
{
ComPtr<slang::IBlob> diagnosticsBlob;
SlangResult result = composedProgram->getEntryPointCode(
- 0, 0, spirvCode.writeRef(), diagnosticsBlob.writeRef());
+ 0,
+ 0,
+ spirvCode.writeRef(),
+ diagnosticsBlob.writeRef());
diagnoseIfNeeded(diagnosticsBlob);
RETURN_ON_FAIL(result);
@@ -238,13 +238,19 @@ int HelloWorldExample::createComputePipelineFromShader()
}
descSetLayoutCreateInfo.pBindings = bindings;
RETURN_ON_FAIL(vkAPI.vkCreateDescriptorSetLayout(
- vkAPI.device, &descSetLayoutCreateInfo, nullptr, &descriptorSetLayout));
+ vkAPI.device,
+ &descSetLayoutCreateInfo,
+ nullptr,
+ &descriptorSetLayout));
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
pipelineLayoutCreateInfo.setLayoutCount = 1;
pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout;
RETURN_ON_FAIL(vkAPI.vkCreatePipelineLayout(
- vkAPI.device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
+ vkAPI.device,
+ &pipelineLayoutCreateInfo,
+ nullptr,
+ &pipelineLayout));
// Next we create a shader module from the compiled SPIRV code.
VkShaderModuleCreateInfo shaderCreateInfo = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
@@ -263,7 +269,12 @@ int HelloWorldExample::createComputePipelineFromShader()
pipelineCreateInfo.stage.pName = "main";
pipelineCreateInfo.layout = pipelineLayout;
RETURN_ON_FAIL(vkAPI.vkCreateComputePipelines(
- vkAPI.device, VK_NULL_HANDLE, 1, &pipelineCreateInfo, nullptr, &pipeline));
+ vkAPI.device,
+ VK_NULL_HANDLE,
+ 1,
+ &pipelineCreateInfo,
+ nullptr,
+ &pipeline));
// We can destroy shader module now since it will no longer be used.
vkAPI.vkDestroyShaderModule(vkAPI.device, vkShaderModule, nullptr);
@@ -287,7 +298,8 @@ int HelloWorldExample::createInOutBuffers()
vkAPI.vkGetBufferMemoryRequirements(vkAPI.device, inOutBuffers[i], &memoryReqs);
int memoryTypeIndex = vkAPI.findMemoryTypeIndex(
- memoryReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ memoryReqs.memoryTypeBits,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
assert(memoryTypeIndex >= 0);
VkMemoryPropertyFlags actualMemoryProperites =
@@ -347,7 +359,10 @@ int HelloWorldExample::createInOutBuffers()
commandBufferAllocInfo.commandBufferCount = 1;
commandBufferAllocInfo.commandPool = commandPool;
commandBufferAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- RETURN_ON_FAIL(vkAPI.vkAllocateCommandBuffers(vkAPI.device, &commandBufferAllocInfo, &uploadCommandBuffer));
+ RETURN_ON_FAIL(vkAPI.vkAllocateCommandBuffers(
+ vkAPI.device,
+ &commandBufferAllocInfo,
+ &uploadCommandBuffer));
VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
vkAPI.vkBeginCommandBuffer(uploadCommandBuffer, &beginInfo);
@@ -378,7 +393,10 @@ int HelloWorldExample::dispatchCompute()
descriptorPoolCreateInfo.flags = 0;
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
RETURN_ON_FAIL(vkAPI.vkCreateDescriptorPool(
- vkAPI.device, &descriptorPoolCreateInfo, nullptr, &descriptorPool));
+ vkAPI.device,
+ &descriptorPoolCreateInfo,
+ nullptr,
+ &descriptorPool));
// Allocate descriptor set.
VkDescriptorSetAllocateInfo descSetAllocInfo = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
diff --git a/examples/hello-world/vulkan-api.cpp b/examples/hello-world/vulkan-api.cpp
index 3581563d4..95c4a512e 100644
--- a/examples/hello-world/vulkan-api.cpp
+++ b/examples/hello-world/vulkan-api.cpp
@@ -1,16 +1,17 @@
#include "vulkan-api.h"
+
#include "slang.h"
-#include <stdlib.h>
-#include <stdio.h>
#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <vector>
#if SLANG_WINDOWS_FAMILY
-# include <windows.h>
+#include <windows.h>
#else
-# include <dlfcn.h>
+#include <dlfcn.h>
#endif
#if _DEBUG
@@ -25,7 +26,8 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(
int32_t /*msgCode*/,
const char* pLayerPrefix,
const char* pMsg,
- void* /*pUserData*/)
+ void* /*pUserData*/
+)
{
printf("[%s]: %s\n", pLayerPrefix, pMsg);
return 1;
@@ -62,7 +64,7 @@ int initializeVulkanDevice(VulkanAPI& api)
uint32_t propertyCount;
if (api.vkEnumerateInstanceLayerProperties(&propertyCount, nullptr) != 0)
return -1;
- std::vector< VkLayerProperties> properties(propertyCount);
+ std::vector<VkLayerProperties> properties(propertyCount);
if (api.vkEnumerateInstanceLayerProperties(&propertyCount, properties.data()) != 0)
return -1;
for (const auto& p : properties)
@@ -119,17 +121,19 @@ int initializeVulkanDevice(VulkanAPI& api)
debugCreateInfo.flags = debugFlags;
RETURN_ON_FAIL(api.vkCreateDebugReportCallbackEXT(
- api.instance, &debugCreateInfo, nullptr, &api.debugReportCallback));
+ api.instance,
+ &debugCreateInfo,
+ nullptr,
+ &api.debugReportCallback));
}
// Enumerate physical devices.
uint32_t numPhysicalDevices = 0;
- RETURN_ON_FAIL(
- api.vkEnumeratePhysicalDevices(api.instance, &numPhysicalDevices, nullptr));
+ RETURN_ON_FAIL(api.vkEnumeratePhysicalDevices(api.instance, &numPhysicalDevices, nullptr));
std::vector<VkPhysicalDevice> physicalDevices;
physicalDevices.resize(numPhysicalDevices);
- RETURN_ON_FAIL(api.vkEnumeratePhysicalDevices(
- api.instance, &numPhysicalDevices, &physicalDevices[0]));
+ RETURN_ON_FAIL(
+ api.vkEnumeratePhysicalDevices(api.instance, &numPhysicalDevices, &physicalDevices[0]));
// We will use device 0.
api.initPhysicalDevice(physicalDevices[0]);
@@ -145,7 +149,9 @@ int initializeVulkanDevice(VulkanAPI& api)
std::vector<VkQueueFamilyProperties> queueFamilies;
queueFamilies.resize(numQueueFamilies);
api.vkGetPhysicalDeviceQueueFamilyProperties(
- api.physicalDevice, &numQueueFamilies, &queueFamilies[0]);
+ api.physicalDevice,
+ &numQueueFamilies,
+ &queueFamilies[0]);
// Find a queue that can service our needs.
auto requiredQueueFlags = VK_QUEUE_COMPUTE_BIT;
diff --git a/examples/hello-world/vulkan-api.h b/examples/hello-world/vulkan-api.h
index 89ca9747d..ab0822569 100644
--- a/examples/hello-world/vulkan-api.h
+++ b/examples/hello-world/vulkan-api.h
@@ -121,12 +121,12 @@ struct VulkanAPI
};
#define RETURN_ON_FAIL(x) \
- { \
- auto _res = x; \
- if (_res != 0) \
- { \
- return -1; \
- } \
+ { \
+ auto _res = x; \
+ if (_res != 0) \
+ { \
+ return -1; \
+ } \
}
// Loads Vulkan library and creates a VkDevice.
diff --git a/examples/model-viewer/main.cpp b/examples/model-viewer/main.cpp
index 7ca5eeb74..7faaf5569 100644
--- a/examples/model-viewer/main.cpp
+++ b/examples/model-viewer/main.cpp
@@ -16,21 +16,21 @@
// We still need to include the Slang header to use the Slang API
//
-#include "slang.h"
#include "slang-com-helper.h"
+#include "slang.h"
// We will again make use of a graphics API abstraction
// layer that implements the shader-object idiom based on Slang's
// `ParameterBlock` and `interface` features to simplify shader specialization
// and parameter binding.
//
+#include "examples/example-base/example-base.h"
#include "slang-gfx.h"
#include "tools/gfx-util/shader-cursor.h"
+#include "tools/platform/gui.h"
#include "tools/platform/model.h"
#include "tools/platform/vector-math.h"
#include "tools/platform/window.h"
-#include "tools/platform/gui.h"
-#include "examples/example-base/example-base.h"
#include <map>
#include <sstream>
@@ -51,7 +51,7 @@ struct RendererContext
slang::TypeReflection* perViewShaderType;
slang::TypeReflection* perModelShaderType;
- TestBase *pTestBase;
+ TestBase* pTestBase;
Result init(IDevice* inDevice, TestBase* inTestBase)
{
@@ -60,9 +60,8 @@ struct RendererContext
pTestBase = inTestBase;
Slang::String path = resourceBase.resolveResource("shaders.slang").getBuffer();
- shaderModule = device->getSlangSession()->loadModule(
- path.getBuffer(),
- diagnostic.writeRef());
+ shaderModule =
+ device->getSlangSession()->loadModule(path.getBuffer(), diagnostic.writeRef());
diagnoseIfNeeded(diagnostic);
if (!shaderModule)
return SLANG_FAIL;
@@ -165,9 +164,9 @@ struct Material : RefObject
//
struct SimpleMaterial : Material
{
- glm::vec3 diffuseColor;
- glm::vec3 specularColor;
- float specularity = 1.0f;
+ glm::vec3 diffuseColor;
+ glm::vec3 specularColor;
+ float specularity = 1.0f;
// Create a shader object that contains the type info and parameter values
// that represent an instance of `SimpleMaterial`.
@@ -194,20 +193,20 @@ struct SimpleMaterial : Material
//
struct Mesh : RefObject
{
- RefPtr<Material> material;
- int firstIndex;
- int indexCount;
+ RefPtr<Material> material;
+ int firstIndex;
+ int indexCount;
};
struct Model : RefObject
{
typedef platform::ModelLoader::Vertex Vertex;
- ComPtr<IBufferResource> vertexBuffer;
- ComPtr<IBufferResource> indexBuffer;
- PrimitiveTopology primitiveTopology;
- int vertexCount;
- int indexCount;
- std::vector<RefPtr<Mesh>> meshes;
+ ComPtr<IBufferResource> vertexBuffer;
+ ComPtr<IBufferResource> indexBuffer;
+ PrimitiveTopology primitiveTopology;
+ int vertexCount;
+ int indexCount;
+ std::vector<RefPtr<Mesh>> meshes;
};
//
// Loading a model from disk is done with the help of some utility
@@ -216,10 +215,10 @@ struct Model : RefObject
// used for its representation.
//
RefPtr<Model> loadModel(
- RendererContext* context,
- char const* inputPath,
+ RendererContext* context,
+ char const* inputPath,
platform::ModelLoader::LoadFlags loadFlags = 0,
- float scale = 1.0f)
+ float scale = 1.0f)
{
// The model loading interface using a C++ interface of
// callback functions to handle creating the application-specific
@@ -308,7 +307,7 @@ struct Light : RefObject
// The shader object for a light will be stashed here
// after it is created.
-// ComPtr<IShaderObject> shaderObject;
+ // ComPtr<IShaderObject> shaderObject;
};
// Helper function to retrieve the underlying shader type of `T`.
@@ -411,8 +410,7 @@ struct LightEnvLayout : public RefObject
{
auto program = context->slangReflection;
std::stringstream typeNameBuilder;
- typeNameBuilder << "LightArray<" << lightType->getName() << "," << maximumCount
- << ">";
+ typeNameBuilder << "LightArray<" << lightType->getName() << "," << maximumCount << ">";
layout.typeName = typeNameBuilder.str();
}
@@ -420,7 +418,8 @@ struct LightEnvLayout : public RefObject
mapLightTypeToArrayIndex.insert(std::make_pair(lightType, arrayIndex));
}
- template<typename T> void addLightType(RendererContext* context, Int maximumCount)
+ template<typename T>
+ void addLightType(RendererContext* context, Int maximumCount)
{
addLightType(context, getShaderType<T>(context), maximumCount);
}
@@ -459,8 +458,7 @@ struct LightEnv : public RefObject
RefPtr<LightEnvLayout> layout;
RendererContext* context;
LightEnv(RefPtr<LightEnvLayout> layout, RendererContext* inContext)
- : layout(layout)
- , context(inContext)
+ : layout(layout), context(inContext)
{
for (auto arrayLayout : layout->lightArrayLayouts)
{
@@ -640,329 +638,324 @@ struct LightEnv : public RefObject
//
struct ModelViewer : WindowedAppBase
{
-RendererContext context;
+ RendererContext context;
-// Most of the application state is stored in the list of loaded models,
-// as well as the active light source (a single light for now).
-//
-std::vector<RefPtr<Model>> gModels;
-RefPtr<LightEnv> lightEnv;
+ // Most of the application state is stored in the list of loaded models,
+ // as well as the active light source (a single light for now).
+ //
+ std::vector<RefPtr<Model>> gModels;
+ RefPtr<LightEnv> lightEnv;
-// The pipeline state object we will use to draw models.
-ComPtr<IPipelineState> gPipelineState;
+ // The pipeline state object we will use to draw models.
+ ComPtr<IPipelineState> gPipelineState;
-// During startup the application will load one or more models and
-// add them to the `gModels` list.
-//
-void loadAndAddModel(
- char const* inputPath,
- platform::ModelLoader::LoadFlags loadFlags = 0,
- float scale = 1.0f)
-{
- auto model = loadModel(&context, inputPath, loadFlags, scale);
- if(!model) return;
- gModels.push_back(model);
-}
+ // During startup the application will load one or more models and
+ // add them to the `gModels` list.
+ //
+ void loadAndAddModel(
+ char const* inputPath,
+ platform::ModelLoader::LoadFlags loadFlags = 0,
+ float scale = 1.0f)
+ {
+ auto model = loadModel(&context, inputPath, loadFlags, scale);
+ if (!model)
+ return;
+ gModels.push_back(model);
+ }
-// Our "simulation" state consists of just a few values.
-//
-uint64_t lastTime = 0;
+ // Our "simulation" state consists of just a few values.
+ //
+ uint64_t lastTime = 0;
-//glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10));
-//glm::vec3 lightColor = glm::vec3(1, 1, 1);
+ // glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10));
+ // glm::vec3 lightColor = glm::vec3(1, 1, 1);
-glm::vec3 cameraPosition = glm::vec3(1.75, 1.25, 5);
-glm::quat cameraOrientation = glm::quat(1, glm::vec3(0));
+ glm::vec3 cameraPosition = glm::vec3(1.75, 1.25, 5);
+ glm::quat cameraOrientation = glm::quat(1, glm::vec3(0));
-float translationScale = 0.5f;
-float rotationScale = 0.025f;
+ float translationScale = 0.5f;
+ float rotationScale = 0.025f;
-// In order to control camera movement, we will
-// use good old WASD
-bool wPressed = false;
-bool aPressed = false;
-bool sPressed = false;
-bool dPressed = false;
+ // In order to control camera movement, we will
+ // use good old WASD
+ bool wPressed = false;
+ bool aPressed = false;
+ bool sPressed = false;
+ bool dPressed = false;
-bool isMouseDown = false;
-float lastMouseX = 0.0f;
-float lastMouseY = 0.0f;
+ bool isMouseDown = false;
+ float lastMouseX = 0.0f;
+ float lastMouseY = 0.0f;
-void setKeyState(platform::KeyCode key, bool state)
-{
- switch (key)
+ void setKeyState(platform::KeyCode key, bool state)
{
- default:
- break;
- case platform::KeyCode::W:
- wPressed = state;
- break;
- case platform::KeyCode::A:
- aPressed = state;
- break;
- case platform::KeyCode::S:
- sPressed = state;
- break;
- case platform::KeyCode::D:
- dPressed = state;
- break;
+ switch (key)
+ {
+ default: break;
+ case platform::KeyCode::W: wPressed = state; break;
+ case platform::KeyCode::A: aPressed = state; break;
+ case platform::KeyCode::S: sPressed = state; break;
+ case platform::KeyCode::D: dPressed = state; break;
+ }
}
-}
-void onKeyDown(platform::KeyEventArgs args) { setKeyState(args.key, true); }
-void onKeyUp(platform::KeyEventArgs args) { setKeyState(args.key, false); }
+ void onKeyDown(platform::KeyEventArgs args) { setKeyState(args.key, true); }
+ void onKeyUp(platform::KeyEventArgs args) { setKeyState(args.key, false); }
-void onMouseDown(platform::MouseEventArgs args)
-{
- isMouseDown = true;
- lastMouseX = (float)args.x;
- lastMouseY = (float)args.y;
-}
-
-void onMouseMove(platform::MouseEventArgs args)
-{
- if (isMouseDown)
+ void onMouseDown(platform::MouseEventArgs args)
{
- float deltaX = args.x - lastMouseX;
- float deltaY = args.y - lastMouseY;
-
- cameraOrientation =
- glm::rotate(cameraOrientation, -deltaX * rotationScale, glm::vec3(0, 1, 0));
- cameraOrientation =
- glm::rotate(cameraOrientation, -deltaY * rotationScale, glm::vec3(1, 0, 0));
-
- cameraOrientation = normalize(cameraOrientation);
-
+ isMouseDown = true;
lastMouseX = (float)args.x;
lastMouseY = (float)args.y;
}
-}
-void onMouseUp(platform::MouseEventArgs args)
-{
- isMouseDown = false;
-}
-// The overall initialization logic is quite similar to
-// the earlier example. The biggest difference is that we
-// create instances of our application-specific parameter
-// block layout and effect types instead of just creating
-// raw graphics API objects.
-//
-Result initialize()
-{
- initializeBase("Model Viewer", 1024, 768);
- if (!isTestMode())
+ void onMouseMove(platform::MouseEventArgs args)
{
- gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { onMouseMove(e); };
- gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); };
- gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { onMouseDown(e); };
- gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); };
- gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); };
- }
+ if (isMouseDown)
+ {
+ float deltaX = args.x - lastMouseX;
+ float deltaY = args.y - lastMouseY;
- // Initialize `RendererContext`, which loads the shader module from file.
- SLANG_RETURN_ON_FAIL(context.init(gDevice, this));
+ cameraOrientation =
+ glm::rotate(cameraOrientation, -deltaX * rotationScale, glm::vec3(0, 1, 0));
+ cameraOrientation =
+ glm::rotate(cameraOrientation, -deltaY * rotationScale, glm::vec3(1, 0, 0));
+ cameraOrientation = normalize(cameraOrientation);
- InputElementDesc inputElements[] = {
- {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Model::Vertex, position) },
- {"NORMAL", 0, Format::R32G32B32_FLOAT, offsetof(Model::Vertex, normal) },
- {"UV", 0, Format::R32G32_FLOAT, offsetof(Model::Vertex, uv) },
- };
- auto inputLayout = gDevice->createInputLayout(
- sizeof(Model::Vertex),
- &inputElements[0],
- 3);
- if(!inputLayout) return SLANG_FAIL;
-
- // Create the pipeline state object for drawing models.
- GraphicsPipelineStateDesc pipelineStateDesc = {};
- pipelineStateDesc.program = context.shaderProgram;
- pipelineStateDesc.framebufferLayout = gFramebufferLayout;
- pipelineStateDesc.inputLayout = inputLayout;
- pipelineStateDesc.primitiveType = PrimitiveType::Triangle;
- pipelineStateDesc.depthStencil.depthFunc = ComparisonFunc::LessEqual;
- pipelineStateDesc.depthStencil.depthTestEnable = true;
- gPipelineState = gDevice->createGraphicsPipelineState(pipelineStateDesc);
-
- // We will create a lighting environment layout that can hold a few point
- // and directional lights, and then initialize a lighting environment
- // with just a single point light.
+ lastMouseX = (float)args.x;
+ lastMouseY = (float)args.y;
+ }
+ }
+ void onMouseUp(platform::MouseEventArgs args) { isMouseDown = false; }
+
+ // The overall initialization logic is quite similar to
+ // the earlier example. The biggest difference is that we
+ // create instances of our application-specific parameter
+ // block layout and effect types instead of just creating
+ // raw graphics API objects.
//
- RefPtr<LightEnvLayout> lightEnvLayout = new LightEnvLayout();
- lightEnvLayout->addLightType<PointLight>(&context, 10);
- lightEnvLayout->addLightType<DirectionalLight>(&context, 2);
+ Result initialize()
+ {
+ initializeBase("Model Viewer", 1024, 768);
+ if (!isTestMode())
+ {
+ gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e)
+ { onMouseMove(e); };
+ gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); };
+ gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e)
+ { onMouseDown(e); };
+ gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); };
+ gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); };
+ }
- lightEnv = new LightEnv(lightEnvLayout, &context);
+ // Initialize `RendererContext`, which loads the shader module from file.
+ SLANG_RETURN_ON_FAIL(context.init(gDevice, this));
- RefPtr<PointLight> pointLight = new PointLight();
- pointLight->position = glm::vec3(5, 3, 1);
- pointLight->intensity = glm::vec3(10);
- lightEnv->add(pointLight);
- // Once we have created all our graphcis API and application resources,
- // we can start to load models. For now we are keeping things extremely
- // simple by using a trivial `.obj` file that can be checked into source
- // control.
- //
- // Support for loading more interesting/complex models will be added
- // to this example over time (although model loading is *not* the focus).
- //
- Slang::String path = resourceBase.resolveResource("cube.obj").getBuffer();
- loadAndAddModel(path.getBuffer());
+ InputElementDesc inputElements[] = {
+ {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Model::Vertex, position)},
+ {"NORMAL", 0, Format::R32G32B32_FLOAT, offsetof(Model::Vertex, normal)},
+ {"UV", 0, Format::R32G32_FLOAT, offsetof(Model::Vertex, uv)},
+ };
+ auto inputLayout = gDevice->createInputLayout(sizeof(Model::Vertex), &inputElements[0], 3);
+ if (!inputLayout)
+ return SLANG_FAIL;
- return SLANG_OK;
-}
+ // Create the pipeline state object for drawing models.
+ GraphicsPipelineStateDesc pipelineStateDesc = {};
+ pipelineStateDesc.program = context.shaderProgram;
+ pipelineStateDesc.framebufferLayout = gFramebufferLayout;
+ pipelineStateDesc.inputLayout = inputLayout;
+ pipelineStateDesc.primitiveType = PrimitiveType::Triangle;
+ pipelineStateDesc.depthStencil.depthFunc = ComparisonFunc::LessEqual;
+ pipelineStateDesc.depthStencil.depthTestEnable = true;
+ gPipelineState = gDevice->createGraphicsPipelineState(pipelineStateDesc);
+
+ // We will create a lighting environment layout that can hold a few point
+ // and directional lights, and then initialize a lighting environment
+ // with just a single point light.
+ //
+ RefPtr<LightEnvLayout> lightEnvLayout = new LightEnvLayout();
+ lightEnvLayout->addLightType<PointLight>(&context, 10);
+ lightEnvLayout->addLightType<DirectionalLight>(&context, 2);
-// With the setup work done, we can look at the per-frame rendering
-// logic to see how the application will drive the `RenderContext`
-// type to perform both shader parameter binding and code specialization.
-//
-void renderFrame(int frameIndex) override
-{
- // In order to see that things are rendering properly we need some
- // kind of animation, so we will compute a crude delta-time value here.
- //
- if(!lastTime) lastTime = getCurrentTime();
- uint64_t currentTime = getCurrentTime();
- float deltaTime = float(double(currentTime - lastTime) / double(getTimerFrequency()));
- lastTime = currentTime;
+ lightEnv = new LightEnv(lightEnvLayout, &context);
- // We will use the GLM library to do the matrix math required
- // to set up our various transformation matrices.
- //
- glm::mat4x4 identity = glm::mat4x4(1.0f);
+ RefPtr<PointLight> pointLight = new PointLight();
+ pointLight->position = glm::vec3(5, 3, 1);
+ pointLight->intensity = glm::vec3(10);
+ lightEnv->add(pointLight);
- platform::Rect clientRect{};
- if (isTestMode())
- {
- clientRect.width = 1024;
- clientRect.height = 768;
- }
- else
- {
- clientRect = getWindow()->getClientRect();
- }
- if (clientRect.height == 0)
- return;
- glm::mat4x4 projection = glm::perspectiveRH_ZO(
- glm::radians(60.0f), float(clientRect.width) / float(clientRect.height),
- 0.1f,
- 1000.0f);
-
- // We are implementing a *very* basic 6DOF first-person
- // camera movement model.
- //
- glm::mat3x3 cameraOrientationMat(cameraOrientation);
- glm::vec3 forward = -cameraOrientationMat[2];
- glm::vec3 right = cameraOrientationMat[0];
-
- glm::vec3 movement = glm::vec3(0);
- if(wPressed) movement += forward;
- if(sPressed) movement -= forward;
- if(aPressed) movement -= right;
- if(dPressed) movement += right;
-
- cameraPosition += deltaTime * translationScale * movement;
-
- glm::mat4x4 view = identity;
- view *= glm::mat4x4(inverse(cameraOrientation));
- view = glm::translate(view, -cameraPosition);
-
- glm::mat4x4 viewProjection = projection * view;
- auto deviceInfo = gDevice->getDeviceInfo();
- glm::mat4x4 correctionMatrix;
- memcpy(&correctionMatrix, deviceInfo.identityProjectionMatrix, sizeof(float)*16);
- viewProjection = correctionMatrix * viewProjection;
- // glm uses column-major layout, we need to translate it to row-major.
- viewProjection = glm::transpose(viewProjection);
-
- auto drawCommandBuffer = gTransientHeaps[frameIndex]->createCommandBuffer();
- auto drawCommandEncoder =
- drawCommandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameIndex]);
- gfx::Viewport viewport = {};
- viewport.maxZ = 1.0f;
- viewport.extentX = (float)clientRect.width;
- viewport.extentY = (float)clientRect.height;
- drawCommandEncoder->setViewportAndScissor(viewport);
- drawCommandEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList);
-
- // We are only rendering one view, so we can fill in a per-view
- // shader object once and use it across all draw calls.
- //
+ // Once we have created all our graphcis API and application resources,
+ // we can start to load models. For now we are keeping things extremely
+ // simple by using a trivial `.obj` file that can be checked into source
+ // control.
+ //
+ // Support for loading more interesting/complex models will be added
+ // to this example over time (although model loading is *not* the focus).
+ //
+ Slang::String path = resourceBase.resolveResource("cube.obj").getBuffer();
+ loadAndAddModel(path.getBuffer());
- auto viewShaderObject = gDevice->createShaderObject(context.perViewShaderType);
- {
- ShaderCursor cursor(viewShaderObject);
- cursor["viewProjection"].setData(&viewProjection, sizeof(viewProjection));
- cursor["eyePosition"].setData(&cameraPosition, sizeof(cameraPosition));
+ return SLANG_OK;
}
- // The majority of our rendering logic is handled as a loop
- // over the models in the scene, and their meshes.
+
+ // With the setup work done, we can look at the per-frame rendering
+ // logic to see how the application will drive the `RenderContext`
+ // type to perform both shader parameter binding and code specialization.
//
- for(auto& model : gModels)
+ void renderFrame(int frameIndex) override
{
- drawCommandEncoder->setVertexBuffer(0, model->vertexBuffer);
- drawCommandEncoder->setIndexBuffer(model->indexBuffer, Format::R32_UINT);
- // For each model we provide a parameter
- // block that holds the per-model transformation
- // parameters, corresponding to the `PerModel` type
- // in the shader code.
- glm::mat4x4 modelTransform = identity;
- glm::mat4x4 inverseTransposeModelTransform = inverse(transpose(modelTransform));
- auto modelShaderObject = gDevice->createShaderObject(context.perModelShaderType);
+ // In order to see that things are rendering properly we need some
+ // kind of animation, so we will compute a crude delta-time value here.
+ //
+ if (!lastTime)
+ lastTime = getCurrentTime();
+ uint64_t currentTime = getCurrentTime();
+ float deltaTime = float(double(currentTime - lastTime) / double(getTimerFrequency()));
+ lastTime = currentTime;
+
+ // We will use the GLM library to do the matrix math required
+ // to set up our various transformation matrices.
+ //
+ glm::mat4x4 identity = glm::mat4x4(1.0f);
+
+ platform::Rect clientRect{};
+ if (isTestMode())
{
- ShaderCursor cursor(modelShaderObject);
- cursor["modelTransform"].setData(&modelTransform, sizeof(modelTransform));
- cursor["inverseTransposeModelTransform"].setData(
- &inverseTransposeModelTransform, sizeof(inverseTransposeModelTransform));
+ clientRect.width = 1024;
+ clientRect.height = 768;
}
-
- auto lightShaderObject = lightEnv->createShaderObject();
-
- // Now we loop over the meshes in the model.
+ else
+ {
+ clientRect = getWindow()->getClientRect();
+ }
+ if (clientRect.height == 0)
+ return;
+ glm::mat4x4 projection = glm::perspectiveRH_ZO(
+ glm::radians(60.0f),
+ float(clientRect.width) / float(clientRect.height),
+ 0.1f,
+ 1000.0f);
+
+ // We are implementing a *very* basic 6DOF first-person
+ // camera movement model.
//
- // A more advanced rendering loop would sort things by material
- // rather than by model, to avoid overly frequent state changes.
- // We are just doing something simple for the purposes of an
- // exmple program.
+ glm::mat3x3 cameraOrientationMat(cameraOrientation);
+ glm::vec3 forward = -cameraOrientationMat[2];
+ glm::vec3 right = cameraOrientationMat[0];
+
+ glm::vec3 movement = glm::vec3(0);
+ if (wPressed)
+ movement += forward;
+ if (sPressed)
+ movement -= forward;
+ if (aPressed)
+ movement -= right;
+ if (dPressed)
+ movement += right;
+
+ cameraPosition += deltaTime * translationScale * movement;
+
+ glm::mat4x4 view = identity;
+ view *= glm::mat4x4(inverse(cameraOrientation));
+ view = glm::translate(view, -cameraPosition);
+
+ glm::mat4x4 viewProjection = projection * view;
+ auto deviceInfo = gDevice->getDeviceInfo();
+ glm::mat4x4 correctionMatrix;
+ memcpy(&correctionMatrix, deviceInfo.identityProjectionMatrix, sizeof(float) * 16);
+ viewProjection = correctionMatrix * viewProjection;
+ // glm uses column-major layout, we need to translate it to row-major.
+ viewProjection = glm::transpose(viewProjection);
+
+ auto drawCommandBuffer = gTransientHeaps[frameIndex]->createCommandBuffer();
+ auto drawCommandEncoder =
+ drawCommandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameIndex]);
+ gfx::Viewport viewport = {};
+ viewport.maxZ = 1.0f;
+ viewport.extentX = (float)clientRect.width;
+ viewport.extentY = (float)clientRect.height;
+ drawCommandEncoder->setViewportAndScissor(viewport);
+ drawCommandEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList);
+
+ // We are only rendering one view, so we can fill in a per-view
+ // shader object once and use it across all draw calls.
//
- for(auto& mesh : model->meshes)
+
+ auto viewShaderObject = gDevice->createShaderObject(context.perViewShaderType);
{
- // Set the pipeline and binding state for drawing each mesh.
- auto rootObject = drawCommandEncoder->bindPipeline(gPipelineState);
- ShaderCursor rootCursor(rootObject);
- rootCursor["gViewParams"].setObject(viewShaderObject);
- rootCursor["gModelParams"].setObject(modelShaderObject);
- rootCursor["gLightEnv"].setObject(lightShaderObject);
-
- // Each mesh has a material, and each material has its own
- // parameter block that was created at load time, so we
- // can just re-use the persistent parameter block for the
- // chosen material.
+ ShaderCursor cursor(viewShaderObject);
+ cursor["viewProjection"].setData(&viewProjection, sizeof(viewProjection));
+ cursor["eyePosition"].setData(&cameraPosition, sizeof(cameraPosition));
+ }
+ // The majority of our rendering logic is handled as a loop
+ // over the models in the scene, and their meshes.
+ //
+ for (auto& model : gModels)
+ {
+ drawCommandEncoder->setVertexBuffer(0, model->vertexBuffer);
+ drawCommandEncoder->setIndexBuffer(model->indexBuffer, Format::R32_UINT);
+ // For each model we provide a parameter
+ // block that holds the per-model transformation
+ // parameters, corresponding to the `PerModel` type
+ // in the shader code.
+ glm::mat4x4 modelTransform = identity;
+ glm::mat4x4 inverseTransposeModelTransform = inverse(transpose(modelTransform));
+ auto modelShaderObject = gDevice->createShaderObject(context.perModelShaderType);
+ {
+ ShaderCursor cursor(modelShaderObject);
+ cursor["modelTransform"].setData(&modelTransform, sizeof(modelTransform));
+ cursor["inverseTransposeModelTransform"].setData(
+ &inverseTransposeModelTransform,
+ sizeof(inverseTransposeModelTransform));
+ }
+
+ auto lightShaderObject = lightEnv->createShaderObject();
+
+ // Now we loop over the meshes in the model.
//
- // Note that binding the material parameter block here is
- // both selecting the values to use for various material
- // parameters as well as the *code* to use for material
- // evaluation (based on the concrete shader type that
- // is implementing the `IMaterial` interface).
+ // A more advanced rendering loop would sort things by material
+ // rather than by model, to avoid overly frequent state changes.
+ // We are just doing something simple for the purposes of an
+ // exmple program.
//
- rootCursor["gMaterial"].setObject(mesh->material->shaderObject);
+ for (auto& mesh : model->meshes)
+ {
+ // Set the pipeline and binding state for drawing each mesh.
+ auto rootObject = drawCommandEncoder->bindPipeline(gPipelineState);
+ ShaderCursor rootCursor(rootObject);
+ rootCursor["gViewParams"].setObject(viewShaderObject);
+ rootCursor["gModelParams"].setObject(modelShaderObject);
+ rootCursor["gLightEnv"].setObject(lightShaderObject);
+
+ // Each mesh has a material, and each material has its own
+ // parameter block that was created at load time, so we
+ // can just re-use the persistent parameter block for the
+ // chosen material.
+ //
+ // Note that binding the material parameter block here is
+ // both selecting the values to use for various material
+ // parameters as well as the *code* to use for material
+ // evaluation (based on the concrete shader type that
+ // is implementing the `IMaterial` interface).
+ //
+ rootCursor["gMaterial"].setObject(mesh->material->shaderObject);
- // All the shader parameters and pipeline states have been set up,
- // we can now issue a draw call for the mesh.
- drawCommandEncoder->drawIndexed(mesh->indexCount, mesh->firstIndex);
+ // All the shader parameters and pipeline states have been set up,
+ // we can now issue a draw call for the mesh.
+ drawCommandEncoder->drawIndexed(mesh->indexCount, mesh->firstIndex);
+ }
}
- }
- drawCommandEncoder->endEncoding();
- drawCommandBuffer->close();
- gQueue->executeCommandBuffer(drawCommandBuffer);
+ drawCommandEncoder->endEncoding();
+ drawCommandBuffer->close();
+ gQueue->executeCommandBuffer(drawCommandBuffer);
- if (!isTestMode())
- {
- gSwapchain->present();
+ if (!isTestMode())
+ {
+ gSwapchain->present();
+ }
}
-}
-
};
// This macro instantiates an appropriate main function to
diff --git a/examples/nv-aftermath-example/main.cpp b/examples/nv-aftermath-example/main.cpp
index 9850586c8..67754a911 100644
--- a/examples/nv-aftermath-example/main.cpp
+++ b/examples/nv-aftermath-example/main.cpp
@@ -1,16 +1,15 @@
// main.cpp
-#include "slang.h"
-#include "slang-gfx.h"
-#include "gfx-util/shader-cursor.h"
-#include "tools/platform/window.h"
-#include "slang-com-ptr.h"
#include "../../source/core/slang-io.h"
-#include "source/core/slang-basic.h"
-#include "examples/example-base/example-base.h"
-
#include "GFSDK_Aftermath.h"
#include "GFSDK_Aftermath_GpuCrashDump.h"
+#include "examples/example-base/example-base.h"
+#include "gfx-util/shader-cursor.h"
+#include "slang-com-ptr.h"
+#include "slang-gfx.h"
+#include "slang.h"
+#include "source/core/slang-basic.h"
+#include "tools/platform/window.h"
using namespace gfx;
using namespace Slang;
@@ -21,10 +20,10 @@ static const ExampleResources resourceBase("nv-aftermath-example");
//
// This examples purpose is to show how to use the aftermath SDK to capture
// a crash dump.
-//
+//
// * [nsight aftermath](https://developer.nvidia.com/nsight-aftermath)
-//
-// In addition it uses obfuscation and source maps to allow source level
+//
+// In addition it uses obfuscation and source maps to allow source level
// debugging via aftermath even with obfuscation.
//
// * [obfuscation](https://github.com/shader-slang/slang/blob/master/docs/user-guide/a1-03-obfuscation.md)
@@ -37,29 +36,28 @@ struct Vertex
};
static const int kVertexCount = 3;
-static const Vertex kVertexData[kVertexCount] =
-{
- { { 0, 0, 0.5 }, { 1, 0, 0 } },
- { { 0, 1, 0.5 }, { 0, 0, 1 } },
- { { 1, 0, 0.5 }, { 0, 1, 0 } },
+static const Vertex kVertexData[kVertexCount] = {
+ {{0, 0, 0.5}, {1, 0, 0}},
+ {{0, 1, 0.5}, {0, 0, 1}},
+ {{1, 0, 0.5}, {0, 1, 0}},
};
struct AftermathCrashExample : public WindowedAppBase
{
void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob);
-
- gfx::Result loadShaderProgram( gfx::IDevice* device, gfx::IShaderProgram** outProgram);
-
+
+ gfx::Result loadShaderProgram(gfx::IDevice* device, gfx::IShaderProgram** outProgram);
+
Slang::Result initialize();
virtual void renderFrame(int frameBufferIndex) override;
-
+
void onAftermathCrash(const void* data, const uint32_t dataSizeInBytes);
void onAftermathDebugInfo(const void* pGpuCrashDump, const uint32_t gpuCrashDumpSize);
void onAftermathCrashDescription(PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription description);
-
+
void onAftermathMarker(const void* pMarker, void** resolvedMarkerData, uint32_t* markerSize);
// Create accessors so we don't have to use g prefixed variables.
@@ -69,12 +67,15 @@ struct AftermathCrashExample : public WindowedAppBase
gfx::ISwapchain* getSwapChain() { return gSwapchain; }
gfx::IRenderPassLayout* getRenderPassLayout() { return gRenderPass; }
Slang::List<Slang::ComPtr<gfx::IFramebuffer>>& getFrameBuffers() { return gFramebuffers; }
- Slang::List<Slang::ComPtr<gfx::ITransientResourceHeap>>& getTransientHeaps() { return gTransientHeaps; }
+ Slang::List<Slang::ComPtr<gfx::ITransientResourceHeap>>& getTransientHeaps()
+ {
+ return gTransientHeaps;
+ }
ComPtr<gfx::IPipelineState> m_pipelineState;
ComPtr<gfx::IBufferResource> m_vertexBuffer;
- /// A counter such that we can make aftermath dump file names unique
+ /// A counter such that we can make aftermath dump file names unique
std::atomic<int> m_uniqueId = 0;
};
@@ -94,13 +95,15 @@ void AftermathCrashExample::onAftermathCrash(const void* data, const uint32_t da
// Dump out as a file
Slang::StringBuilder filename;
filename << "aftermath-dump-" << id << ".bin";
-
+
File::writeAllBytes(filename, data, dataSizeInBytes);
-
- //SLANG_BREAKPOINT(0);
+
+ // SLANG_BREAKPOINT(0);
}
-void AftermathCrashExample::onAftermathDebugInfo(const void* gpuCrashDump, const uint32_t gpuCrashDumpSize)
+void AftermathCrashExample::onAftermathDebugInfo(
+ const void* gpuCrashDump,
+ const uint32_t gpuCrashDumpSize)
{
const auto id = m_uniqueId++;
@@ -111,41 +114,49 @@ void AftermathCrashExample::onAftermathDebugInfo(const void* gpuCrashDump, const
File::writeAllBytes(filename, gpuCrashDump, gpuCrashDumpSize);
}
-void AftermathCrashExample::onAftermathCrashDescription(PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription description)
+void AftermathCrashExample::onAftermathCrashDescription(
+ PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription description)
{
// Ignore for now
}
-void AftermathCrashExample::onAftermathMarker(const void* marker, void** resolvedMarkerData, uint32_t* markerSize)
+void AftermathCrashExample::onAftermathMarker(
+ const void* marker,
+ void** resolvedMarkerData,
+ uint32_t* markerSize)
{
// Ignore for now
}
struct FileSystemEntry
{
- SlangPathType type; ///< The type of the entry
- String path; ///< The path to the entr
+ SlangPathType type; ///< The type of the entry
+ String path; ///< The path to the entr
};
struct CompileProduct
{
- String fileName; ///< The filename to write the compile product out to
- ComPtr<ISlangBlob> blob; ///< A blob holding the products contents
+ String fileName; ///< The filename to write the compile product out to
+ ComPtr<ISlangBlob> blob; ///< A blob holding the products contents
};
-/* Currently the mechanism to access the contents of a compilation that might consist of many products is through
-representing the contents as a "file system".
+/* Currently the mechanism to access the contents of a compilation that might consist of many
+products is through representing the contents as a "file system".
-The file system is just a somewhat convenient/simple in memory representation of the compilation products.
+The file system is just a somewhat convenient/simple in memory representation of the compilation
+products.
This function transverses the file system and adds everything found into outEntries.
*/
-static SlangResult _findFileSystemContents(ISlangFileSystemExt* fileSystem, const char* rootPath, List<FileSystemEntry>& outEntries)
+static SlangResult _findFileSystemContents(
+ ISlangFileSystemExt* fileSystem,
+ const char* rootPath,
+ List<FileSystemEntry>& outEntries)
{
{
SlangPathType type;
SLANG_RETURN_ON_FAIL(fileSystem->getPathType(rootPath, &type));
- outEntries.add(FileSystemEntry{ type, rootPath });
+ outEntries.add(FileSystemEntry{type, rootPath});
}
// A context used to hold state, when using enumeratePathContents
@@ -162,16 +173,18 @@ static SlangResult _findFileSystemContents(ISlangFileSystemExt* fileSystem, cons
// If it's a directory we want to traverse it's contents
if (entry.type == SLANG_PATH_TYPE_DIRECTORY)
{
- Context context{outEntries, entry.path };
+ Context context{outEntries, entry.path};
- fileSystem->enumeratePathContents(entry.path.getBuffer(),
- [](SlangPathType pathType, const char* name, void* userData) -> void {
+ fileSystem->enumeratePathContents(
+ entry.path.getBuffer(),
+ [](SlangPathType pathType, const char* name, void* userData) -> void
+ {
Context* context = reinterpret_cast<Context*>(userData);
const String path = Path::simplify(Path::combine(context->path, name));
context->entries.add({pathType, path});
- },
+ },
&context);
}
}
@@ -179,14 +192,18 @@ static SlangResult _findFileSystemContents(ISlangFileSystemExt* fileSystem, cons
return SLANG_OK;
}
-/* This function takes a compile results file system, and finds items that should be written out.
+/* This function takes a compile results file system, and finds items that should be written out.
-This is somewhat complicated because the names of products from different compilations might have the same names.
-So a "prefix" is passed in, and for files that don't have unique names, they are uniqified via the prefix.
+This is somewhat complicated because the names of products from different compilations might have
+the same names. So a "prefix" is passed in, and for files that don't have unique names, they are
+uniqified via the prefix.
-The same product may appear in multiple compilations, for example obfuscated source maps so a product is not added
-if there is already a product with the same name */
-static SlangResult _addCompileProducts(ISlangFileSystemExt* fileSystem, const char* prefix, List<CompileProduct>& ioProducts)
+The same product may appear in multiple compilations, for example obfuscated source maps so a
+product is not added if there is already a product with the same name */
+static SlangResult _addCompileProducts(
+ ISlangFileSystemExt* fileSystem,
+ const char* prefix,
+ List<CompileProduct>& ioProducts)
{
List<FileSystemEntry> fileSystemEntries;
SLANG_RETURN_ON_FAIL(_findFileSystemContents(fileSystem, ".", fileSystemEntries));
@@ -201,17 +218,18 @@ static SlangResult _addCompileProducts(ISlangFileSystemExt* fileSystem, const ch
const auto ext = Path::getPathExt(fileSystemEntry.path);
String outFileName;
-
+
// Some filenames need special handling, and their names are already unique
- // Others will be the same between differen fileSystem that represent the
- // compilation products.
+ // Others will be the same between differen fileSystem that represent the
+ // compilation products.
//
// Source maps that are obfuscated are unique.
{
String inFileName = Path::getFileNameWithoutExt(fileSystemEntry.path);
-
+
// If it's an obfuscated source map, it's name is already unique (it includes the hash)
- const bool isUniqueName = (ext == toSlice("map") && inFileName.endsWith(toSlice("-obfuscated")));
+ const bool isUniqueName =
+ (ext == toSlice("map") && inFileName.endsWith(toSlice("-obfuscated")));
StringBuilder buf;
// If it's not a uniquename make it unique via the prefix
@@ -224,20 +242,21 @@ static SlangResult _addCompileProducts(ISlangFileSystemExt* fileSystem, const ch
buf << inFileName << "." << ext;
outFileName = buf;
}
-
+
// If we have an output filename
if (outFileName.getLength())
{
// And that filename isn't already used
- if (ioProducts.findFirstIndex([&](const CompileProduct& product) -> bool {
- return product.fileName == outFileName;
- }) < 0)
+ if (ioProducts.findFirstIndex(
+ [&](const CompileProduct& product) -> bool
+ { return product.fileName == outFileName; }) < 0)
{
ComPtr<ISlangBlob> blob;
- SLANG_RETURN_ON_FAIL(fileSystem->loadFile(fileSystemEntry.path.getBuffer(), blob.writeRef()));
+ SLANG_RETURN_ON_FAIL(
+ fileSystem->loadFile(fileSystemEntry.path.getBuffer(), blob.writeRef()));
// Add to the results
- ioProducts.add(CompileProduct{ outFileName, blob });
+ ioProducts.add(CompileProduct{outFileName, blob});
}
}
}
@@ -252,11 +271,11 @@ gfx::Result AftermathCrashExample::loadShaderProgram(
ComPtr<slang::ISession> slangSession;
slangSession = device->getSlangSession();
- // This is a little bit of a work around.
- //
+ // This is a little bit of a work around.
+ //
// We want to set some options that are only available
// via processCommandLineArguments, but we need a request to be able to set them up
- // The setting actually sets the parameters on the Linkage, so they will be used for the later
+ // The setting actually sets the parameters on the Linkage, so they will be used for the later
// actual compilation
{
ComPtr<slang::ICompileRequest> request;
@@ -264,20 +283,20 @@ gfx::Result AftermathCrashExample::loadShaderProgram(
SLANG_RETURN_ON_FAIL(slangSession->createCompileRequest(request.writeRef()));
// Turn on obfuscation
- //
+ //
// Turns on source map as the line directive, this will lead to an "emit source map"
// and no #line directives in generated source.
//
// It isn't necessary to use the "source-map" line directive mode, and just use
// #line directives, and have source locations to obfuscated source file directly embedded.
- //
+ //
// To do this replace the line below with
//
// ```
// const char* args[] = { "-obfuscate" };
// ```
- const char* args[] = { "-obfuscate", "-line-directive-mode", "source-map" };
-
+ const char* args[] = {"-obfuscate", "-line-directive-mode", "source-map"};
+
request->processCommandLineArguments(args, SLANG_COUNT_OF(args));
// Enable debug info
@@ -296,7 +315,8 @@ gfx::Result AftermathCrashExample::loadShaderProgram(
SLANG_RETURN_ON_FAIL(module->findEntryPointByName("vertexMain", vertexEntryPoint.writeRef()));
//
ComPtr<slang::IEntryPoint> fragmentEntryPoint;
- SLANG_RETURN_ON_FAIL(module->findEntryPointByName("fragmentMain", fragmentEntryPoint.writeRef()));
+ SLANG_RETURN_ON_FAIL(
+ module->findEntryPointByName("fragmentMain", fragmentEntryPoint.writeRef()));
// At this point we have a few different Slang API objects that represent
// pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`.
@@ -348,36 +368,53 @@ gfx::Result AftermathCrashExample::loadShaderProgram(
ComPtr<ISlangBlob> code;
ComPtr<ISlangBlob> diagnostics;
- SLANG_RETURN_ON_FAIL(linkedProgram->getEntryPointCode(vertexEntryPointIndex, targetIndex, code.writeRef(), diagnostics.writeRef()));
- SLANG_RETURN_ON_FAIL(linkedProgram->getEntryPointCode(fragmentEntryPointIndex, targetIndex, code.writeRef(), diagnostics.writeRef()));
+ SLANG_RETURN_ON_FAIL(linkedProgram->getEntryPointCode(
+ vertexEntryPointIndex,
+ targetIndex,
+ code.writeRef(),
+ diagnostics.writeRef()));
+ SLANG_RETURN_ON_FAIL(linkedProgram->getEntryPointCode(
+ fragmentEntryPointIndex,
+ targetIndex,
+ code.writeRef(),
+ diagnostics.writeRef()));
}
{
- // We want to find all the compilation products. In particular we want to get the emit source map, and the obfuscated
- // source maps
+ // We want to find all the compilation products. In particular we want to get the emit
+ // source map, and the obfuscated source maps
List<CompileProduct> compileProducts;
- // The current mechanism for getting access to compilation products other than result blob/diagnostics is to
- // return it as a compilation result "file system".
+ // The current mechanism for getting access to compilation products other than result
+ // blob/diagnostics is to return it as a compilation result "file system".
ComPtr<ISlangMutableFileSystem> vertexFileSystem;
- SLANG_RETURN_ON_FAIL(linkedProgram->getResultAsFileSystem(vertexEntryPointIndex, targetIndex, vertexFileSystem.writeRef()));
+ SLANG_RETURN_ON_FAIL(linkedProgram->getResultAsFileSystem(
+ vertexEntryPointIndex,
+ targetIndex,
+ vertexFileSystem.writeRef()));
ComPtr<ISlangMutableFileSystem> fragmentFileSystem;
- SLANG_RETURN_ON_FAIL(linkedProgram->getResultAsFileSystem(fragmentEntryPointIndex, targetIndex, fragmentFileSystem.writeRef()));
+ SLANG_RETURN_ON_FAIL(linkedProgram->getResultAsFileSystem(
+ fragmentEntryPointIndex,
+ targetIndex,
+ fragmentFileSystem.writeRef()));
// Add the contents of the compile result file systems into compileProducts
- // Some products might appear in both file systems, so compileProducts is just the unique products.
- // Additionally because some products may have the same name, we pass in a "prefix" to make the products name
- // unique.
+ // Some products might appear in both file systems, so compileProducts is just the unique
+ // products. Additionally because some products may have the same name, we pass in a
+ // "prefix" to make the products name unique.
SLANG_RETURN_ON_FAIL(_addCompileProducts(vertexFileSystem, "vertex", compileProducts));
SLANG_RETURN_ON_FAIL(_addCompileProducts(fragmentFileSystem, "fragment", compileProducts));
- // Now write all of the products out
+ // Now write all of the products out
for (const auto& product : compileProducts)
{
- SLANG_RETURN_ON_FAIL(File::writeAllBytes(product.fileName, product.blob->getBufferPointer(), product.blob->getBufferSize()));
+ SLANG_RETURN_ON_FAIL(File::writeAllBytes(
+ product.fileName,
+ product.blob->getBufferPointer(),
+ product.blob->getBufferSize()));
}
}
@@ -393,36 +430,53 @@ gfx::Result AftermathCrashExample::loadShaderProgram(
return SLANG_OK;
}
-static void GFSDK_AFTERMATH_CALL _crashCallback(const void* gpuCrashDump, const uint32_t gpuCrashDumpSize, void* userData)
+static void GFSDK_AFTERMATH_CALL
+_crashCallback(const void* gpuCrashDump, const uint32_t gpuCrashDumpSize, void* userData)
{
- reinterpret_cast<AftermathCrashExample*>(userData)->onAftermathCrash(gpuCrashDump, gpuCrashDumpSize);
+ reinterpret_cast<AftermathCrashExample*>(userData)->onAftermathCrash(
+ gpuCrashDump,
+ gpuCrashDumpSize);
}
-static void GFSDK_AFTERMATH_CALL _debugInfoCallback(const void* gpuCrashDump, const uint32_t gpuCrashDumpSize, void* userData)
+static void GFSDK_AFTERMATH_CALL
+_debugInfoCallback(const void* gpuCrashDump, const uint32_t gpuCrashDumpSize, void* userData)
{
- reinterpret_cast<AftermathCrashExample*>(userData)->onAftermathDebugInfo(gpuCrashDump, gpuCrashDumpSize);
+ reinterpret_cast<AftermathCrashExample*>(userData)->onAftermathDebugInfo(
+ gpuCrashDump,
+ gpuCrashDumpSize);
}
-static void GFSDK_AFTERMATH_CALL _crashDescriptionCallback(PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription addDescription, void* userData)
+static void GFSDK_AFTERMATH_CALL _crashDescriptionCallback(
+ PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription addDescription,
+ void* userData)
{
reinterpret_cast<AftermathCrashExample*>(userData)->onAftermathCrashDescription(addDescription);
}
-static void GFSDK_AFTERMATH_CALL _markerCallback(const void* marker, void* pUserData, void** resolvedMarkerData, uint32_t* markerSize)
+static void GFSDK_AFTERMATH_CALL _markerCallback(
+ const void* marker,
+ void* pUserData,
+ void** resolvedMarkerData,
+ uint32_t* markerSize)
{
- reinterpret_cast<AftermathCrashExample*>(pUserData)->onAftermathMarker(marker, resolvedMarkerData, markerSize);
+ reinterpret_cast<AftermathCrashExample*>(pUserData)->onAftermathMarker(
+ marker,
+ resolvedMarkerData,
+ markerSize);
}
Slang::Result AftermathCrashExample::initialize()
{
// Defer shader debug information callbacks until an actual GPU crash dump
// is generated. Increases memory footprint.
- const uint32_t aftermathFeatureFlags = GFSDK_Aftermath_GpuCrashDumpFeatureFlags_DeferDebugInfoCallbacks;
+ const uint32_t aftermathFeatureFlags =
+ GFSDK_Aftermath_GpuCrashDumpFeatureFlags_DeferDebugInfoCallbacks;
// As per docs must be called before any device is created
GFSDK_Aftermath_EnableGpuCrashDumps(
GFSDK_Aftermath_Version_API,
- GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_DX | GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_Vulkan,
+ GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_DX |
+ GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_Vulkan,
aftermathFeatureFlags,
_crashCallback,
_debugInfoCallback,
@@ -431,14 +485,14 @@ Slang::Result AftermathCrashExample::initialize()
this);
// Set to a specific render API as needed. Valid values are...
- //
+ //
// * gfx::DeviceType::Default
// * gfx::DeviceType::Vulkan
// * gfx::DeviceType::DirectX12
// * gfx::DeviceType::DirectX11
const gfx::DeviceType deviceType = gfx::DeviceType::Default;
-
+
initializeBase("aftermath-crash-example", 1024, 768, deviceType);
auto device = getDevice();
@@ -449,14 +503,12 @@ Slang::Result AftermathCrashExample::initialize()
// First, we create an input layout:
//
InputElementDesc inputElements[] = {
- { "POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position) },
- { "COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color) },
+ {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position)},
+ {"COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color)},
};
- auto inputLayout = gDevice->createInputLayout(
- sizeof(Vertex),
- &inputElements[0],
- 2);
- if (!inputLayout) return SLANG_FAIL;
+ auto inputLayout = gDevice->createInputLayout(sizeof(Vertex), &inputElements[0], 2);
+ if (!inputLayout)
+ return SLANG_FAIL;
// Next we allocate a vertex buffer for our pre-initialized
// vertex data.
@@ -466,7 +518,8 @@ Slang::Result AftermathCrashExample::initialize()
vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex);
vertexBufferDesc.defaultState = ResourceState::VertexBuffer;
m_vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]);
- if (!m_vertexBuffer) return SLANG_FAIL;
+ if (!m_vertexBuffer)
+ return SLANG_FAIL;
// Now we will use our `loadShaderProgram` function to load
// the code from `shaders.slang` into the graphics API.
@@ -490,10 +543,12 @@ Slang::Result AftermathCrashExample::initialize()
return SLANG_OK;
}
-void AftermathCrashExample::renderFrame(int frameBufferIndex)
+void AftermathCrashExample::renderFrame(int frameBufferIndex)
{
- ComPtr<ICommandBuffer> commandBuffer = getTransientHeaps()[frameBufferIndex]->createCommandBuffer();
- auto renderEncoder = commandBuffer->encodeRenderCommands(gRenderPass, getFrameBuffers()[frameBufferIndex]);
+ ComPtr<ICommandBuffer> commandBuffer =
+ getTransientHeaps()[frameBufferIndex]->createCommandBuffer();
+ auto renderEncoder =
+ commandBuffer->encodeRenderCommands(gRenderPass, getFrameBuffers()[frameBufferIndex]);
gfx::Viewport viewport = {};
viewport.maxZ = 1.0f;
@@ -508,9 +563,10 @@ void AftermathCrashExample::renderFrame(int frameBufferIndex)
ShaderCursor rootCursor(rootObject);
rootCursor["Uniforms"]["modelViewProjection"].setData(
- deviceInfo.identityProjectionMatrix, sizeof(float) * 16);
+ deviceInfo.identityProjectionMatrix,
+ sizeof(float) * 16);
- // We are going to extra efforts to create a shader that we know will time
+ // We are going to extra efforts to create a shader that we know will time
// out because we *want* a GPU "crash", such we can capture via nsight aftermath.
// The failCount is just a number that is large enought to make things take too long.
int32_t failCount = 0x3fffffff;
diff --git a/examples/platform-test/main.cpp b/examples/platform-test/main.cpp
index f20a5a716..daa9bbc4b 100644
--- a/examples/platform-test/main.cpp
+++ b/examples/platform-test/main.cpp
@@ -1,6 +1,6 @@
+#include "examples/example-base/example-base.h"
#include "slang.h"
#include "tools/platform/window.h"
-#include "examples/example-base/example-base.h"
using namespace gfx;
using namespace Slang;
@@ -8,93 +8,105 @@ using namespace Slang;
struct PlatformTest : public WindowedAppBase
{
-void onSizeChanged()
-{
- printf("onSizeChanged\n");
-}
-
-void onFocus()
-{
- printf("onFocus\n");
-}
-
-void onLostFocus()
-{
- printf("onLostFocus\n");
-}
-
-void onKeyDown(platform::KeyEventArgs args)
-{
- printf("onKeyDown(key=0x%02x, buttons=0x%02x)\n", (uint32_t)args.key, args.buttons);
-}
-
-void onKeyUp(platform::KeyEventArgs args)
-{
- printf("okKeyUp(key=0x%02x, buttons=0x%02x)\n", (uint32_t)args.key, args.buttons);
-}
-
-void onKeyPress(platform::KeyEventArgs args)
-{
- printf("onKeyPress(keyChar=0x%02x)\n", args.keyChar);
-}
-
-void onMouseMove(platform::MouseEventArgs args)
-{
- printf("onMouseMove(x=%d, y=%d, delta=%d, buttons=0x%02x\n", args.x, args.y, args.delta, args.buttons);
-}
-
-void onMouseDown(platform::MouseEventArgs args)
-{
- printf("onMouseDown(x=%d, y=%d, delta=%d, buttons=0x%02x\n", args.x, args.y, args.delta, args.buttons);
-}
-
-void onMouseUp(platform::MouseEventArgs args)
-{
- printf("onMouseUp(x=%d, y=%d, delta=%d, buttons=0x%02x\n", args.x, args.y, args.delta, args.buttons);
-}
-
-void onMouseWheel(platform::MouseEventArgs args)
-{
- printf("onMouseWheel(x=%d, y=%d, delta=%d, buttons=0x%02x\n", args.x, args.y, args.delta, args.buttons);
-}
-
-Slang::Result initialize()
-{
- initializeBase("platform-test", 1024, 768);
-
- gWindow->events.sizeChanged = [this]() { onSizeChanged(); };
- gWindow->events.focus = [this]() { onFocus(); };
- gWindow->events.lostFocus = [this]() { onLostFocus(); };
- gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); };
- gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); };
- gWindow->events.keyPress = [this](const platform::KeyEventArgs& e) { onKeyPress(e); };
- gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { onMouseMove(e); };
- gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { onMouseDown(e); };
- gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); };
- gWindow->events.mouseWheel = [this](const platform::MouseEventArgs& e) { onMouseWheel(e); };
-
- return SLANG_OK;
-}
-
-virtual void renderFrame(int frameBufferIndex) override
-{
- ComPtr<ICommandBuffer> commandBuffer = gTransientHeaps[frameBufferIndex]->createCommandBuffer();
-
- auto renderEncoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]);
-
- gfx::Viewport viewport = {};
- viewport.maxZ = 1.0f;
- viewport.extentX = (float)windowWidth;
- viewport.extentY = (float)windowHeight;
- renderEncoder->setViewportAndScissor(viewport);
-
- renderEncoder->endEncoding();
- commandBuffer->close();
- gQueue->executeCommandBuffer(commandBuffer);
-
- gSwapchain->present();
-}
-
+ void onSizeChanged() { printf("onSizeChanged\n"); }
+
+ void onFocus() { printf("onFocus\n"); }
+
+ void onLostFocus() { printf("onLostFocus\n"); }
+
+ void onKeyDown(platform::KeyEventArgs args)
+ {
+ printf("onKeyDown(key=0x%02x, buttons=0x%02x)\n", (uint32_t)args.key, args.buttons);
+ }
+
+ void onKeyUp(platform::KeyEventArgs args)
+ {
+ printf("okKeyUp(key=0x%02x, buttons=0x%02x)\n", (uint32_t)args.key, args.buttons);
+ }
+
+ void onKeyPress(platform::KeyEventArgs args)
+ {
+ printf("onKeyPress(keyChar=0x%02x)\n", args.keyChar);
+ }
+
+ void onMouseMove(platform::MouseEventArgs args)
+ {
+ printf(
+ "onMouseMove(x=%d, y=%d, delta=%d, buttons=0x%02x\n",
+ args.x,
+ args.y,
+ args.delta,
+ args.buttons);
+ }
+
+ void onMouseDown(platform::MouseEventArgs args)
+ {
+ printf(
+ "onMouseDown(x=%d, y=%d, delta=%d, buttons=0x%02x\n",
+ args.x,
+ args.y,
+ args.delta,
+ args.buttons);
+ }
+
+ void onMouseUp(platform::MouseEventArgs args)
+ {
+ printf(
+ "onMouseUp(x=%d, y=%d, delta=%d, buttons=0x%02x\n",
+ args.x,
+ args.y,
+ args.delta,
+ args.buttons);
+ }
+
+ void onMouseWheel(platform::MouseEventArgs args)
+ {
+ printf(
+ "onMouseWheel(x=%d, y=%d, delta=%d, buttons=0x%02x\n",
+ args.x,
+ args.y,
+ args.delta,
+ args.buttons);
+ }
+
+ Slang::Result initialize()
+ {
+ initializeBase("platform-test", 1024, 768);
+
+ gWindow->events.sizeChanged = [this]() { onSizeChanged(); };
+ gWindow->events.focus = [this]() { onFocus(); };
+ gWindow->events.lostFocus = [this]() { onLostFocus(); };
+ gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); };
+ gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); };
+ gWindow->events.keyPress = [this](const platform::KeyEventArgs& e) { onKeyPress(e); };
+ gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { onMouseMove(e); };
+ gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { onMouseDown(e); };
+ gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); };
+ gWindow->events.mouseWheel = [this](const platform::MouseEventArgs& e) { onMouseWheel(e); };
+
+ return SLANG_OK;
+ }
+
+ virtual void renderFrame(int frameBufferIndex) override
+ {
+ ComPtr<ICommandBuffer> commandBuffer =
+ gTransientHeaps[frameBufferIndex]->createCommandBuffer();
+
+ auto renderEncoder =
+ commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]);
+
+ gfx::Viewport viewport = {};
+ viewport.maxZ = 1.0f;
+ viewport.extentX = (float)windowWidth;
+ viewport.extentY = (float)windowHeight;
+ renderEncoder->setViewportAndScissor(viewport);
+
+ renderEncoder->endEncoding();
+ commandBuffer->close();
+ gQueue->executeCommandBuffer(commandBuffer);
+
+ gSwapchain->present();
+ }
};
// This macro instantiates an appropriate main function to
diff --git a/examples/ray-tracing-pipeline/main.cpp b/examples/ray-tracing-pipeline/main.cpp
index 562eca4dc..f5ad03e1b 100644
--- a/examples/ray-tracing-pipeline/main.cpp
+++ b/examples/ray-tracing-pipeline/main.cpp
@@ -3,14 +3,14 @@
// This file implements an example of hardware ray-tracing using
// Slang shaders and the `gfx` graphics API.
-#include "slang.h"
-#include "slang-gfx.h"
+#include "examples/example-base/example-base.h"
#include "gfx-util/shader-cursor.h"
-#include "tools/platform/window.h"
-#include "tools/platform/vector-math.h"
#include "slang-com-ptr.h"
+#include "slang-gfx.h"
+#include "slang.h"
#include "source/core/slang-basic.h"
-#include "examples/example-base/example-base.h"
+#include "tools/platform/vector-math.h"
+#include "tools/platform/window.h"
using namespace gfx;
using namespace Slang;
@@ -36,8 +36,7 @@ struct Vertex
// Define geometry data for our test scene.
// The scene contains a floor plane, and a cube placed on top of it at the center.
static const int kVertexCount = 24;
-static const Vertex kVertexData[kVertexCount] =
-{
+static const Vertex kVertexData[kVertexCount] = {
// Floor plane
{{-100.0f, 0, 100.0f}},
{{100.0f, 0, 100.0f}},
@@ -70,15 +69,9 @@ static const Vertex kVertexData[kVertexCount] =
{{1.0f, 0.0, -1.0f}},
};
static const int kIndexCount = 36;
-static const int kIndexData[kIndexCount] =
-{
- 0, 1, 2, 0, 2, 3,
- 4, 5, 6, 4, 6, 7,
- 8, 9, 10, 8, 10, 11,
- 12, 13, 14, 12, 14, 15,
- 16, 17, 18, 16, 18, 19,
- 20, 21, 22, 20, 22, 23
-};
+static const int kIndexData[kIndexCount] = {0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7,
+ 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15,
+ 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23};
struct Primitive
{
@@ -86,8 +79,7 @@ struct Primitive
float color[4];
};
static const int kPrimitiveCount = 12;
-static const Primitive kPrimitiveData[kPrimitiveCount] =
-{
+static const Primitive kPrimitiveData[kPrimitiveCount] = {
{{0.0f, 1.0f, 0.0f, 0.0f}, {0.75f, 0.8f, 0.85f, 1.0f}},
{{0.0f, 1.0f, 0.0f, 0.0f}, {0.75f, 0.8f, 0.85f, 1.0f}},
{{0.0f, 1.0f, 0.0f, 0.0f}, {0.95f, 0.85f, 0.05f, 1.0f}},
@@ -134,559 +126,575 @@ struct RayTracing : public WindowedAppBase
{
-Uniforms gUniforms = {};
+ Uniforms gUniforms = {};
-// Many Slang API functions return detailed diagnostic information
-// (error messages, warnings, etc.) as a "blob" of data, or return
-// a null blob pointer instead if there were no issues.
-//
-// For convenience, we define a subroutine that will dump the information
-// in a diagnostic blob if one is produced, and skip it otherwise.
-//
-void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob)
-{
- if( diagnosticsBlob != nullptr )
+ // Many Slang API functions return detailed diagnostic information
+ // (error messages, warnings, etc.) as a "blob" of data, or return
+ // a null blob pointer instead if there were no issues.
+ //
+ // For convenience, we define a subroutine that will dump the information
+ // in a diagnostic blob if one is produced, and skip it otherwise.
+ //
+ void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob)
{
- printf("%s", (const char*) diagnosticsBlob->getBufferPointer());
+ if (diagnosticsBlob != nullptr)
+ {
+ printf("%s", (const char*)diagnosticsBlob->getBufferPointer());
#ifdef _WIN32
- _Win32OutputDebugString((const char*)diagnosticsBlob->getBufferPointer());
+ _Win32OutputDebugString((const char*)diagnosticsBlob->getBufferPointer());
#endif
+ }
}
-}
-// Load and compile shader code from souce.
-gfx::Result loadShaderProgram(
- gfx::IDevice* device, bool isRayTracingPipeline, gfx::IShaderProgram** outProgram)
-{
- ComPtr<slang::ISession> slangSession;
- slangSession = device->getSlangSession();
-
- ComPtr<slang::IBlob> diagnosticsBlob;
- Slang::String path = resourceBase.resolveResource("shaders.slang");
- slang::IModule* module = slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef());
- diagnoseIfNeeded(diagnosticsBlob);
- if(!module)
- return SLANG_FAIL;
-
- Slang::List<slang::IComponentType*> componentTypes;
- componentTypes.add(module);
- if (isRayTracingPipeline)
- {
- ComPtr<slang::IEntryPoint> entryPoint;
- SLANG_RETURN_ON_FAIL(module->findEntryPointByName("rayGenShader", entryPoint.writeRef()));
- componentTypes.add(entryPoint);
- SLANG_RETURN_ON_FAIL(module->findEntryPointByName("missShader", entryPoint.writeRef()));
- componentTypes.add(entryPoint);
- SLANG_RETURN_ON_FAIL(
- module->findEntryPointByName("closestHitShader", entryPoint.writeRef()));
- componentTypes.add(entryPoint);
- SLANG_RETURN_ON_FAIL(
- module->findEntryPointByName("shadowRayHitShader", entryPoint.writeRef()));
- componentTypes.add(entryPoint);
- }
- else
+ // Load and compile shader code from souce.
+ gfx::Result loadShaderProgram(
+ gfx::IDevice* device,
+ bool isRayTracingPipeline,
+ gfx::IShaderProgram** outProgram)
{
- ComPtr<slang::IEntryPoint> entryPoint;
- SLANG_RETURN_ON_FAIL(module->findEntryPointByName("vertexMain", entryPoint.writeRef()));
- componentTypes.add(entryPoint);
- SLANG_RETURN_ON_FAIL(module->findEntryPointByName("fragmentMain", entryPoint.writeRef()));
- componentTypes.add(entryPoint);
- }
-
- ComPtr<slang::IComponentType> linkedProgram;
- SlangResult result = slangSession->createCompositeComponentType(
- componentTypes.getBuffer(),
- componentTypes.getCount(),
- linkedProgram.writeRef(),
- diagnosticsBlob.writeRef());
- diagnoseIfNeeded(diagnosticsBlob);
- SLANG_RETURN_ON_FAIL(result);
+ ComPtr<slang::ISession> slangSession;
+ slangSession = device->getSlangSession();
+
+ ComPtr<slang::IBlob> diagnosticsBlob;
+ Slang::String path = resourceBase.resolveResource("shaders.slang");
+ slang::IModule* module =
+ slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ if (!module)
+ return SLANG_FAIL;
- if (isTestMode())
- {
- printEntrypointHashes(componentTypes.getCount() - 1, 1, linkedProgram);
+ Slang::List<slang::IComponentType*> componentTypes;
+ componentTypes.add(module);
+ if (isRayTracingPipeline)
+ {
+ ComPtr<slang::IEntryPoint> entryPoint;
+ SLANG_RETURN_ON_FAIL(
+ module->findEntryPointByName("rayGenShader", entryPoint.writeRef()));
+ componentTypes.add(entryPoint);
+ SLANG_RETURN_ON_FAIL(module->findEntryPointByName("missShader", entryPoint.writeRef()));
+ componentTypes.add(entryPoint);
+ SLANG_RETURN_ON_FAIL(
+ module->findEntryPointByName("closestHitShader", entryPoint.writeRef()));
+ componentTypes.add(entryPoint);
+ SLANG_RETURN_ON_FAIL(
+ module->findEntryPointByName("shadowRayHitShader", entryPoint.writeRef()));
+ componentTypes.add(entryPoint);
+ }
+ else
+ {
+ ComPtr<slang::IEntryPoint> entryPoint;
+ SLANG_RETURN_ON_FAIL(module->findEntryPointByName("vertexMain", entryPoint.writeRef()));
+ componentTypes.add(entryPoint);
+ SLANG_RETURN_ON_FAIL(
+ module->findEntryPointByName("fragmentMain", entryPoint.writeRef()));
+ componentTypes.add(entryPoint);
+ }
+
+ ComPtr<slang::IComponentType> linkedProgram;
+ SlangResult result = slangSession->createCompositeComponentType(
+ componentTypes.getBuffer(),
+ componentTypes.getCount(),
+ linkedProgram.writeRef(),
+ diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ SLANG_RETURN_ON_FAIL(result);
+
+ if (isTestMode())
+ {
+ printEntrypointHashes(componentTypes.getCount() - 1, 1, linkedProgram);
+ }
+
+ gfx::IShaderProgram::Desc programDesc = {};
+ programDesc.slangGlobalScope = linkedProgram;
+ SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram));
+
+ return SLANG_OK;
}
- gfx::IShaderProgram::Desc programDesc = {};
- programDesc.slangGlobalScope = linkedProgram;
- SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram));
-
- return SLANG_OK;
-}
-
-ComPtr<gfx::IPipelineState> gPresentPipelineState;
-ComPtr<gfx::IPipelineState> gRenderPipelineState;
-ComPtr<gfx::IBufferResource> gFullScreenVertexBuffer;
-ComPtr<gfx::IBufferResource> gVertexBuffer;
-ComPtr<gfx::IBufferResource> gIndexBuffer;
-ComPtr<gfx::IBufferResource> gPrimitiveBuffer;
-ComPtr<gfx::IBufferResource> gTransformBuffer;
-ComPtr<gfx::IResourceView> gPrimitiveBufferSRV;
-ComPtr<gfx::IBufferResource> gInstanceBuffer;
-ComPtr<gfx::IBufferResource> gBLASBuffer;
-ComPtr<gfx::IAccelerationStructure> gBLAS;
-ComPtr<gfx::IBufferResource> gTLASBuffer;
-ComPtr<gfx::IAccelerationStructure> gTLAS;
-ComPtr<gfx::ITextureResource> gResultTexture;
-ComPtr<gfx::IResourceView> gResultTextureUAV;
-ComPtr<gfx::IShaderTable> gShaderTable;
-
-uint64_t lastTime = 0;
-
-// glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10));
-// glm::vec3 lightColor = glm::vec3(1, 1, 1);
-
-glm::vec3 cameraPosition = glm::vec3(-2.53f, 2.72f, 4.3f);
-float cameraOrientationAngles[2] = {-0.475f, -0.35f}; // Spherical angles (theta, phi).
-
-float translationScale = 0.5f;
-float rotationScale = 0.01f;
-
-// In order to control camera movement, we will
-// use good old WASD
-bool wPressed = false;
-bool aPressed = false;
-bool sPressed = false;
-bool dPressed = false;
-
-bool isMouseDown = false;
-float lastMouseX = 0.0f;
-float lastMouseY = 0.0f;
-
-void setKeyState(platform::KeyCode key, bool state)
-{
- switch (key)
+ ComPtr<gfx::IPipelineState> gPresentPipelineState;
+ ComPtr<gfx::IPipelineState> gRenderPipelineState;
+ ComPtr<gfx::IBufferResource> gFullScreenVertexBuffer;
+ ComPtr<gfx::IBufferResource> gVertexBuffer;
+ ComPtr<gfx::IBufferResource> gIndexBuffer;
+ ComPtr<gfx::IBufferResource> gPrimitiveBuffer;
+ ComPtr<gfx::IBufferResource> gTransformBuffer;
+ ComPtr<gfx::IResourceView> gPrimitiveBufferSRV;
+ ComPtr<gfx::IBufferResource> gInstanceBuffer;
+ ComPtr<gfx::IBufferResource> gBLASBuffer;
+ ComPtr<gfx::IAccelerationStructure> gBLAS;
+ ComPtr<gfx::IBufferResource> gTLASBuffer;
+ ComPtr<gfx::IAccelerationStructure> gTLAS;
+ ComPtr<gfx::ITextureResource> gResultTexture;
+ ComPtr<gfx::IResourceView> gResultTextureUAV;
+ ComPtr<gfx::IShaderTable> gShaderTable;
+
+ uint64_t lastTime = 0;
+
+ // glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10));
+ // glm::vec3 lightColor = glm::vec3(1, 1, 1);
+
+ glm::vec3 cameraPosition = glm::vec3(-2.53f, 2.72f, 4.3f);
+ float cameraOrientationAngles[2] = {-0.475f, -0.35f}; // Spherical angles (theta, phi).
+
+ float translationScale = 0.5f;
+ float rotationScale = 0.01f;
+
+ // In order to control camera movement, we will
+ // use good old WASD
+ bool wPressed = false;
+ bool aPressed = false;
+ bool sPressed = false;
+ bool dPressed = false;
+
+ bool isMouseDown = false;
+ float lastMouseX = 0.0f;
+ float lastMouseY = 0.0f;
+
+ void setKeyState(platform::KeyCode key, bool state)
{
- default:
- break;
- case platform::KeyCode::W:
- wPressed = state;
- break;
- case platform::KeyCode::A:
- aPressed = state;
- break;
- case platform::KeyCode::S:
- sPressed = state;
- break;
- case platform::KeyCode::D:
- dPressed = state;
- break;
+ switch (key)
+ {
+ default: break;
+ case platform::KeyCode::W: wPressed = state; break;
+ case platform::KeyCode::A: aPressed = state; break;
+ case platform::KeyCode::S: sPressed = state; break;
+ case platform::KeyCode::D: dPressed = state; break;
+ }
}
-}
-void onKeyDown(platform::KeyEventArgs args) { setKeyState(args.key, true); }
-void onKeyUp(platform::KeyEventArgs args) { setKeyState(args.key, false); }
+ void onKeyDown(platform::KeyEventArgs args) { setKeyState(args.key, true); }
+ void onKeyUp(platform::KeyEventArgs args) { setKeyState(args.key, false); }
-void onMouseDown(platform::MouseEventArgs args)
-{
- isMouseDown = true;
- lastMouseX = (float)args.x;
- lastMouseY = (float)args.y;
-}
-
-void onMouseMove(platform::MouseEventArgs args)
-{
- if (isMouseDown)
+ void onMouseDown(platform::MouseEventArgs args)
{
- float deltaX = args.x - lastMouseX;
- float deltaY = args.y - lastMouseY;
-
- cameraOrientationAngles[0] += -deltaX * rotationScale;
- cameraOrientationAngles[1] += -deltaY * rotationScale;
+ isMouseDown = true;
lastMouseX = (float)args.x;
lastMouseY = (float)args.y;
}
-}
-void onMouseUp(platform::MouseEventArgs args) { isMouseDown = false; }
-Slang::Result initialize()
-{
- initializeBase("Ray Tracing Pipeline", 1024, 768);
- if (!isTestMode())
+ void onMouseMove(platform::MouseEventArgs args)
{
- gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { onMouseMove(e); };
- gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); };
- gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { onMouseDown(e); };
- gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); };
- gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); };
+ if (isMouseDown)
+ {
+ float deltaX = args.x - lastMouseX;
+ float deltaY = args.y - lastMouseY;
+
+ cameraOrientationAngles[0] += -deltaX * rotationScale;
+ cameraOrientationAngles[1] += -deltaY * rotationScale;
+ lastMouseX = (float)args.x;
+ lastMouseY = (float)args.y;
+ }
}
+ void onMouseUp(platform::MouseEventArgs args) { isMouseDown = false; }
- IBufferResource::Desc vertexBufferDesc;
- vertexBufferDesc.type = IResource::Type::Buffer;
- vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex);
- vertexBufferDesc.defaultState = ResourceState::ShaderResource;
- gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]);
- if(!gVertexBuffer) return SLANG_FAIL;
-
- IBufferResource::Desc indexBufferDesc;
- indexBufferDesc.type = IResource::Type::Buffer;
- indexBufferDesc.sizeInBytes = kIndexCount * sizeof(int32_t);
- indexBufferDesc.defaultState = ResourceState::ShaderResource;
- gIndexBuffer = gDevice->createBufferResource(indexBufferDesc, &kIndexData[0]);
- if (!gIndexBuffer)
- return SLANG_FAIL;
-
- IBufferResource::Desc primitiveBufferDesc;
- primitiveBufferDesc.type = IResource::Type::Buffer;
- primitiveBufferDesc.sizeInBytes = kPrimitiveCount * sizeof(Primitive);
- primitiveBufferDesc.elementSize = sizeof(Primitive);
- primitiveBufferDesc.defaultState = ResourceState::ShaderResource;
- gPrimitiveBuffer = gDevice->createBufferResource(primitiveBufferDesc, &kPrimitiveData[0]);
- if (!gPrimitiveBuffer)
- return SLANG_FAIL;
-
- IResourceView::Desc primitiveSRVDesc = {};
- primitiveSRVDesc.format = Format::Unknown;
- primitiveSRVDesc.type = IResourceView::Type::ShaderResource;
- gPrimitiveBufferSRV = gDevice->createBufferView(gPrimitiveBuffer, nullptr, primitiveSRVDesc);
-
- IBufferResource::Desc transformBufferDesc;
- transformBufferDesc.type = IResource::Type::Buffer;
- transformBufferDesc.sizeInBytes = sizeof(float) * 12;
- transformBufferDesc.defaultState = ResourceState::ShaderResource;
- float transformData[12] = {
- 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};
- gTransformBuffer = gDevice->createBufferResource(transformBufferDesc, &transformData);
- if (!gTransformBuffer)
- return SLANG_FAIL;
- // Build bottom level acceleration structure.
+ Slang::Result initialize()
{
- IAccelerationStructure::BuildInputs accelerationStructureBuildInputs;
- IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo;
- accelerationStructureBuildInputs.descCount = 1;
- accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::BottomLevel;
- accelerationStructureBuildInputs.flags =
- IAccelerationStructure::BuildFlags::AllowCompaction;
- IAccelerationStructure::GeometryDesc geomDesc;
- geomDesc.flags = IAccelerationStructure::GeometryFlags::Opaque;
- geomDesc.type = IAccelerationStructure::GeometryType::Triangles;
- geomDesc.content.triangles.indexCount = kIndexCount;
- geomDesc.content.triangles.indexData = gIndexBuffer->getDeviceAddress();
- geomDesc.content.triangles.indexFormat = Format::R32_UINT;
- geomDesc.content.triangles.vertexCount = kVertexCount;
- geomDesc.content.triangles.vertexData = gVertexBuffer->getDeviceAddress();
- geomDesc.content.triangles.vertexFormat = Format::R32G32B32_FLOAT;
- geomDesc.content.triangles.vertexStride = sizeof(Vertex);
- geomDesc.content.triangles.transform3x4 = gTransformBuffer->getDeviceAddress();
- accelerationStructureBuildInputs.geometryDescs = &geomDesc;
-
- // Query buffer size for acceleration structure build.
- SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo(
- accelerationStructureBuildInputs, &accelerationStructurePrebuildInfo));
- // Allocate buffers for acceleration structure.
- IBufferResource::Desc asDraftBufferDesc;
- asDraftBufferDesc.type = IResource::Type::Buffer;
- asDraftBufferDesc.defaultState = ResourceState::AccelerationStructure;
- asDraftBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize;
- ComPtr<IBufferResource> draftBuffer = gDevice->createBufferResource(asDraftBufferDesc);
- IBufferResource::Desc scratchBufferDesc;
- scratchBufferDesc.type = IResource::Type::Buffer;
- scratchBufferDesc.defaultState = ResourceState::UnorderedAccess;
- scratchBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.scratchDataSize;
- ComPtr<IBufferResource> scratchBuffer = gDevice->createBufferResource(scratchBufferDesc);
-
- // Build acceleration structure.
- ComPtr<IQueryPool> compactedSizeQuery;
- IQueryPool::Desc queryPoolDesc;
- queryPoolDesc.count = 1;
- queryPoolDesc.type = QueryType::AccelerationStructureCompactedSize;
- SLANG_RETURN_ON_FAIL(
- gDevice->createQueryPool(queryPoolDesc, compactedSizeQuery.writeRef()));
-
- ComPtr<IAccelerationStructure> draftAS;
- IAccelerationStructure::CreateDesc draftCreateDesc;
- draftCreateDesc.buffer = draftBuffer;
- draftCreateDesc.kind = IAccelerationStructure::Kind::BottomLevel;
- draftCreateDesc.offset = 0;
- draftCreateDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize;
- SLANG_RETURN_ON_FAIL(
- gDevice->createAccelerationStructure(draftCreateDesc, draftAS.writeRef()));
-
- compactedSizeQuery->reset();
-
- auto commandBuffer = gTransientHeaps[0]->createCommandBuffer();
- auto encoder = commandBuffer->encodeRayTracingCommands();
- IAccelerationStructure::BuildDesc buildDesc = {};
- buildDesc.dest = draftAS;
- buildDesc.inputs = accelerationStructureBuildInputs;
- buildDesc.scratchData = scratchBuffer->getDeviceAddress();
- AccelerationStructureQueryDesc compactedSizeQueryDesc = {};
- compactedSizeQueryDesc.queryPool = compactedSizeQuery;
- compactedSizeQueryDesc.queryType = QueryType::AccelerationStructureCompactedSize;
- encoder->buildAccelerationStructure(buildDesc, 1, &compactedSizeQueryDesc);
- encoder->endEncoding();
- commandBuffer->close();
- gQueue->executeCommandBuffer(commandBuffer);
- gQueue->waitOnHost();
-
- uint64_t compactedSize = 0;
- compactedSizeQuery->getResult(0, 1, &compactedSize);
- IBufferResource::Desc asBufferDesc;
- asBufferDesc.type = IResource::Type::Buffer;
- asBufferDesc.defaultState = ResourceState::AccelerationStructure;
- asBufferDesc.sizeInBytes = (size_t)compactedSize;
- gBLASBuffer = gDevice->createBufferResource(asBufferDesc);
- IAccelerationStructure::CreateDesc createDesc;
- createDesc.buffer = gBLASBuffer;
- createDesc.kind = IAccelerationStructure::Kind::BottomLevel;
- createDesc.offset = 0;
- createDesc.size = (size_t)compactedSize;
- gDevice->createAccelerationStructure(createDesc, gBLAS.writeRef());
-
- commandBuffer = gTransientHeaps[0]->createCommandBuffer();
- encoder = commandBuffer->encodeRayTracingCommands();
- encoder->copyAccelerationStructure(gBLAS, draftAS, AccelerationStructureCopyMode::Compact);
- encoder->endEncoding();
- commandBuffer->close();
- gQueue->executeCommandBuffer(commandBuffer);
- gQueue->waitOnHost();
- }
+ initializeBase("Ray Tracing Pipeline", 1024, 768);
+ if (!isTestMode())
+ {
+ gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e)
+ { onMouseMove(e); };
+ gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); };
+ gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e)
+ { onMouseDown(e); };
+ gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); };
+ gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); };
+ }
+
+ IBufferResource::Desc vertexBufferDesc;
+ vertexBufferDesc.type = IResource::Type::Buffer;
+ vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex);
+ vertexBufferDesc.defaultState = ResourceState::ShaderResource;
+ gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]);
+ if (!gVertexBuffer)
+ return SLANG_FAIL;
- // Build top level acceleration structure.
- {
- List<IAccelerationStructure::InstanceDesc> instanceDescs;
- instanceDescs.setCount(1);
- instanceDescs[0].accelerationStructure = gBLAS->getDeviceAddress();
- instanceDescs[0].flags =
- IAccelerationStructure::GeometryInstanceFlags::TriangleFacingCullDisable;
- instanceDescs[0].instanceContributionToHitGroupIndex = 0;
- instanceDescs[0].instanceID = 0;
- instanceDescs[0].instanceMask = 0xFF;
- float transformMatrix[] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};
- memcpy(&instanceDescs[0].transform[0][0], transformMatrix, sizeof(float) * 12);
-
- IBufferResource::Desc instanceBufferDesc;
- instanceBufferDesc.type = IResource::Type::Buffer;
- instanceBufferDesc.sizeInBytes =
- instanceDescs.getCount() * sizeof(IAccelerationStructure::InstanceDesc);
- instanceBufferDesc.defaultState = ResourceState::ShaderResource;
- gInstanceBuffer = gDevice->createBufferResource(instanceBufferDesc, instanceDescs.getBuffer());
- if (!gInstanceBuffer)
+ IBufferResource::Desc indexBufferDesc;
+ indexBufferDesc.type = IResource::Type::Buffer;
+ indexBufferDesc.sizeInBytes = kIndexCount * sizeof(int32_t);
+ indexBufferDesc.defaultState = ResourceState::ShaderResource;
+ gIndexBuffer = gDevice->createBufferResource(indexBufferDesc, &kIndexData[0]);
+ if (!gIndexBuffer)
return SLANG_FAIL;
- IAccelerationStructure::BuildInputs accelerationStructureBuildInputs = {};
- IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo = {};
- accelerationStructureBuildInputs.descCount = 1;
- accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::TopLevel;
- accelerationStructureBuildInputs.instanceDescs = gInstanceBuffer->getDeviceAddress();
-
- // Query buffer size for acceleration structure build.
- SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo(
- accelerationStructureBuildInputs, &accelerationStructurePrebuildInfo));
-
- IBufferResource::Desc asBufferDesc;
- asBufferDesc.type = IResource::Type::Buffer;
- asBufferDesc.defaultState = ResourceState::AccelerationStructure;
- asBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize;
- gTLASBuffer = gDevice->createBufferResource(asBufferDesc);
-
- IBufferResource::Desc scratchBufferDesc;
- scratchBufferDesc.type = IResource::Type::Buffer;
- scratchBufferDesc.defaultState = ResourceState::UnorderedAccess;
- scratchBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.scratchDataSize;
- ComPtr<IBufferResource> scratchBuffer = gDevice->createBufferResource(scratchBufferDesc);
-
- IAccelerationStructure::CreateDesc createDesc;
- createDesc.buffer = gTLASBuffer;
- createDesc.kind = IAccelerationStructure::Kind::TopLevel;
- createDesc.offset = 0;
- createDesc.size = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize;
- SLANG_RETURN_ON_FAIL(gDevice->createAccelerationStructure(createDesc, gTLAS.writeRef()));
-
- auto commandBuffer = gTransientHeaps[0]->createCommandBuffer();
- auto encoder = commandBuffer->encodeRayTracingCommands();
- IAccelerationStructure::BuildDesc buildDesc = {};
- buildDesc.dest = gTLAS;
- buildDesc.inputs = accelerationStructureBuildInputs;
- buildDesc.scratchData = scratchBuffer->getDeviceAddress();
- encoder->buildAccelerationStructure(buildDesc, 0, nullptr);
- encoder->endEncoding();
- commandBuffer->close();
- gQueue->executeCommandBuffer(commandBuffer);
- gQueue->waitOnHost();
- }
+ IBufferResource::Desc primitiveBufferDesc;
+ primitiveBufferDesc.type = IResource::Type::Buffer;
+ primitiveBufferDesc.sizeInBytes = kPrimitiveCount * sizeof(Primitive);
+ primitiveBufferDesc.elementSize = sizeof(Primitive);
+ primitiveBufferDesc.defaultState = ResourceState::ShaderResource;
+ gPrimitiveBuffer = gDevice->createBufferResource(primitiveBufferDesc, &kPrimitiveData[0]);
+ if (!gPrimitiveBuffer)
+ return SLANG_FAIL;
- IBufferResource::Desc fullScreenVertexBufferDesc;
- fullScreenVertexBufferDesc.type = IResource::Type::Buffer;
- fullScreenVertexBufferDesc.sizeInBytes =
- FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex);
- fullScreenVertexBufferDesc.defaultState = ResourceState::VertexBuffer;
- gFullScreenVertexBuffer = gDevice->createBufferResource(
- fullScreenVertexBufferDesc, &FullScreenTriangle::kVertices[0]);
- if (!gFullScreenVertexBuffer)
- return SLANG_FAIL;
-
- InputElementDesc inputElements[] = {
- {"POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position)},
- };
- auto inputLayout = gDevice->createInputLayout(sizeof(FullScreenTriangle::Vertex), &inputElements[0], SLANG_COUNT_OF(inputElements));
- if (!inputLayout)
- return SLANG_FAIL;
-
- ComPtr<IShaderProgram> shaderProgram;
- SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, false, shaderProgram.writeRef()));
- GraphicsPipelineStateDesc desc;
- desc.inputLayout = inputLayout;
- desc.program = shaderProgram;
- desc.framebufferLayout = gFramebufferLayout;
- gPresentPipelineState = gDevice->createGraphicsPipelineState(desc);
- if (!gPresentPipelineState)
- return SLANG_FAIL;
-
- const char* hitgroupNames[] = {"hitgroup0", "hitgroup1"};
-
- ComPtr<IShaderProgram> rayTracingProgram;
- SLANG_RETURN_ON_FAIL(
- loadShaderProgram(gDevice, true, rayTracingProgram.writeRef()));
- RayTracingPipelineStateDesc rtpDesc = {};
- rtpDesc.program = rayTracingProgram;
- rtpDesc.hitGroupCount = 2;
- HitGroupDesc hitGroups[2];
- hitGroups[0].closestHitEntryPoint = "closestHitShader";
- hitGroups[0].hitGroupName = hitgroupNames[0];
- hitGroups[1].closestHitEntryPoint = "shadowRayHitShader";
- hitGroups[1].hitGroupName = hitgroupNames[1];
- rtpDesc.hitGroups = hitGroups;
- rtpDesc.maxRayPayloadSize = 64;
- rtpDesc.maxRecursion = 2;
- SLANG_RETURN_ON_FAIL(
- gDevice->createRayTracingPipelineState(rtpDesc, gRenderPipelineState.writeRef()));
- if (!gRenderPipelineState)
- return SLANG_FAIL;
-
- IShaderTable::Desc shaderTableDesc = {};
- const char* raygenName = "rayGenShader";
- const char* missName = "missShader";
- shaderTableDesc.program = rayTracingProgram;
- shaderTableDesc.hitGroupCount = 2;
- shaderTableDesc.hitGroupNames = hitgroupNames;
- shaderTableDesc.rayGenShaderCount = 1;
- shaderTableDesc.rayGenShaderEntryPointNames = &raygenName;
- shaderTableDesc.missShaderCount = 1;
- shaderTableDesc.missShaderEntryPointNames = &missName;
- SLANG_RETURN_ON_FAIL(gDevice->createShaderTable(shaderTableDesc, gShaderTable.writeRef()));
-
- createResultTexture();
- return SLANG_OK;
-}
-
-void createResultTexture()
-{
- ITextureResource::Desc resultTextureDesc = {};
- resultTextureDesc.type = IResource::Type::Texture2D;
- resultTextureDesc.numMipLevels = 1;
- resultTextureDesc.size.width = windowWidth;
- resultTextureDesc.size.height = windowHeight;
- resultTextureDesc.size.depth = 1;
- resultTextureDesc.defaultState = ResourceState::UnorderedAccess;
- resultTextureDesc.format = Format::R16G16B16A16_FLOAT;
- gResultTexture = gDevice->createTextureResource(resultTextureDesc);
- IResourceView::Desc resultUAVDesc = {};
- resultUAVDesc.format = resultTextureDesc.format;
- resultUAVDesc.type = IResourceView::Type::UnorderedAccess;
- gResultTextureUAV = gDevice->createTextureView(gResultTexture, resultUAVDesc);
-}
-
-virtual void windowSizeChanged() override
-{
- WindowedAppBase::windowSizeChanged();
- createResultTexture();
-}
+ IResourceView::Desc primitiveSRVDesc = {};
+ primitiveSRVDesc.format = Format::Unknown;
+ primitiveSRVDesc.type = IResourceView::Type::ShaderResource;
+ gPrimitiveBufferSRV =
+ gDevice->createBufferView(gPrimitiveBuffer, nullptr, primitiveSRVDesc);
+
+ IBufferResource::Desc transformBufferDesc;
+ transformBufferDesc.type = IResource::Type::Buffer;
+ transformBufferDesc.sizeInBytes = sizeof(float) * 12;
+ transformBufferDesc.defaultState = ResourceState::ShaderResource;
+ float transformData[12] =
+ {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};
+ gTransformBuffer = gDevice->createBufferResource(transformBufferDesc, &transformData);
+ if (!gTransformBuffer)
+ return SLANG_FAIL;
+ // Build bottom level acceleration structure.
+ {
+ IAccelerationStructure::BuildInputs accelerationStructureBuildInputs;
+ IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo;
+ accelerationStructureBuildInputs.descCount = 1;
+ accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::BottomLevel;
+ accelerationStructureBuildInputs.flags =
+ IAccelerationStructure::BuildFlags::AllowCompaction;
+ IAccelerationStructure::GeometryDesc geomDesc;
+ geomDesc.flags = IAccelerationStructure::GeometryFlags::Opaque;
+ geomDesc.type = IAccelerationStructure::GeometryType::Triangles;
+ geomDesc.content.triangles.indexCount = kIndexCount;
+ geomDesc.content.triangles.indexData = gIndexBuffer->getDeviceAddress();
+ geomDesc.content.triangles.indexFormat = Format::R32_UINT;
+ geomDesc.content.triangles.vertexCount = kVertexCount;
+ geomDesc.content.triangles.vertexData = gVertexBuffer->getDeviceAddress();
+ geomDesc.content.triangles.vertexFormat = Format::R32G32B32_FLOAT;
+ geomDesc.content.triangles.vertexStride = sizeof(Vertex);
+ geomDesc.content.triangles.transform3x4 = gTransformBuffer->getDeviceAddress();
+ accelerationStructureBuildInputs.geometryDescs = &geomDesc;
+
+ // Query buffer size for acceleration structure build.
+ SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo(
+ accelerationStructureBuildInputs,
+ &accelerationStructurePrebuildInfo));
+ // Allocate buffers for acceleration structure.
+ IBufferResource::Desc asDraftBufferDesc;
+ asDraftBufferDesc.type = IResource::Type::Buffer;
+ asDraftBufferDesc.defaultState = ResourceState::AccelerationStructure;
+ asDraftBufferDesc.sizeInBytes =
+ (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize;
+ ComPtr<IBufferResource> draftBuffer = gDevice->createBufferResource(asDraftBufferDesc);
+ IBufferResource::Desc scratchBufferDesc;
+ scratchBufferDesc.type = IResource::Type::Buffer;
+ scratchBufferDesc.defaultState = ResourceState::UnorderedAccess;
+ scratchBufferDesc.sizeInBytes =
+ (size_t)accelerationStructurePrebuildInfo.scratchDataSize;
+ ComPtr<IBufferResource> scratchBuffer =
+ gDevice->createBufferResource(scratchBufferDesc);
+
+ // Build acceleration structure.
+ ComPtr<IQueryPool> compactedSizeQuery;
+ IQueryPool::Desc queryPoolDesc;
+ queryPoolDesc.count = 1;
+ queryPoolDesc.type = QueryType::AccelerationStructureCompactedSize;
+ SLANG_RETURN_ON_FAIL(
+ gDevice->createQueryPool(queryPoolDesc, compactedSizeQuery.writeRef()));
+
+ ComPtr<IAccelerationStructure> draftAS;
+ IAccelerationStructure::CreateDesc draftCreateDesc;
+ draftCreateDesc.buffer = draftBuffer;
+ draftCreateDesc.kind = IAccelerationStructure::Kind::BottomLevel;
+ draftCreateDesc.offset = 0;
+ draftCreateDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize;
+ SLANG_RETURN_ON_FAIL(
+ gDevice->createAccelerationStructure(draftCreateDesc, draftAS.writeRef()));
+
+ compactedSizeQuery->reset();
+
+ auto commandBuffer = gTransientHeaps[0]->createCommandBuffer();
+ auto encoder = commandBuffer->encodeRayTracingCommands();
+ IAccelerationStructure::BuildDesc buildDesc = {};
+ buildDesc.dest = draftAS;
+ buildDesc.inputs = accelerationStructureBuildInputs;
+ buildDesc.scratchData = scratchBuffer->getDeviceAddress();
+ AccelerationStructureQueryDesc compactedSizeQueryDesc = {};
+ compactedSizeQueryDesc.queryPool = compactedSizeQuery;
+ compactedSizeQueryDesc.queryType = QueryType::AccelerationStructureCompactedSize;
+ encoder->buildAccelerationStructure(buildDesc, 1, &compactedSizeQueryDesc);
+ encoder->endEncoding();
+ commandBuffer->close();
+ gQueue->executeCommandBuffer(commandBuffer);
+ gQueue->waitOnHost();
+
+ uint64_t compactedSize = 0;
+ compactedSizeQuery->getResult(0, 1, &compactedSize);
+ IBufferResource::Desc asBufferDesc;
+ asBufferDesc.type = IResource::Type::Buffer;
+ asBufferDesc.defaultState = ResourceState::AccelerationStructure;
+ asBufferDesc.sizeInBytes = (size_t)compactedSize;
+ gBLASBuffer = gDevice->createBufferResource(asBufferDesc);
+ IAccelerationStructure::CreateDesc createDesc;
+ createDesc.buffer = gBLASBuffer;
+ createDesc.kind = IAccelerationStructure::Kind::BottomLevel;
+ createDesc.offset = 0;
+ createDesc.size = (size_t)compactedSize;
+ gDevice->createAccelerationStructure(createDesc, gBLAS.writeRef());
+
+ commandBuffer = gTransientHeaps[0]->createCommandBuffer();
+ encoder = commandBuffer->encodeRayTracingCommands();
+ encoder->copyAccelerationStructure(
+ gBLAS,
+ draftAS,
+ AccelerationStructureCopyMode::Compact);
+ encoder->endEncoding();
+ commandBuffer->close();
+ gQueue->executeCommandBuffer(commandBuffer);
+ gQueue->waitOnHost();
+ }
+
+ // Build top level acceleration structure.
+ {
+ List<IAccelerationStructure::InstanceDesc> instanceDescs;
+ instanceDescs.setCount(1);
+ instanceDescs[0].accelerationStructure = gBLAS->getDeviceAddress();
+ instanceDescs[0].flags =
+ IAccelerationStructure::GeometryInstanceFlags::TriangleFacingCullDisable;
+ instanceDescs[0].instanceContributionToHitGroupIndex = 0;
+ instanceDescs[0].instanceID = 0;
+ instanceDescs[0].instanceMask = 0xFF;
+ float transformMatrix[] =
+ {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};
+ memcpy(&instanceDescs[0].transform[0][0], transformMatrix, sizeof(float) * 12);
+
+ IBufferResource::Desc instanceBufferDesc;
+ instanceBufferDesc.type = IResource::Type::Buffer;
+ instanceBufferDesc.sizeInBytes =
+ instanceDescs.getCount() * sizeof(IAccelerationStructure::InstanceDesc);
+ instanceBufferDesc.defaultState = ResourceState::ShaderResource;
+ gInstanceBuffer =
+ gDevice->createBufferResource(instanceBufferDesc, instanceDescs.getBuffer());
+ if (!gInstanceBuffer)
+ return SLANG_FAIL;
+
+ IAccelerationStructure::BuildInputs accelerationStructureBuildInputs = {};
+ IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo = {};
+ accelerationStructureBuildInputs.descCount = 1;
+ accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::TopLevel;
+ accelerationStructureBuildInputs.instanceDescs = gInstanceBuffer->getDeviceAddress();
+
+ // Query buffer size for acceleration structure build.
+ SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo(
+ accelerationStructureBuildInputs,
+ &accelerationStructurePrebuildInfo));
+
+ IBufferResource::Desc asBufferDesc;
+ asBufferDesc.type = IResource::Type::Buffer;
+ asBufferDesc.defaultState = ResourceState::AccelerationStructure;
+ asBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize;
+ gTLASBuffer = gDevice->createBufferResource(asBufferDesc);
+
+ IBufferResource::Desc scratchBufferDesc;
+ scratchBufferDesc.type = IResource::Type::Buffer;
+ scratchBufferDesc.defaultState = ResourceState::UnorderedAccess;
+ scratchBufferDesc.sizeInBytes =
+ (size_t)accelerationStructurePrebuildInfo.scratchDataSize;
+ ComPtr<IBufferResource> scratchBuffer =
+ gDevice->createBufferResource(scratchBufferDesc);
+
+ IAccelerationStructure::CreateDesc createDesc;
+ createDesc.buffer = gTLASBuffer;
+ createDesc.kind = IAccelerationStructure::Kind::TopLevel;
+ createDesc.offset = 0;
+ createDesc.size = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize;
+ SLANG_RETURN_ON_FAIL(
+ gDevice->createAccelerationStructure(createDesc, gTLAS.writeRef()));
+
+ auto commandBuffer = gTransientHeaps[0]->createCommandBuffer();
+ auto encoder = commandBuffer->encodeRayTracingCommands();
+ IAccelerationStructure::BuildDesc buildDesc = {};
+ buildDesc.dest = gTLAS;
+ buildDesc.inputs = accelerationStructureBuildInputs;
+ buildDesc.scratchData = scratchBuffer->getDeviceAddress();
+ encoder->buildAccelerationStructure(buildDesc, 0, nullptr);
+ encoder->endEncoding();
+ commandBuffer->close();
+ gQueue->executeCommandBuffer(commandBuffer);
+ gQueue->waitOnHost();
+ }
+
+ IBufferResource::Desc fullScreenVertexBufferDesc;
+ fullScreenVertexBufferDesc.type = IResource::Type::Buffer;
+ fullScreenVertexBufferDesc.sizeInBytes =
+ FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex);
+ fullScreenVertexBufferDesc.defaultState = ResourceState::VertexBuffer;
+ gFullScreenVertexBuffer = gDevice->createBufferResource(
+ fullScreenVertexBufferDesc,
+ &FullScreenTriangle::kVertices[0]);
+ if (!gFullScreenVertexBuffer)
+ return SLANG_FAIL;
-glm::vec3 getVectorFromSphericalAngles(float theta, float phi)
-{
- auto sinTheta = sin(theta);
- auto cosTheta = cos(theta);
- auto sinPhi = sin(phi);
- auto cosPhi = cos(phi);
- return glm::vec3(-sinTheta * cosPhi, sinPhi, -cosTheta * cosPhi);
-}
-void updateUniforms()
-{
- gUniforms.screenWidth = (float)windowWidth;
- gUniforms.screenHeight = (float)windowHeight;
- if (!lastTime)
- lastTime = getCurrentTime();
- uint64_t currentTime = getCurrentTime();
- float deltaTime = float(double(currentTime - lastTime) / double(getTimerFrequency()));
- lastTime = currentTime;
-
- auto camDir =
- getVectorFromSphericalAngles(cameraOrientationAngles[0], cameraOrientationAngles[1]);
- auto camUp = getVectorFromSphericalAngles(
- cameraOrientationAngles[0], cameraOrientationAngles[1] + glm::pi<float>() * 0.5f);
- auto camRight = glm::cross(camDir, camUp);
-
- glm::vec3 movement = glm::vec3(0);
- if (wPressed)
- movement += camDir;
- if (sPressed)
- movement -= camDir;
- if (aPressed)
- movement -= camRight;
- if (dPressed)
- movement += camRight;
-
- cameraPosition += deltaTime * translationScale * movement;
-
- memcpy(gUniforms.cameraDir, &camDir, sizeof(float) * 3);
- memcpy(gUniforms.cameraUp, &camUp, sizeof(float) * 3);
- memcpy(gUniforms.cameraRight, &camRight, sizeof(float) * 3);
- memcpy(gUniforms.cameraPosition, &cameraPosition, sizeof(float) * 3);
- auto lightDir = glm::normalize(glm::vec3(1.0f, 3.0f, 2.0f));
- memcpy(gUniforms.lightDir, &lightDir, sizeof(float) * 3);
-}
-
-virtual void renderFrame(int frameBufferIndex) override
-{
- updateUniforms();
+ InputElementDesc inputElements[] = {
+ {"POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position)},
+ };
+ auto inputLayout = gDevice->createInputLayout(
+ sizeof(FullScreenTriangle::Vertex),
+ &inputElements[0],
+ SLANG_COUNT_OF(inputElements));
+ if (!inputLayout)
+ return SLANG_FAIL;
+
+ ComPtr<IShaderProgram> shaderProgram;
+ SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, false, shaderProgram.writeRef()));
+ GraphicsPipelineStateDesc desc;
+ desc.inputLayout = inputLayout;
+ desc.program = shaderProgram;
+ desc.framebufferLayout = gFramebufferLayout;
+ gPresentPipelineState = gDevice->createGraphicsPipelineState(desc);
+ if (!gPresentPipelineState)
+ return SLANG_FAIL;
+
+ const char* hitgroupNames[] = {"hitgroup0", "hitgroup1"};
+
+ ComPtr<IShaderProgram> rayTracingProgram;
+ SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, true, rayTracingProgram.writeRef()));
+ RayTracingPipelineStateDesc rtpDesc = {};
+ rtpDesc.program = rayTracingProgram;
+ rtpDesc.hitGroupCount = 2;
+ HitGroupDesc hitGroups[2];
+ hitGroups[0].closestHitEntryPoint = "closestHitShader";
+ hitGroups[0].hitGroupName = hitgroupNames[0];
+ hitGroups[1].closestHitEntryPoint = "shadowRayHitShader";
+ hitGroups[1].hitGroupName = hitgroupNames[1];
+ rtpDesc.hitGroups = hitGroups;
+ rtpDesc.maxRayPayloadSize = 64;
+ rtpDesc.maxRecursion = 2;
+ SLANG_RETURN_ON_FAIL(
+ gDevice->createRayTracingPipelineState(rtpDesc, gRenderPipelineState.writeRef()));
+ if (!gRenderPipelineState)
+ return SLANG_FAIL;
+
+ IShaderTable::Desc shaderTableDesc = {};
+ const char* raygenName = "rayGenShader";
+ const char* missName = "missShader";
+ shaderTableDesc.program = rayTracingProgram;
+ shaderTableDesc.hitGroupCount = 2;
+ shaderTableDesc.hitGroupNames = hitgroupNames;
+ shaderTableDesc.rayGenShaderCount = 1;
+ shaderTableDesc.rayGenShaderEntryPointNames = &raygenName;
+ shaderTableDesc.missShaderCount = 1;
+ shaderTableDesc.missShaderEntryPointNames = &missName;
+ SLANG_RETURN_ON_FAIL(gDevice->createShaderTable(shaderTableDesc, gShaderTable.writeRef()));
+
+ createResultTexture();
+ return SLANG_OK;
+ }
+
+ void createResultTexture()
{
- ComPtr<ICommandBuffer> renderCommandBuffer =
- gTransientHeaps[frameBufferIndex]->createCommandBuffer();
- auto renderEncoder = renderCommandBuffer->encodeRayTracingCommands();
- IShaderObject* rootObject = nullptr;
- renderEncoder->bindPipeline(gRenderPipelineState, &rootObject);
- auto cursor = ShaderCursor(rootObject);
- cursor["resultTexture"].setResource(gResultTextureUAV);
- cursor["uniforms"].setData(&gUniforms, sizeof(Uniforms));
- cursor["sceneBVH"].setResource(gTLAS);
- cursor["primitiveBuffer"].setResource(gPrimitiveBufferSRV);
- renderEncoder->dispatchRays(0, gShaderTable, windowWidth, windowHeight, 1);
- renderEncoder->endEncoding();
- renderCommandBuffer->close();
- gQueue->executeCommandBuffer(renderCommandBuffer);
+ ITextureResource::Desc resultTextureDesc = {};
+ resultTextureDesc.type = IResource::Type::Texture2D;
+ resultTextureDesc.numMipLevels = 1;
+ resultTextureDesc.size.width = windowWidth;
+ resultTextureDesc.size.height = windowHeight;
+ resultTextureDesc.size.depth = 1;
+ resultTextureDesc.defaultState = ResourceState::UnorderedAccess;
+ resultTextureDesc.format = Format::R16G16B16A16_FLOAT;
+ gResultTexture = gDevice->createTextureResource(resultTextureDesc);
+ IResourceView::Desc resultUAVDesc = {};
+ resultUAVDesc.format = resultTextureDesc.format;
+ resultUAVDesc.type = IResourceView::Type::UnorderedAccess;
+ gResultTextureUAV = gDevice->createTextureView(gResultTexture, resultUAVDesc);
}
+ virtual void windowSizeChanged() override
{
- ComPtr<ICommandBuffer> presentCommandBuffer =
- gTransientHeaps[frameBufferIndex]->createCommandBuffer();
- auto presentEncoder = presentCommandBuffer->encodeRenderCommands(
- gRenderPass, gFramebuffers[frameBufferIndex]);
- gfx::Viewport viewport = {};
- viewport.maxZ = 1.0f;
- viewport.extentX = (float)windowWidth;
- viewport.extentY = (float)windowHeight;
- presentEncoder->setViewportAndScissor(viewport);
- auto rootObject = presentEncoder->bindPipeline(gPresentPipelineState);
- auto cursor = ShaderCursor(rootObject->getEntryPoint(1));
- cursor["t"].setResource(gResultTextureUAV);
- presentEncoder->setVertexBuffer(
- 0, gFullScreenVertexBuffer);
- presentEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList);
- presentEncoder->draw(3);
- presentEncoder->endEncoding();
- presentCommandBuffer->close();
- gQueue->executeCommandBuffer(presentCommandBuffer);
+ WindowedAppBase::windowSizeChanged();
+ createResultTexture();
}
- if (!isTestMode())
+ glm::vec3 getVectorFromSphericalAngles(float theta, float phi)
{
- // With that, we are done drawing for one frame, and ready for the next.
- //
- gSwapchain->present();
+ auto sinTheta = sin(theta);
+ auto cosTheta = cos(theta);
+ auto sinPhi = sin(phi);
+ auto cosPhi = cos(phi);
+ return glm::vec3(-sinTheta * cosPhi, sinPhi, -cosTheta * cosPhi);
+ }
+ void updateUniforms()
+ {
+ gUniforms.screenWidth = (float)windowWidth;
+ gUniforms.screenHeight = (float)windowHeight;
+ if (!lastTime)
+ lastTime = getCurrentTime();
+ uint64_t currentTime = getCurrentTime();
+ float deltaTime = float(double(currentTime - lastTime) / double(getTimerFrequency()));
+ lastTime = currentTime;
+
+ auto camDir =
+ getVectorFromSphericalAngles(cameraOrientationAngles[0], cameraOrientationAngles[1]);
+ auto camUp = getVectorFromSphericalAngles(
+ cameraOrientationAngles[0],
+ cameraOrientationAngles[1] + glm::pi<float>() * 0.5f);
+ auto camRight = glm::cross(camDir, camUp);
+
+ glm::vec3 movement = glm::vec3(0);
+ if (wPressed)
+ movement += camDir;
+ if (sPressed)
+ movement -= camDir;
+ if (aPressed)
+ movement -= camRight;
+ if (dPressed)
+ movement += camRight;
+
+ cameraPosition += deltaTime * translationScale * movement;
+
+ memcpy(gUniforms.cameraDir, &camDir, sizeof(float) * 3);
+ memcpy(gUniforms.cameraUp, &camUp, sizeof(float) * 3);
+ memcpy(gUniforms.cameraRight, &camRight, sizeof(float) * 3);
+ memcpy(gUniforms.cameraPosition, &cameraPosition, sizeof(float) * 3);
+ auto lightDir = glm::normalize(glm::vec3(1.0f, 3.0f, 2.0f));
+ memcpy(gUniforms.lightDir, &lightDir, sizeof(float) * 3);
}
-}
+ virtual void renderFrame(int frameBufferIndex) override
+ {
+ updateUniforms();
+ {
+ ComPtr<ICommandBuffer> renderCommandBuffer =
+ gTransientHeaps[frameBufferIndex]->createCommandBuffer();
+ auto renderEncoder = renderCommandBuffer->encodeRayTracingCommands();
+ IShaderObject* rootObject = nullptr;
+ renderEncoder->bindPipeline(gRenderPipelineState, &rootObject);
+ auto cursor = ShaderCursor(rootObject);
+ cursor["resultTexture"].setResource(gResultTextureUAV);
+ cursor["uniforms"].setData(&gUniforms, sizeof(Uniforms));
+ cursor["sceneBVH"].setResource(gTLAS);
+ cursor["primitiveBuffer"].setResource(gPrimitiveBufferSRV);
+ renderEncoder->dispatchRays(0, gShaderTable, windowWidth, windowHeight, 1);
+ renderEncoder->endEncoding();
+ renderCommandBuffer->close();
+ gQueue->executeCommandBuffer(renderCommandBuffer);
+ }
+
+ {
+ ComPtr<ICommandBuffer> presentCommandBuffer =
+ gTransientHeaps[frameBufferIndex]->createCommandBuffer();
+ auto presentEncoder = presentCommandBuffer->encodeRenderCommands(
+ gRenderPass,
+ gFramebuffers[frameBufferIndex]);
+ gfx::Viewport viewport = {};
+ viewport.maxZ = 1.0f;
+ viewport.extentX = (float)windowWidth;
+ viewport.extentY = (float)windowHeight;
+ presentEncoder->setViewportAndScissor(viewport);
+ auto rootObject = presentEncoder->bindPipeline(gPresentPipelineState);
+ auto cursor = ShaderCursor(rootObject->getEntryPoint(1));
+ cursor["t"].setResource(gResultTextureUAV);
+ presentEncoder->setVertexBuffer(0, gFullScreenVertexBuffer);
+ presentEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList);
+ presentEncoder->draw(3);
+ presentEncoder->endEncoding();
+ presentCommandBuffer->close();
+ gQueue->executeCommandBuffer(presentCommandBuffer);
+ }
+
+ if (!isTestMode())
+ {
+ // With that, we are done drawing for one frame, and ready for the next.
+ //
+ gSwapchain->present();
+ }
+ }
};
// This macro instantiates an appropriate main function to
diff --git a/examples/ray-tracing/main.cpp b/examples/ray-tracing/main.cpp
index 4ec5070d8..22111149c 100644
--- a/examples/ray-tracing/main.cpp
+++ b/examples/ray-tracing/main.cpp
@@ -3,14 +3,14 @@
// This file implements an example of hardware ray-tracing using
// Slang shaders and the `gfx` graphics API.
-#include "slang.h"
-#include "slang-gfx.h"
+#include "examples/example-base/example-base.h"
#include "gfx-util/shader-cursor.h"
-#include "tools/platform/window.h"
-#include "tools/platform/vector-math.h"
#include "slang-com-ptr.h"
+#include "slang-gfx.h"
+#include "slang.h"
#include "source/core/slang-basic.h"
-#include "examples/example-base/example-base.h"
+#include "tools/platform/vector-math.h"
+#include "tools/platform/window.h"
using namespace gfx;
using namespace Slang;
@@ -36,8 +36,7 @@ struct Vertex
// Define geometry data for our test scene.
// The scene contains a floor plane, and a cube placed on top of it at the center.
static const int kVertexCount = 24;
-static const Vertex kVertexData[kVertexCount] =
-{
+static const Vertex kVertexData[kVertexCount] = {
// Floor plane
{{-100.0f, 0, 100.0f}},
{{100.0f, 0, 100.0f}},
@@ -70,15 +69,9 @@ static const Vertex kVertexData[kVertexCount] =
{{1.0f, 0.0, -1.0f}},
};
static const int kIndexCount = 36;
-static const int kIndexData[kIndexCount] =
-{
- 0, 1, 2, 0, 2, 3,
- 4, 5, 6, 4, 6, 7,
- 8, 9, 10, 8, 10, 11,
- 12, 13, 14, 12, 14, 15,
- 16, 17, 18, 16, 18, 19,
- 20, 21, 22, 20, 22, 23
-};
+static const int kIndexData[kIndexCount] = {0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7,
+ 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15,
+ 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23};
struct Primitive
{
@@ -86,8 +79,7 @@ struct Primitive
float color[4];
};
static const int kPrimitiveCount = 12;
-static const Primitive kPrimitiveData[kPrimitiveCount] =
-{
+static const Primitive kPrimitiveData[kPrimitiveCount] = {
{{0.0f, 1.0f, 0.0f, 0.0f}, {0.75f, 0.8f, 0.85f, 1.0f}},
{{0.0f, 1.0f, 0.0f, 0.0f}, {0.75f, 0.8f, 0.85f, 1.0f}},
{{0.0f, 1.0f, 0.0f, 0.0f}, {0.95f, 0.85f, 0.05f, 1.0f}},
@@ -134,525 +126,539 @@ struct RayTracing : public WindowedAppBase
{
-Uniforms gUniforms = {};
+ Uniforms gUniforms = {};
-// Many Slang API functions return detailed diagnostic information
-// (error messages, warnings, etc.) as a "blob" of data, or return
-// a null blob pointer instead if there were no issues.
-//
-// For convenience, we define a subroutine that will dump the information
-// in a diagnostic blob if one is produced, and skip it otherwise.
-//
-void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob)
-{
- if( diagnosticsBlob != nullptr )
+ // Many Slang API functions return detailed diagnostic information
+ // (error messages, warnings, etc.) as a "blob" of data, or return
+ // a null blob pointer instead if there were no issues.
+ //
+ // For convenience, we define a subroutine that will dump the information
+ // in a diagnostic blob if one is produced, and skip it otherwise.
+ //
+ void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob)
{
- printf("%s", (const char*) diagnosticsBlob->getBufferPointer());
+ if (diagnosticsBlob != nullptr)
+ {
+ printf("%s", (const char*)diagnosticsBlob->getBufferPointer());
#ifdef _WIN32
- _Win32OutputDebugString((const char*)diagnosticsBlob->getBufferPointer());
+ _Win32OutputDebugString((const char*)diagnosticsBlob->getBufferPointer());
#endif
+ }
}
-}
-// Load and compile shader code from souce.
-gfx::Result loadShaderProgram(
- gfx::IDevice* device, bool isComputePipeline, gfx::IShaderProgram** outProgram)
-{
- ComPtr<slang::ISession> slangSession;
- slangSession = device->getSlangSession();
-
- ComPtr<slang::IBlob> diagnosticsBlob;
- Slang::String path = resourceBase.resolveResource("shaders.slang");
- slang::IModule* module = slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef());
- diagnoseIfNeeded(diagnosticsBlob);
- if(!module)
- return SLANG_FAIL;
-
- Slang::List<slang::IComponentType*> componentTypes;
- componentTypes.add(module);
- if (isComputePipeline)
+ // Load and compile shader code from souce.
+ gfx::Result loadShaderProgram(
+ gfx::IDevice* device,
+ bool isComputePipeline,
+ gfx::IShaderProgram** outProgram)
{
- ComPtr<slang::IEntryPoint> computeEntryPoint;
- SLANG_RETURN_ON_FAIL(module->findEntryPointByName("computeMain", computeEntryPoint.writeRef()));
- componentTypes.add(computeEntryPoint);
- }
- else
- {
- ComPtr<slang::IEntryPoint> entryPoint;
- SLANG_RETURN_ON_FAIL(module->findEntryPointByName("vertexMain", entryPoint.writeRef()));
- componentTypes.add(entryPoint);
- SLANG_RETURN_ON_FAIL(module->findEntryPointByName("fragmentMain", entryPoint.writeRef()));
- componentTypes.add(entryPoint);
- }
-
- ComPtr<slang::IComponentType> linkedProgram;
- SlangResult result = slangSession->createCompositeComponentType(
- componentTypes.getBuffer(),
- componentTypes.getCount(),
- linkedProgram.writeRef(),
- diagnosticsBlob.writeRef());
- diagnoseIfNeeded(diagnosticsBlob);
- SLANG_RETURN_ON_FAIL(result);
+ ComPtr<slang::ISession> slangSession;
+ slangSession = device->getSlangSession();
+
+ ComPtr<slang::IBlob> diagnosticsBlob;
+ Slang::String path = resourceBase.resolveResource("shaders.slang");
+ slang::IModule* module =
+ slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ if (!module)
+ return SLANG_FAIL;
- if (isTestMode())
- {
- printEntrypointHashes(componentTypes.getCount() - 1, 1, linkedProgram);
+ Slang::List<slang::IComponentType*> componentTypes;
+ componentTypes.add(module);
+ if (isComputePipeline)
+ {
+ ComPtr<slang::IEntryPoint> computeEntryPoint;
+ SLANG_RETURN_ON_FAIL(
+ module->findEntryPointByName("computeMain", computeEntryPoint.writeRef()));
+ componentTypes.add(computeEntryPoint);
+ }
+ else
+ {
+ ComPtr<slang::IEntryPoint> entryPoint;
+ SLANG_RETURN_ON_FAIL(module->findEntryPointByName("vertexMain", entryPoint.writeRef()));
+ componentTypes.add(entryPoint);
+ SLANG_RETURN_ON_FAIL(
+ module->findEntryPointByName("fragmentMain", entryPoint.writeRef()));
+ componentTypes.add(entryPoint);
+ }
+
+ ComPtr<slang::IComponentType> linkedProgram;
+ SlangResult result = slangSession->createCompositeComponentType(
+ componentTypes.getBuffer(),
+ componentTypes.getCount(),
+ linkedProgram.writeRef(),
+ diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ SLANG_RETURN_ON_FAIL(result);
+
+ if (isTestMode())
+ {
+ printEntrypointHashes(componentTypes.getCount() - 1, 1, linkedProgram);
+ }
+
+ gfx::IShaderProgram::Desc programDesc = {};
+ programDesc.slangGlobalScope = linkedProgram;
+ SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram));
+
+ return SLANG_OK;
}
- gfx::IShaderProgram::Desc programDesc = {};
- programDesc.slangGlobalScope = linkedProgram;
- SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram));
-
- return SLANG_OK;
-}
-
-ComPtr<gfx::IPipelineState> gPresentPipelineState;
-ComPtr<gfx::IPipelineState> gRenderPipelineState;
-ComPtr<gfx::IBufferResource> gFullScreenVertexBuffer;
-ComPtr<gfx::IBufferResource> gVertexBuffer;
-ComPtr<gfx::IBufferResource> gIndexBuffer;
-ComPtr<gfx::IBufferResource> gPrimitiveBuffer;
-ComPtr<gfx::IBufferResource> gTransformBuffer;
-ComPtr<gfx::IResourceView> gPrimitiveBufferSRV;
-ComPtr<gfx::IBufferResource> gInstanceBuffer;
-ComPtr<gfx::IBufferResource> gBLASBuffer;
-ComPtr<gfx::IAccelerationStructure> gBLAS;
-ComPtr<gfx::IBufferResource> gTLASBuffer;
-ComPtr<gfx::IAccelerationStructure> gTLAS;
-ComPtr<gfx::ITextureResource> gResultTexture;
-ComPtr<gfx::IResourceView> gResultTextureUAV;
-
-uint64_t lastTime = 0;
-
-// glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10));
-// glm::vec3 lightColor = glm::vec3(1, 1, 1);
-
-glm::vec3 cameraPosition = glm::vec3(-2.53f, 2.72f, 4.3f);
-float cameraOrientationAngles[2] = {-0.475f, -0.35f}; // Spherical angles (theta, phi).
-
-float translationScale = 0.5f;
-float rotationScale = 0.01f;
-
-// In order to control camera movement, we will
-// use good old WASD
-bool wPressed = false;
-bool aPressed = false;
-bool sPressed = false;
-bool dPressed = false;
-
-bool isMouseDown = false;
-float lastMouseX = 0.0f;
-float lastMouseY = 0.0f;
-
-void setKeyState(platform::KeyCode key, bool state)
-{
- switch (key)
+ ComPtr<gfx::IPipelineState> gPresentPipelineState;
+ ComPtr<gfx::IPipelineState> gRenderPipelineState;
+ ComPtr<gfx::IBufferResource> gFullScreenVertexBuffer;
+ ComPtr<gfx::IBufferResource> gVertexBuffer;
+ ComPtr<gfx::IBufferResource> gIndexBuffer;
+ ComPtr<gfx::IBufferResource> gPrimitiveBuffer;
+ ComPtr<gfx::IBufferResource> gTransformBuffer;
+ ComPtr<gfx::IResourceView> gPrimitiveBufferSRV;
+ ComPtr<gfx::IBufferResource> gInstanceBuffer;
+ ComPtr<gfx::IBufferResource> gBLASBuffer;
+ ComPtr<gfx::IAccelerationStructure> gBLAS;
+ ComPtr<gfx::IBufferResource> gTLASBuffer;
+ ComPtr<gfx::IAccelerationStructure> gTLAS;
+ ComPtr<gfx::ITextureResource> gResultTexture;
+ ComPtr<gfx::IResourceView> gResultTextureUAV;
+
+ uint64_t lastTime = 0;
+
+ // glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10));
+ // glm::vec3 lightColor = glm::vec3(1, 1, 1);
+
+ glm::vec3 cameraPosition = glm::vec3(-2.53f, 2.72f, 4.3f);
+ float cameraOrientationAngles[2] = {-0.475f, -0.35f}; // Spherical angles (theta, phi).
+
+ float translationScale = 0.5f;
+ float rotationScale = 0.01f;
+
+ // In order to control camera movement, we will
+ // use good old WASD
+ bool wPressed = false;
+ bool aPressed = false;
+ bool sPressed = false;
+ bool dPressed = false;
+
+ bool isMouseDown = false;
+ float lastMouseX = 0.0f;
+ float lastMouseY = 0.0f;
+
+ void setKeyState(platform::KeyCode key, bool state)
{
- default:
- break;
- case platform::KeyCode::W:
- wPressed = state;
- break;
- case platform::KeyCode::A:
- aPressed = state;
- break;
- case platform::KeyCode::S:
- sPressed = state;
- break;
- case platform::KeyCode::D:
- dPressed = state;
- break;
+ switch (key)
+ {
+ default: break;
+ case platform::KeyCode::W: wPressed = state; break;
+ case platform::KeyCode::A: aPressed = state; break;
+ case platform::KeyCode::S: sPressed = state; break;
+ case platform::KeyCode::D: dPressed = state; break;
+ }
}
-}
-void onKeyDown(platform::KeyEventArgs args) { setKeyState(args.key, true); }
-void onKeyUp(platform::KeyEventArgs args) { setKeyState(args.key, false); }
+ void onKeyDown(platform::KeyEventArgs args) { setKeyState(args.key, true); }
+ void onKeyUp(platform::KeyEventArgs args) { setKeyState(args.key, false); }
-void onMouseDown(platform::MouseEventArgs args)
-{
- isMouseDown = true;
- lastMouseX = (float)args.x;
- lastMouseY = (float)args.y;
-}
-
-void onMouseMove(platform::MouseEventArgs args)
-{
- if (isMouseDown)
+ void onMouseDown(platform::MouseEventArgs args)
{
- float deltaX = args.x - lastMouseX;
- float deltaY = args.y - lastMouseY;
-
- cameraOrientationAngles[0] += -deltaX * rotationScale;
- cameraOrientationAngles[1] += -deltaY * rotationScale;
+ isMouseDown = true;
lastMouseX = (float)args.x;
lastMouseY = (float)args.y;
}
-}
-void onMouseUp(platform::MouseEventArgs args) { isMouseDown = false; }
-
-Slang::Result initialize()
-{
- initializeBase("Ray Tracing", 1024, 768);
- if (!isTestMode())
+ void onMouseMove(platform::MouseEventArgs args)
{
- gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { onMouseMove(e); };
- gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); };
- gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { onMouseDown(e); };
- gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); };
- gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); };
+ if (isMouseDown)
+ {
+ float deltaX = args.x - lastMouseX;
+ float deltaY = args.y - lastMouseY;
+
+ cameraOrientationAngles[0] += -deltaX * rotationScale;
+ cameraOrientationAngles[1] += -deltaY * rotationScale;
+ lastMouseX = (float)args.x;
+ lastMouseY = (float)args.y;
+ }
}
+ void onMouseUp(platform::MouseEventArgs args) { isMouseDown = false; }
- IBufferResource::Desc vertexBufferDesc;
- vertexBufferDesc.type = IResource::Type::Buffer;
- vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex);
- vertexBufferDesc.defaultState = ResourceState::ShaderResource;
- gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]);
- if(!gVertexBuffer) return SLANG_FAIL;
-
- IBufferResource::Desc indexBufferDesc;
- indexBufferDesc.type = IResource::Type::Buffer;
- indexBufferDesc.sizeInBytes = kIndexCount * sizeof(int32_t);
- indexBufferDesc.defaultState = ResourceState::ShaderResource;
- gIndexBuffer = gDevice->createBufferResource(indexBufferDesc, &kIndexData[0]);
- if (!gIndexBuffer)
- return SLANG_FAIL;
-
- IBufferResource::Desc primitiveBufferDesc;
- primitiveBufferDesc.type = IResource::Type::Buffer;
- primitiveBufferDesc.sizeInBytes = kPrimitiveCount * sizeof(Primitive);
- primitiveBufferDesc.elementSize = sizeof(Primitive);
- primitiveBufferDesc.defaultState = ResourceState::ShaderResource;
- gPrimitiveBuffer = gDevice->createBufferResource(primitiveBufferDesc, &kPrimitiveData[0]);
- if (!gPrimitiveBuffer)
- return SLANG_FAIL;
-
- IResourceView::Desc primitiveSRVDesc = {};
- primitiveSRVDesc.format = Format::Unknown;
- primitiveSRVDesc.type = IResourceView::Type::ShaderResource;
- gPrimitiveBufferSRV = gDevice->createBufferView(gPrimitiveBuffer, nullptr, primitiveSRVDesc);
-
- IBufferResource::Desc transformBufferDesc;
- transformBufferDesc.type = IResource::Type::Buffer;
- transformBufferDesc.sizeInBytes = sizeof(float) * 12;
- transformBufferDesc.defaultState = ResourceState::ShaderResource;
- float transformData[12] = {
- 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};
- gTransformBuffer = gDevice->createBufferResource(transformBufferDesc, &transformData);
- if (!gTransformBuffer)
- return SLANG_FAIL;
- // Build bottom level acceleration structure.
+ Slang::Result initialize()
{
- IAccelerationStructure::BuildInputs accelerationStructureBuildInputs;
- IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo;
- accelerationStructureBuildInputs.descCount = 1;
- accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::BottomLevel;
- accelerationStructureBuildInputs.flags =
- IAccelerationStructure::BuildFlags::AllowCompaction;
- IAccelerationStructure::GeometryDesc geomDesc;
- geomDesc.flags = IAccelerationStructure::GeometryFlags::Opaque;
- geomDesc.type = IAccelerationStructure::GeometryType::Triangles;
- geomDesc.content.triangles.indexCount = kIndexCount;
- geomDesc.content.triangles.indexData = gIndexBuffer->getDeviceAddress();
- geomDesc.content.triangles.indexFormat = Format::R32_UINT;
- geomDesc.content.triangles.vertexCount = kVertexCount;
- geomDesc.content.triangles.vertexData = gVertexBuffer->getDeviceAddress();
- geomDesc.content.triangles.vertexFormat = Format::R32G32B32_FLOAT;
- geomDesc.content.triangles.vertexStride = sizeof(Vertex);
- geomDesc.content.triangles.transform3x4 = gTransformBuffer->getDeviceAddress();
- accelerationStructureBuildInputs.geometryDescs = &geomDesc;
-
- // Query buffer size for acceleration structure build.
- SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo(
- accelerationStructureBuildInputs, &accelerationStructurePrebuildInfo));
- // Allocate buffers for acceleration structure.
- IBufferResource::Desc asDraftBufferDesc;
- asDraftBufferDesc.type = IResource::Type::Buffer;
- asDraftBufferDesc.defaultState = ResourceState::AccelerationStructure;
- asDraftBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.resultDataMaxSize;
- ComPtr<IBufferResource> draftBuffer = gDevice->createBufferResource(asDraftBufferDesc);
- IBufferResource::Desc scratchBufferDesc;
- scratchBufferDesc.type = IResource::Type::Buffer;
- scratchBufferDesc.defaultState = ResourceState::UnorderedAccess;
- scratchBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.scratchDataSize;
- ComPtr<IBufferResource> scratchBuffer = gDevice->createBufferResource(scratchBufferDesc);
-
- // Build acceleration structure.
- ComPtr<IQueryPool> compactedSizeQuery;
- IQueryPool::Desc queryPoolDesc;
- queryPoolDesc.count = 1;
- queryPoolDesc.type = QueryType::AccelerationStructureCompactedSize;
- SLANG_RETURN_ON_FAIL(
- gDevice->createQueryPool(queryPoolDesc, compactedSizeQuery.writeRef()));
-
- ComPtr<IAccelerationStructure> draftAS;
- IAccelerationStructure::CreateDesc draftCreateDesc;
- draftCreateDesc.buffer = draftBuffer;
- draftCreateDesc.kind = IAccelerationStructure::Kind::BottomLevel;
- draftCreateDesc.offset = 0;
- draftCreateDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize;
- SLANG_RETURN_ON_FAIL(
- gDevice->createAccelerationStructure(draftCreateDesc, draftAS.writeRef()));
-
- compactedSizeQuery->reset();
-
- auto commandBuffer = gTransientHeaps[0]->createCommandBuffer();
- auto encoder = commandBuffer->encodeRayTracingCommands();
- IAccelerationStructure::BuildDesc buildDesc = {};
- buildDesc.dest = draftAS;
- buildDesc.inputs = accelerationStructureBuildInputs;
- buildDesc.scratchData = scratchBuffer->getDeviceAddress();
- AccelerationStructureQueryDesc compactedSizeQueryDesc = {};
- compactedSizeQueryDesc.queryPool = compactedSizeQuery;
- compactedSizeQueryDesc.queryType = QueryType::AccelerationStructureCompactedSize;
- encoder->buildAccelerationStructure(buildDesc, 1, &compactedSizeQueryDesc);
- encoder->endEncoding();
- commandBuffer->close();
- gQueue->executeCommandBuffer(commandBuffer);
- gQueue->waitOnHost();
-
- uint64_t compactedSize = 0;
- compactedSizeQuery->getResult(0, 1, &compactedSize);
- IBufferResource::Desc asBufferDesc;
- asBufferDesc.type = IResource::Type::Buffer;
- asBufferDesc.defaultState = ResourceState::AccelerationStructure;
- asBufferDesc.sizeInBytes = (Size)compactedSize;
- gBLASBuffer = gDevice->createBufferResource(asBufferDesc);
- IAccelerationStructure::CreateDesc createDesc;
- createDesc.buffer = gBLASBuffer;
- createDesc.kind = IAccelerationStructure::Kind::BottomLevel;
- createDesc.offset = 0;
- createDesc.size = (Size)compactedSize;
- gDevice->createAccelerationStructure(createDesc, gBLAS.writeRef());
-
- commandBuffer = gTransientHeaps[0]->createCommandBuffer();
- encoder = commandBuffer->encodeRayTracingCommands();
- encoder->copyAccelerationStructure(gBLAS, draftAS, AccelerationStructureCopyMode::Compact);
- encoder->endEncoding();
- commandBuffer->close();
- gQueue->executeCommandBuffer(commandBuffer);
- gQueue->waitOnHost();
- }
+ initializeBase("Ray Tracing", 1024, 768);
+
+ if (!isTestMode())
+ {
+ gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e)
+ { onMouseMove(e); };
+ gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); };
+ gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e)
+ { onMouseDown(e); };
+ gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); };
+ gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); };
+ }
+
+ IBufferResource::Desc vertexBufferDesc;
+ vertexBufferDesc.type = IResource::Type::Buffer;
+ vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex);
+ vertexBufferDesc.defaultState = ResourceState::ShaderResource;
+ gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]);
+ if (!gVertexBuffer)
+ return SLANG_FAIL;
- // Build top level acceleration structure.
- {
- List<IAccelerationStructure::InstanceDesc> instanceDescs;
- instanceDescs.setCount(1);
- instanceDescs[0].accelerationStructure = gBLAS->getDeviceAddress();
- instanceDescs[0].flags =
- IAccelerationStructure::GeometryInstanceFlags::TriangleFacingCullDisable;
- instanceDescs[0].instanceContributionToHitGroupIndex = 0;
- instanceDescs[0].instanceID = 0;
- instanceDescs[0].instanceMask = 0xFF;
- float transformMatrix[] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};
- memcpy(&instanceDescs[0].transform[0][0], transformMatrix, sizeof(float) * 12);
-
- IBufferResource::Desc instanceBufferDesc;
- instanceBufferDesc.type = IResource::Type::Buffer;
- instanceBufferDesc.sizeInBytes =
- instanceDescs.getCount() * sizeof(IAccelerationStructure::InstanceDesc);
- instanceBufferDesc.defaultState = ResourceState::ShaderResource;
- gInstanceBuffer = gDevice->createBufferResource(instanceBufferDesc, instanceDescs.getBuffer());
- if (!gInstanceBuffer)
+ IBufferResource::Desc indexBufferDesc;
+ indexBufferDesc.type = IResource::Type::Buffer;
+ indexBufferDesc.sizeInBytes = kIndexCount * sizeof(int32_t);
+ indexBufferDesc.defaultState = ResourceState::ShaderResource;
+ gIndexBuffer = gDevice->createBufferResource(indexBufferDesc, &kIndexData[0]);
+ if (!gIndexBuffer)
return SLANG_FAIL;
- IAccelerationStructure::BuildInputs accelerationStructureBuildInputs = {};
- IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo = {};
- accelerationStructureBuildInputs.descCount = 1;
- accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::TopLevel;
- accelerationStructureBuildInputs.instanceDescs = gInstanceBuffer->getDeviceAddress();
-
- // Query buffer size for acceleration structure build.
- SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo(
- accelerationStructureBuildInputs, &accelerationStructurePrebuildInfo));
-
- IBufferResource::Desc asBufferDesc;
- asBufferDesc.type = IResource::Type::Buffer;
- asBufferDesc.defaultState = ResourceState::AccelerationStructure;
- asBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.resultDataMaxSize;
- gTLASBuffer = gDevice->createBufferResource(asBufferDesc);
-
- IBufferResource::Desc scratchBufferDesc;
- scratchBufferDesc.type = IResource::Type::Buffer;
- scratchBufferDesc.defaultState = ResourceState::UnorderedAccess;
- scratchBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.scratchDataSize;
- ComPtr<IBufferResource> scratchBuffer = gDevice->createBufferResource(scratchBufferDesc);
-
- IAccelerationStructure::CreateDesc createDesc;
- createDesc.buffer = gTLASBuffer;
- createDesc.kind = IAccelerationStructure::Kind::TopLevel;
- createDesc.offset = 0;
- createDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize;
- SLANG_RETURN_ON_FAIL(gDevice->createAccelerationStructure(createDesc, gTLAS.writeRef()));
-
- auto commandBuffer = gTransientHeaps[0]->createCommandBuffer();
- auto encoder = commandBuffer->encodeRayTracingCommands();
- IAccelerationStructure::BuildDesc buildDesc = {};
- buildDesc.dest = gTLAS;
- buildDesc.inputs = accelerationStructureBuildInputs;
- buildDesc.scratchData = scratchBuffer->getDeviceAddress();
- encoder->buildAccelerationStructure(buildDesc, 0, nullptr);
- encoder->endEncoding();
- commandBuffer->close();
- gQueue->executeCommandBuffer(commandBuffer);
- gQueue->waitOnHost();
- }
+ IBufferResource::Desc primitiveBufferDesc;
+ primitiveBufferDesc.type = IResource::Type::Buffer;
+ primitiveBufferDesc.sizeInBytes = kPrimitiveCount * sizeof(Primitive);
+ primitiveBufferDesc.elementSize = sizeof(Primitive);
+ primitiveBufferDesc.defaultState = ResourceState::ShaderResource;
+ gPrimitiveBuffer = gDevice->createBufferResource(primitiveBufferDesc, &kPrimitiveData[0]);
+ if (!gPrimitiveBuffer)
+ return SLANG_FAIL;
- IBufferResource::Desc fullScreenVertexBufferDesc;
- fullScreenVertexBufferDesc.type = IResource::Type::Buffer;
- fullScreenVertexBufferDesc.sizeInBytes =
- FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex);
- fullScreenVertexBufferDesc.defaultState = ResourceState::VertexBuffer;
- gFullScreenVertexBuffer = gDevice->createBufferResource(
- fullScreenVertexBufferDesc, &FullScreenTriangle::kVertices[0]);
- if (!gFullScreenVertexBuffer)
- return SLANG_FAIL;
-
- InputElementDesc inputElements[] = {
- {"POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position)},
- };
- auto inputLayout = gDevice->createInputLayout(sizeof(FullScreenTriangle::Vertex), &inputElements[0], SLANG_COUNT_OF(inputElements));
- if (!inputLayout)
- return SLANG_FAIL;
-
- ComPtr<IShaderProgram> shaderProgram;
- SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, false, shaderProgram.writeRef()));
- GraphicsPipelineStateDesc desc;
- desc.inputLayout = inputLayout;
- desc.program = shaderProgram;
- desc.framebufferLayout = gFramebufferLayout;
- gPresentPipelineState = gDevice->createGraphicsPipelineState(desc);
- if (!gPresentPipelineState)
- return SLANG_FAIL;
-
- ComPtr<IShaderProgram> computeProgram;
- SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, true, computeProgram.writeRef()));
- ComputePipelineStateDesc computeDesc;
- computeDesc.program = computeProgram;
- gRenderPipelineState = gDevice->createComputePipelineState(computeDesc);
- if (!gRenderPipelineState)
- return SLANG_FAIL;
-
- createResultTexture();
- return SLANG_OK;
-}
-
-void createResultTexture()
-{
- ITextureResource::Desc resultTextureDesc = {};
- resultTextureDesc.type = IResource::Type::Texture2D;
- resultTextureDesc.numMipLevels = 1;
- resultTextureDesc.size.width = windowWidth;
- resultTextureDesc.size.height = windowHeight;
- resultTextureDesc.size.depth = 1;
- resultTextureDesc.defaultState = ResourceState::UnorderedAccess;
- resultTextureDesc.format = Format::R16G16B16A16_FLOAT;
- gResultTexture = gDevice->createTextureResource(resultTextureDesc);
- IResourceView::Desc resultUAVDesc = {};
- resultUAVDesc.format = resultTextureDesc.format;
- resultUAVDesc.type = IResourceView::Type::UnorderedAccess;
- gResultTextureUAV = gDevice->createTextureView(gResultTexture, resultUAVDesc);
-}
-
-virtual void windowSizeChanged() override
-{
- WindowedAppBase::windowSizeChanged();
- createResultTexture();
-}
+ IResourceView::Desc primitiveSRVDesc = {};
+ primitiveSRVDesc.format = Format::Unknown;
+ primitiveSRVDesc.type = IResourceView::Type::ShaderResource;
+ gPrimitiveBufferSRV =
+ gDevice->createBufferView(gPrimitiveBuffer, nullptr, primitiveSRVDesc);
+
+ IBufferResource::Desc transformBufferDesc;
+ transformBufferDesc.type = IResource::Type::Buffer;
+ transformBufferDesc.sizeInBytes = sizeof(float) * 12;
+ transformBufferDesc.defaultState = ResourceState::ShaderResource;
+ float transformData[12] =
+ {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};
+ gTransformBuffer = gDevice->createBufferResource(transformBufferDesc, &transformData);
+ if (!gTransformBuffer)
+ return SLANG_FAIL;
+ // Build bottom level acceleration structure.
+ {
+ IAccelerationStructure::BuildInputs accelerationStructureBuildInputs;
+ IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo;
+ accelerationStructureBuildInputs.descCount = 1;
+ accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::BottomLevel;
+ accelerationStructureBuildInputs.flags =
+ IAccelerationStructure::BuildFlags::AllowCompaction;
+ IAccelerationStructure::GeometryDesc geomDesc;
+ geomDesc.flags = IAccelerationStructure::GeometryFlags::Opaque;
+ geomDesc.type = IAccelerationStructure::GeometryType::Triangles;
+ geomDesc.content.triangles.indexCount = kIndexCount;
+ geomDesc.content.triangles.indexData = gIndexBuffer->getDeviceAddress();
+ geomDesc.content.triangles.indexFormat = Format::R32_UINT;
+ geomDesc.content.triangles.vertexCount = kVertexCount;
+ geomDesc.content.triangles.vertexData = gVertexBuffer->getDeviceAddress();
+ geomDesc.content.triangles.vertexFormat = Format::R32G32B32_FLOAT;
+ geomDesc.content.triangles.vertexStride = sizeof(Vertex);
+ geomDesc.content.triangles.transform3x4 = gTransformBuffer->getDeviceAddress();
+ accelerationStructureBuildInputs.geometryDescs = &geomDesc;
+
+ // Query buffer size for acceleration structure build.
+ SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo(
+ accelerationStructureBuildInputs,
+ &accelerationStructurePrebuildInfo));
+ // Allocate buffers for acceleration structure.
+ IBufferResource::Desc asDraftBufferDesc;
+ asDraftBufferDesc.type = IResource::Type::Buffer;
+ asDraftBufferDesc.defaultState = ResourceState::AccelerationStructure;
+ asDraftBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.resultDataMaxSize;
+ ComPtr<IBufferResource> draftBuffer = gDevice->createBufferResource(asDraftBufferDesc);
+ IBufferResource::Desc scratchBufferDesc;
+ scratchBufferDesc.type = IResource::Type::Buffer;
+ scratchBufferDesc.defaultState = ResourceState::UnorderedAccess;
+ scratchBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.scratchDataSize;
+ ComPtr<IBufferResource> scratchBuffer =
+ gDevice->createBufferResource(scratchBufferDesc);
+
+ // Build acceleration structure.
+ ComPtr<IQueryPool> compactedSizeQuery;
+ IQueryPool::Desc queryPoolDesc;
+ queryPoolDesc.count = 1;
+ queryPoolDesc.type = QueryType::AccelerationStructureCompactedSize;
+ SLANG_RETURN_ON_FAIL(
+ gDevice->createQueryPool(queryPoolDesc, compactedSizeQuery.writeRef()));
+
+ ComPtr<IAccelerationStructure> draftAS;
+ IAccelerationStructure::CreateDesc draftCreateDesc;
+ draftCreateDesc.buffer = draftBuffer;
+ draftCreateDesc.kind = IAccelerationStructure::Kind::BottomLevel;
+ draftCreateDesc.offset = 0;
+ draftCreateDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize;
+ SLANG_RETURN_ON_FAIL(
+ gDevice->createAccelerationStructure(draftCreateDesc, draftAS.writeRef()));
+
+ compactedSizeQuery->reset();
+
+ auto commandBuffer = gTransientHeaps[0]->createCommandBuffer();
+ auto encoder = commandBuffer->encodeRayTracingCommands();
+ IAccelerationStructure::BuildDesc buildDesc = {};
+ buildDesc.dest = draftAS;
+ buildDesc.inputs = accelerationStructureBuildInputs;
+ buildDesc.scratchData = scratchBuffer->getDeviceAddress();
+ AccelerationStructureQueryDesc compactedSizeQueryDesc = {};
+ compactedSizeQueryDesc.queryPool = compactedSizeQuery;
+ compactedSizeQueryDesc.queryType = QueryType::AccelerationStructureCompactedSize;
+ encoder->buildAccelerationStructure(buildDesc, 1, &compactedSizeQueryDesc);
+ encoder->endEncoding();
+ commandBuffer->close();
+ gQueue->executeCommandBuffer(commandBuffer);
+ gQueue->waitOnHost();
+
+ uint64_t compactedSize = 0;
+ compactedSizeQuery->getResult(0, 1, &compactedSize);
+ IBufferResource::Desc asBufferDesc;
+ asBufferDesc.type = IResource::Type::Buffer;
+ asBufferDesc.defaultState = ResourceState::AccelerationStructure;
+ asBufferDesc.sizeInBytes = (Size)compactedSize;
+ gBLASBuffer = gDevice->createBufferResource(asBufferDesc);
+ IAccelerationStructure::CreateDesc createDesc;
+ createDesc.buffer = gBLASBuffer;
+ createDesc.kind = IAccelerationStructure::Kind::BottomLevel;
+ createDesc.offset = 0;
+ createDesc.size = (Size)compactedSize;
+ gDevice->createAccelerationStructure(createDesc, gBLAS.writeRef());
+
+ commandBuffer = gTransientHeaps[0]->createCommandBuffer();
+ encoder = commandBuffer->encodeRayTracingCommands();
+ encoder->copyAccelerationStructure(
+ gBLAS,
+ draftAS,
+ AccelerationStructureCopyMode::Compact);
+ encoder->endEncoding();
+ commandBuffer->close();
+ gQueue->executeCommandBuffer(commandBuffer);
+ gQueue->waitOnHost();
+ }
+
+ // Build top level acceleration structure.
+ {
+ List<IAccelerationStructure::InstanceDesc> instanceDescs;
+ instanceDescs.setCount(1);
+ instanceDescs[0].accelerationStructure = gBLAS->getDeviceAddress();
+ instanceDescs[0].flags =
+ IAccelerationStructure::GeometryInstanceFlags::TriangleFacingCullDisable;
+ instanceDescs[0].instanceContributionToHitGroupIndex = 0;
+ instanceDescs[0].instanceID = 0;
+ instanceDescs[0].instanceMask = 0xFF;
+ float transformMatrix[] =
+ {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};
+ memcpy(&instanceDescs[0].transform[0][0], transformMatrix, sizeof(float) * 12);
+
+ IBufferResource::Desc instanceBufferDesc;
+ instanceBufferDesc.type = IResource::Type::Buffer;
+ instanceBufferDesc.sizeInBytes =
+ instanceDescs.getCount() * sizeof(IAccelerationStructure::InstanceDesc);
+ instanceBufferDesc.defaultState = ResourceState::ShaderResource;
+ gInstanceBuffer =
+ gDevice->createBufferResource(instanceBufferDesc, instanceDescs.getBuffer());
+ if (!gInstanceBuffer)
+ return SLANG_FAIL;
+
+ IAccelerationStructure::BuildInputs accelerationStructureBuildInputs = {};
+ IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo = {};
+ accelerationStructureBuildInputs.descCount = 1;
+ accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::TopLevel;
+ accelerationStructureBuildInputs.instanceDescs = gInstanceBuffer->getDeviceAddress();
+
+ // Query buffer size for acceleration structure build.
+ SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo(
+ accelerationStructureBuildInputs,
+ &accelerationStructurePrebuildInfo));
+
+ IBufferResource::Desc asBufferDesc;
+ asBufferDesc.type = IResource::Type::Buffer;
+ asBufferDesc.defaultState = ResourceState::AccelerationStructure;
+ asBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.resultDataMaxSize;
+ gTLASBuffer = gDevice->createBufferResource(asBufferDesc);
+
+ IBufferResource::Desc scratchBufferDesc;
+ scratchBufferDesc.type = IResource::Type::Buffer;
+ scratchBufferDesc.defaultState = ResourceState::UnorderedAccess;
+ scratchBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.scratchDataSize;
+ ComPtr<IBufferResource> scratchBuffer =
+ gDevice->createBufferResource(scratchBufferDesc);
+
+ IAccelerationStructure::CreateDesc createDesc;
+ createDesc.buffer = gTLASBuffer;
+ createDesc.kind = IAccelerationStructure::Kind::TopLevel;
+ createDesc.offset = 0;
+ createDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize;
+ SLANG_RETURN_ON_FAIL(
+ gDevice->createAccelerationStructure(createDesc, gTLAS.writeRef()));
+
+ auto commandBuffer = gTransientHeaps[0]->createCommandBuffer();
+ auto encoder = commandBuffer->encodeRayTracingCommands();
+ IAccelerationStructure::BuildDesc buildDesc = {};
+ buildDesc.dest = gTLAS;
+ buildDesc.inputs = accelerationStructureBuildInputs;
+ buildDesc.scratchData = scratchBuffer->getDeviceAddress();
+ encoder->buildAccelerationStructure(buildDesc, 0, nullptr);
+ encoder->endEncoding();
+ commandBuffer->close();
+ gQueue->executeCommandBuffer(commandBuffer);
+ gQueue->waitOnHost();
+ }
+
+ IBufferResource::Desc fullScreenVertexBufferDesc;
+ fullScreenVertexBufferDesc.type = IResource::Type::Buffer;
+ fullScreenVertexBufferDesc.sizeInBytes =
+ FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex);
+ fullScreenVertexBufferDesc.defaultState = ResourceState::VertexBuffer;
+ gFullScreenVertexBuffer = gDevice->createBufferResource(
+ fullScreenVertexBufferDesc,
+ &FullScreenTriangle::kVertices[0]);
+ if (!gFullScreenVertexBuffer)
+ return SLANG_FAIL;
-glm::vec3 getVectorFromSphericalAngles(float theta, float phi)
-{
- auto sinTheta = sin(theta);
- auto cosTheta = cos(theta);
- auto sinPhi = sin(phi);
- auto cosPhi = cos(phi);
- return glm::vec3(-sinTheta * cosPhi, sinPhi, -cosTheta * cosPhi);
-}
-void updateUniforms()
-{
- gUniforms.screenWidth = (float)windowWidth;
- gUniforms.screenHeight = (float)windowHeight;
- if (!lastTime)
- lastTime = getCurrentTime();
- uint64_t currentTime = getCurrentTime();
- float deltaTime = float(double(currentTime - lastTime) / double(getTimerFrequency()));
- lastTime = currentTime;
-
- auto camDir =
- getVectorFromSphericalAngles(cameraOrientationAngles[0], cameraOrientationAngles[1]);
- auto camUp = getVectorFromSphericalAngles(
- cameraOrientationAngles[0], cameraOrientationAngles[1] + glm::pi<float>() * 0.5f);
- auto camRight = glm::cross(camDir, camUp);
-
- glm::vec3 movement = glm::vec3(0);
- if (wPressed)
- movement += camDir;
- if (sPressed)
- movement -= camDir;
- if (aPressed)
- movement -= camRight;
- if (dPressed)
- movement += camRight;
-
- cameraPosition += deltaTime * translationScale * movement;
-
- memcpy(gUniforms.cameraDir, &camDir, sizeof(float) * 3);
- memcpy(gUniforms.cameraUp, &camUp, sizeof(float) * 3);
- memcpy(gUniforms.cameraRight, &camRight, sizeof(float) * 3);
- memcpy(gUniforms.cameraPosition, &cameraPosition, sizeof(float) * 3);
- auto lightDir = glm::normalize(glm::vec3(1.0f, 3.0f, 2.0f));
- memcpy(gUniforms.lightDir, &lightDir, sizeof(float) * 3);
-}
-
-virtual void renderFrame(int frameBufferIndex) override
-{
- updateUniforms();
+ InputElementDesc inputElements[] = {
+ {"POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position)},
+ };
+ auto inputLayout = gDevice->createInputLayout(
+ sizeof(FullScreenTriangle::Vertex),
+ &inputElements[0],
+ SLANG_COUNT_OF(inputElements));
+ if (!inputLayout)
+ return SLANG_FAIL;
+
+ ComPtr<IShaderProgram> shaderProgram;
+ SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, false, shaderProgram.writeRef()));
+ GraphicsPipelineStateDesc desc;
+ desc.inputLayout = inputLayout;
+ desc.program = shaderProgram;
+ desc.framebufferLayout = gFramebufferLayout;
+ gPresentPipelineState = gDevice->createGraphicsPipelineState(desc);
+ if (!gPresentPipelineState)
+ return SLANG_FAIL;
+
+ ComPtr<IShaderProgram> computeProgram;
+ SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, true, computeProgram.writeRef()));
+ ComputePipelineStateDesc computeDesc;
+ computeDesc.program = computeProgram;
+ gRenderPipelineState = gDevice->createComputePipelineState(computeDesc);
+ if (!gRenderPipelineState)
+ return SLANG_FAIL;
+
+ createResultTexture();
+ return SLANG_OK;
+ }
+
+ void createResultTexture()
{
- ComPtr<ICommandBuffer> renderCommandBuffer =
- gTransientHeaps[frameBufferIndex]->createCommandBuffer();
- auto renderEncoder = renderCommandBuffer->encodeComputeCommands();
- auto rootObject = renderEncoder->bindPipeline(gRenderPipelineState);
- auto cursor = ShaderCursor(rootObject->getEntryPoint(0));
- cursor["resultTexture"].setResource(gResultTextureUAV);
- cursor["uniforms"].setData(&gUniforms, sizeof(Uniforms));
- cursor["sceneBVH"].setResource(gTLAS);
- cursor["primitiveBuffer"].setResource(gPrimitiveBufferSRV);
- renderEncoder->dispatchCompute((windowWidth + 15) / 16, (windowHeight + 15) / 16, 1);
- renderEncoder->endEncoding();
- renderCommandBuffer->close();
- gQueue->executeCommandBuffer(renderCommandBuffer);
+ ITextureResource::Desc resultTextureDesc = {};
+ resultTextureDesc.type = IResource::Type::Texture2D;
+ resultTextureDesc.numMipLevels = 1;
+ resultTextureDesc.size.width = windowWidth;
+ resultTextureDesc.size.height = windowHeight;
+ resultTextureDesc.size.depth = 1;
+ resultTextureDesc.defaultState = ResourceState::UnorderedAccess;
+ resultTextureDesc.format = Format::R16G16B16A16_FLOAT;
+ gResultTexture = gDevice->createTextureResource(resultTextureDesc);
+ IResourceView::Desc resultUAVDesc = {};
+ resultUAVDesc.format = resultTextureDesc.format;
+ resultUAVDesc.type = IResourceView::Type::UnorderedAccess;
+ gResultTextureUAV = gDevice->createTextureView(gResultTexture, resultUAVDesc);
}
+ virtual void windowSizeChanged() override
{
- ComPtr<ICommandBuffer> presentCommandBuffer =
- gTransientHeaps[frameBufferIndex]->createCommandBuffer();
- auto presentEncoder = presentCommandBuffer->encodeRenderCommands(
- gRenderPass, gFramebuffers[frameBufferIndex]);
- gfx::Viewport viewport = {};
- viewport.maxZ = 1.0f;
- viewport.extentX = (float)windowWidth;
- viewport.extentY = (float)windowHeight;
- presentEncoder->setViewportAndScissor(viewport);
- auto rootObject = presentEncoder->bindPipeline(gPresentPipelineState);
- auto cursor = ShaderCursor(rootObject->getEntryPoint(1));
- cursor["t"].setResource(gResultTextureUAV);
- presentEncoder->setVertexBuffer(
- 0, gFullScreenVertexBuffer);
- presentEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList);
- presentEncoder->draw(3);
- presentEncoder->endEncoding();
- presentCommandBuffer->close();
- gQueue->executeCommandBuffer(presentCommandBuffer);
+ WindowedAppBase::windowSizeChanged();
+ createResultTexture();
}
- if (!isTestMode())
+ glm::vec3 getVectorFromSphericalAngles(float theta, float phi)
{
- // With that, we are done drawing for one frame, and ready for the next.
- //
- gSwapchain->present();
+ auto sinTheta = sin(theta);
+ auto cosTheta = cos(theta);
+ auto sinPhi = sin(phi);
+ auto cosPhi = cos(phi);
+ return glm::vec3(-sinTheta * cosPhi, sinPhi, -cosTheta * cosPhi);
+ }
+ void updateUniforms()
+ {
+ gUniforms.screenWidth = (float)windowWidth;
+ gUniforms.screenHeight = (float)windowHeight;
+ if (!lastTime)
+ lastTime = getCurrentTime();
+ uint64_t currentTime = getCurrentTime();
+ float deltaTime = float(double(currentTime - lastTime) / double(getTimerFrequency()));
+ lastTime = currentTime;
+
+ auto camDir =
+ getVectorFromSphericalAngles(cameraOrientationAngles[0], cameraOrientationAngles[1]);
+ auto camUp = getVectorFromSphericalAngles(
+ cameraOrientationAngles[0],
+ cameraOrientationAngles[1] + glm::pi<float>() * 0.5f);
+ auto camRight = glm::cross(camDir, camUp);
+
+ glm::vec3 movement = glm::vec3(0);
+ if (wPressed)
+ movement += camDir;
+ if (sPressed)
+ movement -= camDir;
+ if (aPressed)
+ movement -= camRight;
+ if (dPressed)
+ movement += camRight;
+
+ cameraPosition += deltaTime * translationScale * movement;
+
+ memcpy(gUniforms.cameraDir, &camDir, sizeof(float) * 3);
+ memcpy(gUniforms.cameraUp, &camUp, sizeof(float) * 3);
+ memcpy(gUniforms.cameraRight, &camRight, sizeof(float) * 3);
+ memcpy(gUniforms.cameraPosition, &cameraPosition, sizeof(float) * 3);
+ auto lightDir = glm::normalize(glm::vec3(1.0f, 3.0f, 2.0f));
+ memcpy(gUniforms.lightDir, &lightDir, sizeof(float) * 3);
}
-}
+ virtual void renderFrame(int frameBufferIndex) override
+ {
+ updateUniforms();
+ {
+ ComPtr<ICommandBuffer> renderCommandBuffer =
+ gTransientHeaps[frameBufferIndex]->createCommandBuffer();
+ auto renderEncoder = renderCommandBuffer->encodeComputeCommands();
+ auto rootObject = renderEncoder->bindPipeline(gRenderPipelineState);
+ auto cursor = ShaderCursor(rootObject->getEntryPoint(0));
+ cursor["resultTexture"].setResource(gResultTextureUAV);
+ cursor["uniforms"].setData(&gUniforms, sizeof(Uniforms));
+ cursor["sceneBVH"].setResource(gTLAS);
+ cursor["primitiveBuffer"].setResource(gPrimitiveBufferSRV);
+ renderEncoder->dispatchCompute((windowWidth + 15) / 16, (windowHeight + 15) / 16, 1);
+ renderEncoder->endEncoding();
+ renderCommandBuffer->close();
+ gQueue->executeCommandBuffer(renderCommandBuffer);
+ }
+
+ {
+ ComPtr<ICommandBuffer> presentCommandBuffer =
+ gTransientHeaps[frameBufferIndex]->createCommandBuffer();
+ auto presentEncoder = presentCommandBuffer->encodeRenderCommands(
+ gRenderPass,
+ gFramebuffers[frameBufferIndex]);
+ gfx::Viewport viewport = {};
+ viewport.maxZ = 1.0f;
+ viewport.extentX = (float)windowWidth;
+ viewport.extentY = (float)windowHeight;
+ presentEncoder->setViewportAndScissor(viewport);
+ auto rootObject = presentEncoder->bindPipeline(gPresentPipelineState);
+ auto cursor = ShaderCursor(rootObject->getEntryPoint(1));
+ cursor["t"].setResource(gResultTextureUAV);
+ presentEncoder->setVertexBuffer(0, gFullScreenVertexBuffer);
+ presentEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList);
+ presentEncoder->draw(3);
+ presentEncoder->endEncoding();
+ presentCommandBuffer->close();
+ gQueue->executeCommandBuffer(presentCommandBuffer);
+ }
+
+ if (!isTestMode())
+ {
+ // With that, we are done drawing for one frame, and ready for the next.
+ //
+ gSwapchain->present();
+ }
+ }
};
// This macro instantiates an appropriate main function to
diff --git a/examples/shader-object/main.cpp b/examples/shader-object/main.cpp
index 603278bcf..74d81604b 100644
--- a/examples/shader-object/main.cpp
+++ b/examples/shader-object/main.cpp
@@ -8,14 +8,14 @@
// simplifies shader specialization and parameter binding when using `interface` typed
// shader parameters.
//
-#include "slang.h"
#include "slang-com-ptr.h"
+#include "slang.h"
using Slang::ComPtr;
-#include "slang-gfx.h"
+#include "examples/example-base/example-base.h"
#include "gfx-util/shader-cursor.h"
+#include "slang-gfx.h"
#include "source/core/slang-basic.h"
-#include "examples/example-base/example-base.h"
using namespace gfx;
@@ -37,7 +37,7 @@ Result loadShaderProgram(
// creates a Slang compilation session for us, so we just grab and use it here.
ComPtr<slang::ISession> slangSession;
SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef()));
-
+
// Once the session has been obtained, we can start loading code into it.
//
// The simplest way to load code is by calling `loadModule` with the name of a Slang
@@ -61,7 +61,7 @@ Result loadShaderProgram(
Slang::String path = resourceBase.resolveResource("shader-object.slang");
slang::IModule* module = slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef());
diagnoseIfNeeded(diagnosticsBlob);
- if(!module)
+ if (!module)
return SLANG_FAIL;
// Loading the `shader-object` module will compile and check all the shader code in it,
@@ -74,13 +74,13 @@ Result loadShaderProgram(
// is no umambiguous way for the compiler to know which functions represent entry
// points when it parses your code via `loadModule()`.
//
- char const* computeEntryPointName = "computeMain";
+ char const* computeEntryPointName = "computeMain";
ComPtr<slang::IEntryPoint> computeEntryPoint;
SLANG_RETURN_ON_FAIL(
module->findEntryPointByName(computeEntryPointName, computeEntryPoint.writeRef()));
-
+
// At this point we have a few different Slang API objects that represent
- // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`.
+ // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`.
//
// A single Slang module could contain many different entry points (e.g.,
// four vertex entry points, three fragment entry points, and two compute
@@ -177,10 +177,8 @@ int main(int argc, char* argv[])
bufferDesc.memoryType = MemoryType::DeviceLocal;
ComPtr<gfx::IBufferResource> numbersBuffer;
- SLANG_RETURN_ON_FAIL(device->createBufferResource(
- bufferDesc,
- (void*)initialData,
- numbersBuffer.writeRef()));
+ SLANG_RETURN_ON_FAIL(
+ device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef()));
// Create a resource view for the buffer.
ComPtr<gfx::IResourceView> bufferView;
@@ -217,7 +215,9 @@ int main(int argc, char* argv[])
// Now we can use this type to create a shader object that can be bound to the root object.
ComPtr<gfx::IShaderObject> transformer;
SLANG_RETURN_ON_FAIL(device->createShaderObject(
- addTransformerType, ShaderObjectContainerType::None, transformer.writeRef()));
+ addTransformerType,
+ ShaderObjectContainerType::None,
+ transformer.writeRef()));
// Set the `c` field of the `AddTransformer`.
float c = 1.0f;
gfx::ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float));
@@ -244,7 +244,10 @@ int main(int argc, char* argv[])
// Read back the results.
ComPtr<ISlangBlob> resultBlob;
SLANG_RETURN_ON_FAIL(device->readBufferResource(
- numbersBuffer, 0, numberCount * sizeof(float), resultBlob.writeRef()));
+ numbersBuffer,
+ 0,
+ numberCount * sizeof(float),
+ resultBlob.writeRef()));
auto result = reinterpret_cast<const float*>(resultBlob->getBufferPointer());
for (int i = 0; i < numberCount; i++)
printf("%f\n", result[i]);
diff --git a/examples/shader-toy/main.cpp b/examples/shader-toy/main.cpp
index 13a79c7ee..38212099e 100644
--- a/examples/shader-toy/main.cpp
+++ b/examples/shader-toy/main.cpp
@@ -10,8 +10,8 @@
// This example uses the Slang C/C++ API, alonmg with its optional type
// for managing COM-style reference-counted pointers.
//
-#include "slang.h"
#include "slang-com-ptr.h"
+#include "slang.h"
using Slang::ComPtr;
// This example uses a graphics API abstraction layer that is implemented inside
@@ -19,12 +19,12 @@ using Slang::ComPtr;
// this layer is *not* required or assumed when using the Slang language,
// compiler, and API.
//
+#include "examples/example-base/example-base.h"
#include "slang-gfx.h"
+#include "source/core/slang-basic.h"
#include "tools/gfx-util/shader-cursor.h"
-#include "tools/platform/window.h"
#include "tools/platform/performance-counter.h"
-#include "examples/example-base/example-base.h"
-#include "source/core/slang-basic.h"
+#include "tools/platform/window.h"
#include <chrono>
@@ -43,15 +43,17 @@ struct FullScreenTriangle
float position[2];
};
- enum { kVertexCount = 3 };
+ enum
+ {
+ kVertexCount = 3
+ };
static const Vertex kVertices[kVertexCount];
};
-const FullScreenTriangle::Vertex FullScreenTriangle::kVertices[FullScreenTriangle::kVertexCount] =
-{
- { { -1, -1 } },
- { { -1, 3 } },
- { { 3, -1 } },
+const FullScreenTriangle::Vertex FullScreenTriangle::kVertices[FullScreenTriangle::kVertexCount] = {
+ {{-1, -1}},
+ {{-1, 3}},
+ {{3, -1}},
};
// The application itself will be encapsulated in a C++ `struct` type
@@ -60,333 +62,336 @@ const FullScreenTriangle::Vertex FullScreenTriangle::kVertices[FullScreenTriangl
struct ShaderToyApp : public WindowedAppBase
{
-// The uniform data used by the shader is defined here as a simple
-// POD ("plain old data") type.
-//
-// Note: This type must match the declaration of `ShaderToyUniforms`
-// in the file `shader-toy.slang`.
-//
-// An application could instead use a shared header file to define
-// this type, or use Slang's reflection capabilities to allocate
-// and set parameters at runtime. For this simple example we did
-// the expedient thing of having distinct Slang and C++ declarations.
-//
-struct Uniforms
-{
- float iMouse[4];
- float iResolution[2];
- float iTime;
-};
-
-// The main interesting part of the host application code is where we
-// load, compile, inspect, and compose the Slang shader code.
-//
-Result loadShaderProgram(gfx::IDevice* device, ComPtr<gfx::IShaderProgram>& outShaderProgram)
-{
- // We need to obatin a compilation session (`slang::ISession`) that will provide
- // a scope to all the compilation and loading of code we do.
- //
- // Our example application uses the `gfx` graphics API abstraction layer, which already
- // creates a Slang compilation session for us, so we just grab and use it here.
- ComPtr<slang::ISession> slangSession;
- SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef()));
-
- // Once the session has been obtained, we can start loading code into it.
- //
- // The simplest way to load code is by calling `loadModule` with the name of a Slang
- // module. A call to `loadModule("MyStuff")` will behave more or less as if you
- // wrote:
- //
- // import MyStuff;
- //
- // In a Slang shader file. The compiler will use its search paths to try to locate
- // `MyModule.slang`, then compile and load that file. If a matching module had
- // already been loaded previously, that would be used directly.
+ // The uniform data used by the shader is defined here as a simple
+ // POD ("plain old data") type.
//
- // Note: The only interesting wrinkle here is that our file is named `shader-toy` with
- // a hyphen in it, so the name is not directly usable as an identifier in Slang code.
- // Instead, when trying to import this module in the context of Slang code, a user
- // needs to replace the hyphens with underscores:
+ // Note: This type must match the declaration of `ShaderToyUniforms`
+ // in the file `shader-toy.slang`.
//
- // import shader_toy;
+ // An application could instead use a shared header file to define
+ // this type, or use Slang's reflection capabilities to allocate
+ // and set parameters at runtime. For this simple example we did
+ // the expedient thing of having distinct Slang and C++ declarations.
//
- ComPtr<slang::IBlob> diagnosticsBlob;
- Slang::String shaderToyPath = resourceBase.resolveResource("shader-toy.slang");
- slang::IModule* module = slangSession->loadModule(shaderToyPath.getBuffer(), diagnosticsBlob.writeRef());
- diagnoseIfNeeded(diagnosticsBlob);
- if(!module)
- return SLANG_FAIL;
-
- // Loading the `shader-toy` module will compile and check all the shader code in it,
- // including the shader entry points we want to use. Now that the module is loaded
- // we can look up those entry points by name.
- //
- // Note: If you are using this `loadModule` approach to load your shader code it is
- // important to tag your entry point functions with the `[shader("...")]` attribute
- // (e.g., `[shader("vertex")] void vertexMain(...)`). Without that information there
- // is no umambiguous way for the compiler to know which functions represent entry
- // points when it parses your code via `loadModule()`.
- //
- char const* vertexEntryPointName = "vertexMain";
- char const* fragmentEntryPointName = "fragmentMain";
- //
- ComPtr<slang::IEntryPoint> vertexEntryPoint;
- SLANG_RETURN_ON_FAIL(module->findEntryPointByName(vertexEntryPointName, vertexEntryPoint.writeRef()));
- //
- ComPtr<slang::IEntryPoint> fragmentEntryPoint;
- SLANG_RETURN_ON_FAIL(module->findEntryPointByName(fragmentEntryPointName, fragmentEntryPoint.writeRef()));
+ struct Uniforms
+ {
+ float iMouse[4];
+ float iResolution[2];
+ float iTime;
+ };
- // At this point we have a few different Slang API objects that represent
- // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`.
- //
- // A single Slang module could contain many different entry points (e.g.,
- // four vertex entry points, three fragment entry points, and two compute
- // shaders), and before we try to generate output code for our target API
- // we need to identify which entry points we plan to use together.
- //
- // Modules and entry points are both examples of *component types* in the
- // Slang API. The API also provides a way to build a *composite* out of
- // other pieces, and that is what we are going to do with our module
- // and entry points.
- //
- Slang::List<slang::IComponentType*> componentTypes;
- componentTypes.add(module);
-
- // Later on when we go to extract compiled kernel code for our vertex
- // and fragment shaders, we will need to make use of their order within
- // the composition, so we will record the relative ordering of the entry
- // points here as we add them.
- int entryPointCount = 0;
- int vertexEntryPointIndex = entryPointCount++;
- componentTypes.add(vertexEntryPoint);
-
- int fragmentEntryPointIndex = entryPointCount++;
- componentTypes.add(fragmentEntryPoint);
-
- // Actually creating the composite component type is a single operation
- // on the Slang session, but the operation could potentially fail if
- // something about the composite was invalid (e.g., you are trying to
- // combine multiple copies of the same module), so we need to deal
- // with the possibility of diagnostic output.
- //
- ComPtr<slang::IComponentType> composedProgram;
- SlangResult result = slangSession->createCompositeComponentType(
- componentTypes.getBuffer(),
- componentTypes.getCount(),
- composedProgram.writeRef(),
- diagnosticsBlob.writeRef());
- diagnoseIfNeeded(diagnosticsBlob);
- SLANG_RETURN_ON_FAIL(result);
-
- // At this point, `composedProgram` represents the shader program
- // we want to run, and the vertex and fragment shader there have
- // been checked.
- //
- // We could use the Slang reflection API on `composedProgram` at this
- // point to query things like the locations and offsets of the
- // various uniform parameters, textures, etc.
+ // The main interesting part of the host application code is where we
+ // load, compile, inspect, and compose the Slang shader code.
//
- // What *cannot* be done yet at this point is actually generating
- // kernel code, because `composedProgram` includes a generic type
- // parameter as part of the `fragmentMain` entry point:
- //
- // void fragmentMain<T : IShaderToyImageShader>(...)
- //
- // Our next task is to load code for a type we'd like to plug in
- // for `T` there.
- //
- // Because Slang supports modular programming, there is no requirement
- // that a type we want to plug in for `T` has to come from the
- // same module, and to demonstrate that we will load a different
- // module to provide the effect type we will plug in.
- //
- const char* effectTypeName = "ExampleEffect";
- Slang::String effectModulePath = resourceBase.resolveResource("example-effect.slang");
- slang::IModule* effectModule = slangSession->loadModule(effectModulePath.getBuffer(), diagnosticsBlob.writeRef());
- diagnoseIfNeeded(diagnosticsBlob);
- if(!module)
- return SLANG_FAIL;
-
- // Once we've loaded the code module that defines out effect type,
- // we can look it up by name using the reflection information on
- // the module.
- //
- // Note: A future version of the Slang API will support enumerating
- // the types declared in a module so that we do not have to hard-code
- // the name here.
- //
- auto effectType = effectModule->getLayout()->findTypeByName(effectTypeName);
+ Result loadShaderProgram(gfx::IDevice* device, ComPtr<gfx::IShaderProgram>& outShaderProgram)
+ {
+ // We need to obatin a compilation session (`slang::ISession`) that will provide
+ // a scope to all the compilation and loading of code we do.
+ //
+ // Our example application uses the `gfx` graphics API abstraction layer, which already
+ // creates a Slang compilation session for us, so we just grab and use it here.
+ ComPtr<slang::ISession> slangSession;
+ SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef()));
- // Now that we have the `effectType` we want to plug in to our generic
- // shader, we need to specialize the shader to that type.
- //
- // Because a shader program could have zero or more specialization parameters,
- // we need to build up an array of specialization arguments.
- //
- Slang::List<slang::SpecializationArg> specializationArgs;
+ // Once the session has been obtained, we can start loading code into it.
+ //
+ // The simplest way to load code is by calling `loadModule` with the name of a Slang
+ // module. A call to `loadModule("MyStuff")` will behave more or less as if you
+ // wrote:
+ //
+ // import MyStuff;
+ //
+ // In a Slang shader file. The compiler will use its search paths to try to locate
+ // `MyModule.slang`, then compile and load that file. If a matching module had
+ // already been loaded previously, that would be used directly.
+ //
+ // Note: The only interesting wrinkle here is that our file is named `shader-toy` with
+ // a hyphen in it, so the name is not directly usable as an identifier in Slang code.
+ // Instead, when trying to import this module in the context of Slang code, a user
+ // needs to replace the hyphens with underscores:
+ //
+ // import shader_toy;
+ //
+ ComPtr<slang::IBlob> diagnosticsBlob;
+ Slang::String shaderToyPath = resourceBase.resolveResource("shader-toy.slang");
+ slang::IModule* module =
+ slangSession->loadModule(shaderToyPath.getBuffer(), diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ if (!module)
+ return SLANG_FAIL;
+
+ // Loading the `shader-toy` module will compile and check all the shader code in it,
+ // including the shader entry points we want to use. Now that the module is loaded
+ // we can look up those entry points by name.
+ //
+ // Note: If you are using this `loadModule` approach to load your shader code it is
+ // important to tag your entry point functions with the `[shader("...")]` attribute
+ // (e.g., `[shader("vertex")] void vertexMain(...)`). Without that information there
+ // is no umambiguous way for the compiler to know which functions represent entry
+ // points when it parses your code via `loadModule()`.
+ //
+ char const* vertexEntryPointName = "vertexMain";
+ char const* fragmentEntryPointName = "fragmentMain";
+ //
+ ComPtr<slang::IEntryPoint> vertexEntryPoint;
+ SLANG_RETURN_ON_FAIL(
+ module->findEntryPointByName(vertexEntryPointName, vertexEntryPoint.writeRef()));
+ //
+ ComPtr<slang::IEntryPoint> fragmentEntryPoint;
+ SLANG_RETURN_ON_FAIL(
+ module->findEntryPointByName(fragmentEntryPointName, fragmentEntryPoint.writeRef()));
- {
- // In our case, we only have a single specialization argument we plan
- // to use, and it is a type argument.
+ // At this point we have a few different Slang API objects that represent
+ // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`.
+ //
+ // A single Slang module could contain many different entry points (e.g.,
+ // four vertex entry points, three fragment entry points, and two compute
+ // shaders), and before we try to generate output code for our target API
+ // we need to identify which entry points we plan to use together.
+ //
+ // Modules and entry points are both examples of *component types* in the
+ // Slang API. The API also provides a way to build a *composite* out of
+ // other pieces, and that is what we are going to do with our module
+ // and entry points.
+ //
+ Slang::List<slang::IComponentType*> componentTypes;
+ componentTypes.add(module);
+
+ // Later on when we go to extract compiled kernel code for our vertex
+ // and fragment shaders, we will need to make use of their order within
+ // the composition, so we will record the relative ordering of the entry
+ // points here as we add them.
+ int entryPointCount = 0;
+ int vertexEntryPointIndex = entryPointCount++;
+ componentTypes.add(vertexEntryPoint);
+
+ int fragmentEntryPointIndex = entryPointCount++;
+ componentTypes.add(fragmentEntryPoint);
+
+ // Actually creating the composite component type is a single operation
+ // on the Slang session, but the operation could potentially fail if
+ // something about the composite was invalid (e.g., you are trying to
+ // combine multiple copies of the same module), so we need to deal
+ // with the possibility of diagnostic output.
+ //
+ ComPtr<slang::IComponentType> composedProgram;
+ SlangResult result = slangSession->createCompositeComponentType(
+ componentTypes.getBuffer(),
+ componentTypes.getCount(),
+ composedProgram.writeRef(),
+ diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ SLANG_RETURN_ON_FAIL(result);
+
+ // At this point, `composedProgram` represents the shader program
+ // we want to run, and the vertex and fragment shader there have
+ // been checked.
+ //
+ // We could use the Slang reflection API on `composedProgram` at this
+ // point to query things like the locations and offsets of the
+ // various uniform parameters, textures, etc.
+ //
+ // What *cannot* be done yet at this point is actually generating
+ // kernel code, because `composedProgram` includes a generic type
+ // parameter as part of the `fragmentMain` entry point:
+ //
+ // void fragmentMain<T : IShaderToyImageShader>(...)
+ //
+ // Our next task is to load code for a type we'd like to plug in
+ // for `T` there.
+ //
+ // Because Slang supports modular programming, there is no requirement
+ // that a type we want to plug in for `T` has to come from the
+ // same module, and to demonstrate that we will load a different
+ // module to provide the effect type we will plug in.
+ //
+ const char* effectTypeName = "ExampleEffect";
+ Slang::String effectModulePath = resourceBase.resolveResource("example-effect.slang");
+ slang::IModule* effectModule =
+ slangSession->loadModule(effectModulePath.getBuffer(), diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ if (!module)
+ return SLANG_FAIL;
+
+ // Once we've loaded the code module that defines out effect type,
+ // we can look it up by name using the reflection information on
+ // the module.
+ //
+ // Note: A future version of the Slang API will support enumerating
+ // the types declared in a module so that we do not have to hard-code
+ // the name here.
+ //
+ auto effectType = effectModule->getLayout()->findTypeByName(effectTypeName);
+
+ // Now that we have the `effectType` we want to plug in to our generic
+ // shader, we need to specialize the shader to that type.
+ //
+ // Because a shader program could have zero or more specialization parameters,
+ // we need to build up an array of specialization arguments.
//
- slang::SpecializationArg effectTypeArg;
- effectTypeArg.kind = slang::SpecializationArg::Kind::Type;
- effectTypeArg.type = effectType;
- specializationArgs.add(effectTypeArg);
+ Slang::List<slang::SpecializationArg> specializationArgs;
+
+ {
+ // In our case, we only have a single specialization argument we plan
+ // to use, and it is a type argument.
+ //
+ slang::SpecializationArg effectTypeArg;
+ effectTypeArg.kind = slang::SpecializationArg::Kind::Type;
+ effectTypeArg.type = effectType;
+ specializationArgs.add(effectTypeArg);
+ }
+
+ // Specialization of a component type is a single Slang API call, but
+ // we need to deal with the possibility of diagnostic output on failure.
+ // For example, if we tried to specialize the shader program to a
+ // type like `int` that doesn't support the `IShaderToyImageShader` interface,
+ // this is the step where we'd get an error message saying so.
+ //
+ ComPtr<slang::IComponentType> specializedProgram;
+ result = composedProgram->specialize(
+ specializationArgs.getBuffer(),
+ specializationArgs.getCount(),
+ specializedProgram.writeRef(),
+ diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ SLANG_RETURN_ON_FAIL(result);
+
+ // At this point we have a specialized shader program that represents our
+ // intention to run the `vertexMain` and `fragmentMain` entry points,
+ // specialized to the `ExampleEffect` type we loaded.
+ //
+ // We can now *link* the program, which ensures that all of the code that
+ // it transitively depends on has been pulled together into a single
+ // component type.
+ //
+ ComPtr<slang::IComponentType> linkedProgram;
+ result = specializedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ SLANG_RETURN_ON_FAIL(result);
+
+ gfx::IShaderProgram::Desc programDesc = {};
+ programDesc.slangGlobalScope = linkedProgram.get();
+ auto shaderProgram = device->createProgram(programDesc);
+ outShaderProgram = shaderProgram;
+ return SLANG_OK;
}
- // Specialization of a component type is a single Slang API call, but
- // we need to deal with the possibility of diagnostic output on failure.
- // For example, if we tried to specialize the shader program to a
- // type like `int` that doesn't support the `IShaderToyImageShader` interface,
- // this is the step where we'd get an error message saying so.
- //
- ComPtr<slang::IComponentType> specializedProgram;
- result = composedProgram->specialize(
- specializationArgs.getBuffer(),
- specializationArgs.getCount(),
- specializedProgram.writeRef(),
- diagnosticsBlob.writeRef());
- diagnoseIfNeeded(diagnosticsBlob);
- SLANG_RETURN_ON_FAIL(result);
-
- // At this point we have a specialized shader program that represents our
- // intention to run the `vertexMain` and `fragmentMain` entry points,
- // specialized to the `ExampleEffect` type we loaded.
- //
- // We can now *link* the program, which ensures that all of the code that
- // it transitively depends on has been pulled together into a single
- // component type.
- //
- ComPtr<slang::IComponentType> linkedProgram;
- result = specializedProgram->link(
- linkedProgram.writeRef(),
- diagnosticsBlob.writeRef());
- diagnoseIfNeeded(diagnosticsBlob);
- SLANG_RETURN_ON_FAIL(result);
-
- gfx::IShaderProgram::Desc programDesc = {};
- programDesc.slangGlobalScope = linkedProgram.get();
- auto shaderProgram = device->createProgram(programDesc);
- outShaderProgram = shaderProgram;
- return SLANG_OK;
-}
-
-ComPtr<IShaderProgram> gShaderProgram;
-ComPtr<gfx::IPipelineState> gPipelineState;
-ComPtr<gfx::IBufferResource> gVertexBuffer;
-
-Result initialize()
-{
- initializeBase("Shader Toy", 1024, 768);
- gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { handleEvent(e); };
- gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { handleEvent(e); };
- gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { handleEvent(e); };
+ ComPtr<IShaderProgram> gShaderProgram;
+ ComPtr<gfx::IPipelineState> gPipelineState;
+ ComPtr<gfx::IBufferResource> gVertexBuffer;
- InputElementDesc inputElements[] = {
- { "POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position) },
- };
- auto inputLayout = gDevice->createInputLayout(
- sizeof(FullScreenTriangle::Vertex),
- &inputElements[0],
- SLANG_COUNT_OF(inputElements));
- if(!inputLayout) return SLANG_FAIL;
-
- IBufferResource::Desc vertexBufferDesc;
- vertexBufferDesc.type = IResource::Type::Buffer;
- vertexBufferDesc.sizeInBytes = FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex);
- vertexBufferDesc.defaultState = ResourceState::VertexBuffer;
- gVertexBuffer = gDevice->createBufferResource(
- vertexBufferDesc,
- &FullScreenTriangle::kVertices[0]);
- if(!gVertexBuffer) return SLANG_FAIL;
-
- SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, gShaderProgram));
-
- // Create pipeline.
- GraphicsPipelineStateDesc desc;
- desc.inputLayout = inputLayout;
- desc.program = gShaderProgram;
- desc.framebufferLayout = gFramebufferLayout;
- auto pipelineState = gDevice->createGraphicsPipelineState(desc);
- if (!pipelineState)
- return SLANG_FAIL;
-
- gPipelineState = pipelineState;
-
- return SLANG_OK;
-}
-
-bool wasMouseDown = false;
-bool isMouseDown = false;
-float lastMouseX = 0.0f;
-float lastMouseY = 0.0f;
-float clickMouseX = 0.0f;
-float clickMouseY = 0.0f;
-
-bool firstTime = true;
-platform::TimePoint startTime;
-
-virtual void renderFrame(int frameIndex) override
-{
- auto commandBuffer = gTransientHeaps[frameIndex]->createCommandBuffer();
- if( firstTime )
+ Result initialize()
{
- startTime = platform::PerformanceCounter::now();
- firstTime = false;
+ initializeBase("Shader Toy", 1024, 768);
+ gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { handleEvent(e); };
+ gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { handleEvent(e); };
+ gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { handleEvent(e); };
+
+ InputElementDesc inputElements[] = {
+ {"POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position)},
+ };
+ auto inputLayout = gDevice->createInputLayout(
+ sizeof(FullScreenTriangle::Vertex),
+ &inputElements[0],
+ SLANG_COUNT_OF(inputElements));
+ if (!inputLayout)
+ return SLANG_FAIL;
+
+ IBufferResource::Desc vertexBufferDesc;
+ vertexBufferDesc.type = IResource::Type::Buffer;
+ vertexBufferDesc.sizeInBytes =
+ FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex);
+ vertexBufferDesc.defaultState = ResourceState::VertexBuffer;
+ gVertexBuffer =
+ gDevice->createBufferResource(vertexBufferDesc, &FullScreenTriangle::kVertices[0]);
+ if (!gVertexBuffer)
+ return SLANG_FAIL;
+
+ SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, gShaderProgram));
+
+ // Create pipeline.
+ GraphicsPipelineStateDesc desc;
+ desc.inputLayout = inputLayout;
+ desc.program = gShaderProgram;
+ desc.framebufferLayout = gFramebufferLayout;
+ auto pipelineState = gDevice->createGraphicsPipelineState(desc);
+ if (!pipelineState)
+ return SLANG_FAIL;
+
+ gPipelineState = pipelineState;
+
+ return SLANG_OK;
}
- // Update uniform buffer.
+ bool wasMouseDown = false;
+ bool isMouseDown = false;
+ float lastMouseX = 0.0f;
+ float lastMouseY = 0.0f;
+ float clickMouseX = 0.0f;
+ float clickMouseY = 0.0f;
+
+ bool firstTime = true;
+ platform::TimePoint startTime;
- Uniforms uniforms = {};
+ virtual void renderFrame(int frameIndex) override
{
- bool isMouseClick = isMouseDown && !wasMouseDown;
- wasMouseDown = isMouseDown;
+ auto commandBuffer = gTransientHeaps[frameIndex]->createCommandBuffer();
+ if (firstTime)
+ {
+ startTime = platform::PerformanceCounter::now();
+ firstTime = false;
+ }
+
+ // Update uniform buffer.
- if( isMouseClick )
+ Uniforms uniforms = {};
{
- clickMouseX = lastMouseX;
- clickMouseY = lastMouseY;
+ bool isMouseClick = isMouseDown && !wasMouseDown;
+ wasMouseDown = isMouseDown;
+
+ if (isMouseClick)
+ {
+ clickMouseX = lastMouseX;
+ clickMouseY = lastMouseY;
+ }
+
+ uniforms.iMouse[0] = lastMouseX;
+ uniforms.iMouse[1] = lastMouseY;
+ uniforms.iMouse[2] = isMouseDown ? clickMouseX : -clickMouseX;
+ uniforms.iMouse[3] = isMouseClick ? clickMouseY : -clickMouseY;
+ uniforms.iTime = platform::PerformanceCounter::getElapsedTimeInSeconds(startTime);
+ uniforms.iResolution[0] = float(windowWidth);
+ uniforms.iResolution[1] = float(windowHeight);
}
- uniforms.iMouse[0] = lastMouseX;
- uniforms.iMouse[1] = lastMouseY;
- uniforms.iMouse[2] = isMouseDown ? clickMouseX : -clickMouseX;
- uniforms.iMouse[3] = isMouseClick ? clickMouseY : -clickMouseY;
- uniforms.iTime = platform::PerformanceCounter::getElapsedTimeInSeconds(startTime);
- uniforms.iResolution[0] = float(windowWidth);
- uniforms.iResolution[1] = float(windowHeight);
+ // Encode render commands.
+ auto encoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameIndex]);
+
+ gfx::Viewport viewport = {};
+ viewport.maxZ = 1.0f;
+ viewport.extentX = (float)windowWidth;
+ viewport.extentY = (float)windowHeight;
+ encoder->setViewportAndScissor(viewport);
+ auto rootObject = encoder->bindPipeline(gPipelineState);
+ auto constantBuffer = rootObject->getObject(ShaderOffset());
+ constantBuffer->setData(ShaderOffset(), &uniforms, sizeof(uniforms));
+
+ encoder->setVertexBuffer(0, gVertexBuffer);
+ encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList);
+ encoder->draw(3);
+ encoder->endEncoding();
+ commandBuffer->close();
+
+ gQueue->executeCommandBuffer(commandBuffer);
+ gSwapchain->present();
+ }
+ void handleEvent(const platform::MouseEventArgs& event)
+ {
+ isMouseDown = ((int)event.buttons & (int)platform::ButtonState::Enum::LeftButton) != 0;
+ lastMouseX = (float)event.x;
+ lastMouseY = (float)event.y;
}
-
- // Encode render commands.
- auto encoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameIndex]);
-
- gfx::Viewport viewport = {};
- viewport.maxZ = 1.0f;
- viewport.extentX = (float)windowWidth;
- viewport.extentY = (float)windowHeight;
- encoder->setViewportAndScissor(viewport);
- auto rootObject = encoder->bindPipeline(gPipelineState);
- auto constantBuffer = rootObject->getObject(ShaderOffset());
- constantBuffer->setData(ShaderOffset(), &uniforms, sizeof(uniforms));
-
- encoder->setVertexBuffer(0, gVertexBuffer);
- encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList);
- encoder->draw(3);
- encoder->endEncoding();
- commandBuffer->close();
-
- gQueue->executeCommandBuffer(commandBuffer);
- gSwapchain->present();
-}
-
-void handleEvent(const platform::MouseEventArgs& event)
-{
- isMouseDown = ((int)event.buttons & (int)platform::ButtonState::Enum::LeftButton) != 0;
- lastMouseX = (float)event.x;
- lastMouseY = (float)event.y;
-}
};
// This macro instantiates an appropriate main function to
diff --git a/examples/triangle/main.cpp b/examples/triangle/main.cpp
index 88c55c416..d5f929bf2 100644
--- a/examples/triangle/main.cpp
+++ b/examples/triangle/main.cpp
@@ -32,12 +32,12 @@
// with Slang may depend on an application/engine making certain
// design choices in their abstraction layer.
//
-#include "slang-gfx.h"
+#include "examples/example-base/example-base.h"
#include "gfx-util/shader-cursor.h"
-#include "tools/platform/window.h"
#include "slang-com-ptr.h"
+#include "slang-gfx.h"
#include "source/core/slang-basic.h"
-#include "examples/example-base/example-base.h"
+#include "tools/platform/window.h"
using namespace gfx;
using namespace Slang;
@@ -55,11 +55,10 @@ struct Vertex
};
static const int kVertexCount = 3;
-static const Vertex kVertexData[kVertexCount] =
-{
- { { 0, 0, 0.5 }, { 1, 0, 0 } },
- { { 0, 1, 0.5 }, { 0, 0, 1 } },
- { { 1, 0, 0.5 }, { 0, 1, 0 } },
+static const Vertex kVertexData[kVertexCount] = {
+ {{0, 0, 0.5}, {1, 0, 0}},
+ {{0, 1, 0.5}, {0, 0, 1}},
+ {{1, 0, 0.5}, {0, 1, 0}},
};
// The example application will be implemented as a `struct`, so that
@@ -68,338 +67,340 @@ static const Vertex kVertexData[kVertexCount] =
struct HelloWorld : public WindowedAppBase
{
-// Many Slang API functions return detailed diagnostic information
-// (error messages, warnings, etc.) as a "blob" of data, or return
-// a null blob pointer instead if there were no issues.
-//
-// For convenience, we define a subroutine that will dump the information
-// in a diagnostic blob if one is produced, and skip it otherwise.
-//
-void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob)
-{
- if( diagnosticsBlob != nullptr )
- {
- printf("%s", (const char*) diagnosticsBlob->getBufferPointer());
- }
-}
-
-// The main task an application cares about is compiling shader code
-// from souce (if needed) and loading it through the chosen graphics API.
-//
-// In addition, an application may want to receive reflection information
-// about the program, which is what a `slang::ProgramLayout` provides.
-//
-gfx::Result loadShaderProgram(
- gfx::IDevice* device,
- gfx::IShaderProgram** outProgram)
-{
- // We need to obatin a compilation session (`slang::ISession`) that will provide
- // a scope to all the compilation and loading of code we do.
- //
- // Our example application uses the `gfx` graphics API abstraction layer, which already
- // creates a Slang compilation session for us, so we just grab and use it here.
- ComPtr<slang::ISession> slangSession;
- slangSession = device->getSlangSession();
-
- // We can now start loading code into the slang session.
- //
- // The simplest way to load code is by calling `loadModule` with the name of a Slang
- // module. A call to `loadModule("MyStuff")` will behave more or less as if you
- // wrote:
- //
- // import MyStuff;
- //
- // In a Slang shader file. The compiler will use its search paths to try to locate
- // `MyModule.slang`, then compile and load that file. If a matching module had
- // already been loaded previously, that would be used directly.
+ // Many Slang API functions return detailed diagnostic information
+ // (error messages, warnings, etc.) as a "blob" of data, or return
+ // a null blob pointer instead if there were no issues.
//
- ComPtr<slang::IBlob> diagnosticsBlob;
- Slang::String path = resourceBase.resolveResource("shaders.slang");
- slang::IModule* module = slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef());
- diagnoseIfNeeded(diagnosticsBlob);
- if(!module)
- return SLANG_FAIL;
-
- // Loading the `shaders` module will compile and check all the shader code in it,
- // including the shader entry points we want to use. Now that the module is loaded
- // we can look up those entry points by name.
+ // For convenience, we define a subroutine that will dump the information
+ // in a diagnostic blob if one is produced, and skip it otherwise.
//
- // Note: If you are using this `loadModule` approach to load your shader code it is
- // important to tag your entry point functions with the `[shader("...")]` attribute
- // (e.g., `[shader("vertex")] void vertexMain(...)`). Without that information there
- // is no umambiguous way for the compiler to know which functions represent entry
- // points when it parses your code via `loadModule()`.
- //
- ComPtr<slang::IEntryPoint> vertexEntryPoint;
- SLANG_RETURN_ON_FAIL(module->findEntryPointByName("vertexMain", vertexEntryPoint.writeRef()));
- //
- ComPtr<slang::IEntryPoint> fragmentEntryPoint;
- SLANG_RETURN_ON_FAIL(module->findEntryPointByName("fragmentMain", fragmentEntryPoint.writeRef()));
+ void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob)
+ {
+ if (diagnosticsBlob != nullptr)
+ {
+ printf("%s", (const char*)diagnosticsBlob->getBufferPointer());
+ }
+ }
- // At this point we have a few different Slang API objects that represent
- // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`.
- //
- // A single Slang module could contain many different entry points (e.g.,
- // four vertex entry points, three fragment entry points, and two compute
- // shaders), and before we try to generate output code for our target API
- // we need to identify which entry points we plan to use together.
- //
- // Modules and entry points are both examples of *component types* in the
- // Slang API. The API also provides a way to build a *composite* out of
- // other pieces, and that is what we are going to do with our module
- // and entry points.
- //
- Slang::List<slang::IComponentType*> componentTypes;
- componentTypes.add(module);
-
- // Later on when we go to extract compiled kernel code for our vertex
- // and fragment shaders, we will need to make use of their order within
- // the composition, so we will record the relative ordering of the entry
- // points here as we add them.
- int entryPointCount = 0;
- int vertexEntryPointIndex = entryPointCount++;
- componentTypes.add(vertexEntryPoint);
-
- int fragmentEntryPointIndex = entryPointCount++;
- componentTypes.add(fragmentEntryPoint);
-
- // Actually creating the composite component type is a single operation
- // on the Slang session, but the operation could potentially fail if
- // something about the composite was invalid (e.g., you are trying to
- // combine multiple copies of the same module), so we need to deal
- // with the possibility of diagnostic output.
+ // The main task an application cares about is compiling shader code
+ // from souce (if needed) and loading it through the chosen graphics API.
//
- ComPtr<slang::IComponentType> linkedProgram;
- SlangResult result = slangSession->createCompositeComponentType(
- componentTypes.getBuffer(),
- componentTypes.getCount(),
- linkedProgram.writeRef(),
- diagnosticsBlob.writeRef());
- diagnoseIfNeeded(diagnosticsBlob);
- SLANG_RETURN_ON_FAIL(result);
-
- // Once we've described the particular composition of entry points
- // that we want to compile, we defer to the graphics API layer
- // to extract compiled kernel code and load it into the API-specific
- // program representation.
+ // In addition, an application may want to receive reflection information
+ // about the program, which is what a `slang::ProgramLayout` provides.
//
- gfx::IShaderProgram::Desc programDesc = {};
- programDesc.slangGlobalScope = linkedProgram;
- SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram));
-
- if (isTestMode())
+ gfx::Result loadShaderProgram(gfx::IDevice* device, gfx::IShaderProgram** outProgram)
{
- printEntrypointHashes(entryPointCount, 1, linkedProgram);
- }
+ // We need to obatin a compilation session (`slang::ISession`) that will provide
+ // a scope to all the compilation and loading of code we do.
+ //
+ // Our example application uses the `gfx` graphics API abstraction layer, which already
+ // creates a Slang compilation session for us, so we just grab and use it here.
+ ComPtr<slang::ISession> slangSession;
+ slangSession = device->getSlangSession();
- return SLANG_OK;
-}
+ // We can now start loading code into the slang session.
+ //
+ // The simplest way to load code is by calling `loadModule` with the name of a Slang
+ // module. A call to `loadModule("MyStuff")` will behave more or less as if you
+ // wrote:
+ //
+ // import MyStuff;
+ //
+ // In a Slang shader file. The compiler will use its search paths to try to locate
+ // `MyModule.slang`, then compile and load that file. If a matching module had
+ // already been loaded previously, that would be used directly.
+ //
+ ComPtr<slang::IBlob> diagnosticsBlob;
+ Slang::String path = resourceBase.resolveResource("shaders.slang");
+ slang::IModule* module =
+ slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ if (!module)
+ return SLANG_FAIL;
+
+ // Loading the `shaders` module will compile and check all the shader code in it,
+ // including the shader entry points we want to use. Now that the module is loaded
+ // we can look up those entry points by name.
+ //
+ // Note: If you are using this `loadModule` approach to load your shader code it is
+ // important to tag your entry point functions with the `[shader("...")]` attribute
+ // (e.g., `[shader("vertex")] void vertexMain(...)`). Without that information there
+ // is no umambiguous way for the compiler to know which functions represent entry
+ // points when it parses your code via `loadModule()`.
+ //
+ ComPtr<slang::IEntryPoint> vertexEntryPoint;
+ SLANG_RETURN_ON_FAIL(
+ module->findEntryPointByName("vertexMain", vertexEntryPoint.writeRef()));
+ //
+ ComPtr<slang::IEntryPoint> fragmentEntryPoint;
+ SLANG_RETURN_ON_FAIL(
+ module->findEntryPointByName("fragmentMain", fragmentEntryPoint.writeRef()));
-//
-// The above function shows the core of what is required to use the
-// Slang API as a simple compiler (e.g., a drop-in replacement for
-// fxc or dxc).
-//
-// The rest of this file implements an extremely simple rendering application
-// that will execute the vertex/fragment shaders loaded with the function
-// we have just defined.
-//
+ // At this point we have a few different Slang API objects that represent
+ // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`.
+ //
+ // A single Slang module could contain many different entry points (e.g.,
+ // four vertex entry points, three fragment entry points, and two compute
+ // shaders), and before we try to generate output code for our target API
+ // we need to identify which entry points we plan to use together.
+ //
+ // Modules and entry points are both examples of *component types* in the
+ // Slang API. The API also provides a way to build a *composite* out of
+ // other pieces, and that is what we are going to do with our module
+ // and entry points.
+ //
+ Slang::List<slang::IComponentType*> componentTypes;
+ componentTypes.add(module);
+
+ // Later on when we go to extract compiled kernel code for our vertex
+ // and fragment shaders, we will need to make use of their order within
+ // the composition, so we will record the relative ordering of the entry
+ // points here as we add them.
+ int entryPointCount = 0;
+ int vertexEntryPointIndex = entryPointCount++;
+ componentTypes.add(vertexEntryPoint);
+
+ int fragmentEntryPointIndex = entryPointCount++;
+ componentTypes.add(fragmentEntryPoint);
+
+ // Actually creating the composite component type is a single operation
+ // on the Slang session, but the operation could potentially fail if
+ // something about the composite was invalid (e.g., you are trying to
+ // combine multiple copies of the same module), so we need to deal
+ // with the possibility of diagnostic output.
+ //
+ ComPtr<slang::IComponentType> linkedProgram;
+ SlangResult result = slangSession->createCompositeComponentType(
+ componentTypes.getBuffer(),
+ componentTypes.getCount(),
+ linkedProgram.writeRef(),
+ diagnosticsBlob.writeRef());
+ diagnoseIfNeeded(diagnosticsBlob);
+ SLANG_RETURN_ON_FAIL(result);
+
+ // Once we've described the particular composition of entry points
+ // that we want to compile, we defer to the graphics API layer
+ // to extract compiled kernel code and load it into the API-specific
+ // program representation.
+ //
+ gfx::IShaderProgram::Desc programDesc = {};
+ programDesc.slangGlobalScope = linkedProgram;
+ SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram));
-// We will define global variables for the various platform and
-// graphics API objects that our application needs:
-//
-// As a reminder, *none* of these are Slang API objects. All
-// of them come from the utility library we are using to simplify
-// building an example program.
-//
-ComPtr<gfx::IPipelineState> gPipelineState;
-ComPtr<gfx::IBufferResource> gVertexBuffer;
+ if (isTestMode())
+ {
+ printEntrypointHashes(entryPointCount, 1, linkedProgram);
+ }
-// Now that we've covered the function that actually loads and
-// compiles our Slang shade code, we can go through the rest
-// of the application code without as much commentary.
-//
-Slang::Result initialize()
-{
- // Create a window for our application to render into.
- //
- initializeBase("hello-world", 1024, 768);
+ return SLANG_OK;
+ }
- // We will create objects needed to configur the "input assembler"
- // (IA) stage of the D3D pipeline.
//
- // First, we create an input layout:
+ // The above function shows the core of what is required to use the
+ // Slang API as a simple compiler (e.g., a drop-in replacement for
+ // fxc or dxc).
//
- InputElementDesc inputElements[] = {
- { "POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position) },
- { "COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color) },
- };
- auto inputLayout = gDevice->createInputLayout(
- sizeof(Vertex),
- &inputElements[0],
- 2);
- if(!inputLayout) return SLANG_FAIL;
-
- // Next we allocate a vertex buffer for our pre-initialized
- // vertex data.
+ // The rest of this file implements an extremely simple rendering application
+ // that will execute the vertex/fragment shaders loaded with the function
+ // we have just defined.
//
- IBufferResource::Desc vertexBufferDesc;
- vertexBufferDesc.type = IResource::Type::Buffer;
- vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex);
- vertexBufferDesc.defaultState = ResourceState::VertexBuffer;
- gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]);
- if(!gVertexBuffer) return SLANG_FAIL;
-
- // Now we will use our `loadShaderProgram` function to load
- // the code from `shaders.slang` into the graphics API.
- //
- ComPtr<IShaderProgram> shaderProgram;
- SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, shaderProgram.writeRef()));
- // Following the D3D12/Vulkan style of API, we need a pipeline state object
- // (PSO) to encapsulate the configuration of the overall graphics pipeline.
+ // We will define global variables for the various platform and
+ // graphics API objects that our application needs:
//
- GraphicsPipelineStateDesc desc;
- desc.inputLayout = inputLayout;
- desc.program = shaderProgram;
- desc.framebufferLayout = gFramebufferLayout;
- auto pipelineState = gDevice->createGraphicsPipelineState(desc);
- if (!pipelineState)
- return SLANG_FAIL;
-
- gPipelineState = pipelineState;
-
- return SLANG_OK;
-}
-
-// With the initialization out of the way, we can now turn our attention
-// to the per-frame rendering logic. As with the initialization, there is
-// nothing really Slang-specific here, so the commentary doesn't need
-// to be very detailed.
-//
-virtual void renderFrame(int frameBufferIndex) override
-{
- ComPtr<ICommandBuffer> commandBuffer = gTransientHeaps[frameBufferIndex]->createCommandBuffer();
- auto renderEncoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]);
-
- gfx::Viewport viewport = {};
- viewport.maxZ = 1.0f;
- viewport.extentX = (float)windowWidth;
- viewport.extentY = (float)windowHeight;
- renderEncoder->setViewportAndScissor(viewport);
-
- // In order to bind shader parameters to the pipeline, we need
- // to know how those parameters were assigned to locations/bindings/registers
- // for the target graphics API.
+ // As a reminder, *none* of these are Slang API objects. All
+ // of them come from the utility library we are using to simplify
+ // building an example program.
//
- // The Slang compiler assigns locations to parameters in a deterministic
- // fashion, so it is possible for a programmer to hard-code locations
- // into their application code that will match up with their shaders.
- //
- // Hard-coding of locations can become intractable as an application needs
- // to support more different target platforms and graphics APIs, as well
- // as more shaders with different specialized variants.
- //
- // Rather than rely on hard-coded locations, our examples will make use of
- // reflection information provided by the Slang compiler (see `programLayout`
- // above), and our example graphics API layer will translate that reflection
- // information into a layout for a "root shader object."
- //
- // The root object will store values/bindings for all of the parameters in
- // the `IShaderProgram` used to create the pipeline state. At a conceptual
- // level we can think of `rootObject` as representing the "global scope" of
- // the shader program that was loaded; it has entries for each global shader
- // parameter that was declared.
- //
- // Readers who are familiar with D3D12 or Vulkan might think of this root
- // layout as being similar in spirit to a "root signature" or "pipeline layout."
- //
- // We start parameter binding by binding the pipeline state in command encoder.
- // This method will return a transient root shader object for us to write our
- // shader parameters into.
- //
- auto rootObject = renderEncoder->bindPipeline(gPipelineState);
+ ComPtr<gfx::IPipelineState> gPipelineState;
+ ComPtr<gfx::IBufferResource> gVertexBuffer;
- // We will update the model-view-projection matrix that is passed
- // into the shader code via the `Uniforms` buffer on a per-frame
- // basis, even though the data that is loaded does not change
- // per-frame (we always use an identity matrix).
+ // Now that we've covered the function that actually loads and
+ // compiles our Slang shade code, we can go through the rest
+ // of the application code without as much commentary.
//
- auto deviceInfo = gDevice->getDeviceInfo();
+ Slang::Result initialize()
+ {
+ // Create a window for our application to render into.
+ //
+ initializeBase("hello-world", 1024, 768);
- // We know that `rootObject` is a root shader object created
- // from our program, and that it is set up to hold values for
- // all the parameter of that program. In order to actually
- // set values, we need to be able to look up the location
- // of speciic parameter that we want to set.
- //
- // Our example graphics API layer supports this operation
- // with the idea of a *shader cursor* which can be thought
- // of as pointing "into" a particular shader object at
- // some location/offset. This design choice abstracts over
- // the many ways that different platforms and APIs represent
- // the necessary offset information.
- //
- // We construct an initial shader cursor that points at the
- // entire shader program. You can think of this as akin to
- // a diretory path of `/` for the root directory in a file
- // system.
- //
- ShaderCursor rootCursor(rootObject);
- //
- // Next, we use a convenience overload of `operator[]` to
- // navigate from the root cursor down to the parameter we
- // want to set.
- //
- // The operation `rootCursor["Uniforms"]` looks up the
- // offset/location of the global shader parameter `Uniforms`
- // (which is a uniform/constant buffer), and the subsequent
- // `["modelViewProjection"]` step navigates from there down
- // to the member named `modelViewProjection` in that buffer.
- //
- // Once we have formed a cursor that "points" at the
- // model-view projection matrix, we can set its data directly.
- //
- rootCursor["Uniforms"]["modelViewProjection"].setData(
- deviceInfo.identityProjectionMatrix, sizeof(float) * 16);
- //
- // Some readers might be concerned about the performance o
- // the above operations because of the use of strings. For
- // those readers, here are two things to note:
- //
- // * While these `operator[]` steps do need to perform string
- // comparisons, they do *not* make copies of the strings or
- // perform any heap allocation.
- //
- // * There are other overloads of `operator[]` that use the
- // *index* of a parameter/field instead of its name, and those
- // operations have fixed/constant overhead and perform no
- // string comparisons. The indices used are independent of
- // the target platform and graphics API, and can thus be
- // hard-coded even in cross-platform code.
- //
+ // We will create objects needed to configur the "input assembler"
+ // (IA) stage of the D3D pipeline.
+ //
+ // First, we create an input layout:
+ //
+ InputElementDesc inputElements[] = {
+ {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position)},
+ {"COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color)},
+ };
+ auto inputLayout = gDevice->createInputLayout(sizeof(Vertex), &inputElements[0], 2);
+ if (!inputLayout)
+ return SLANG_FAIL;
+
+ // Next we allocate a vertex buffer for our pre-initialized
+ // vertex data.
+ //
+ IBufferResource::Desc vertexBufferDesc;
+ vertexBufferDesc.type = IResource::Type::Buffer;
+ vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex);
+ vertexBufferDesc.defaultState = ResourceState::VertexBuffer;
+ gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]);
+ if (!gVertexBuffer)
+ return SLANG_FAIL;
+
+ // Now we will use our `loadShaderProgram` function to load
+ // the code from `shaders.slang` into the graphics API.
+ //
+ ComPtr<IShaderProgram> shaderProgram;
+ SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, shaderProgram.writeRef()));
- // We also need to set up a few pieces of fixed-function pipeline
- // state that are not bound by the pipeline state above.
- //
- renderEncoder->setVertexBuffer(0, gVertexBuffer);
- renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList);
+ // Following the D3D12/Vulkan style of API, we need a pipeline state object
+ // (PSO) to encapsulate the configuration of the overall graphics pipeline.
+ //
+ GraphicsPipelineStateDesc desc;
+ desc.inputLayout = inputLayout;
+ desc.program = shaderProgram;
+ desc.framebufferLayout = gFramebufferLayout;
+ auto pipelineState = gDevice->createGraphicsPipelineState(desc);
+ if (!pipelineState)
+ return SLANG_FAIL;
- // Finally, we are ready to issue a draw call for a single triangle.
- //
- renderEncoder->draw(3);
- renderEncoder->endEncoding();
- commandBuffer->close();
- gQueue->executeCommandBuffer(commandBuffer);
+ gPipelineState = pipelineState;
+
+ return SLANG_OK;
+ }
- if (!isTestMode())
+ // With the initialization out of the way, we can now turn our attention
+ // to the per-frame rendering logic. As with the initialization, there is
+ // nothing really Slang-specific here, so the commentary doesn't need
+ // to be very detailed.
+ //
+ virtual void renderFrame(int frameBufferIndex) override
{
- // With that, we are done drawing for one frame, and ready for the next.
+ ComPtr<ICommandBuffer> commandBuffer =
+ gTransientHeaps[frameBufferIndex]->createCommandBuffer();
+ auto renderEncoder =
+ commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]);
+
+ gfx::Viewport viewport = {};
+ viewport.maxZ = 1.0f;
+ viewport.extentX = (float)windowWidth;
+ viewport.extentY = (float)windowHeight;
+ renderEncoder->setViewportAndScissor(viewport);
+
+ // In order to bind shader parameters to the pipeline, we need
+ // to know how those parameters were assigned to locations/bindings/registers
+ // for the target graphics API.
//
- gSwapchain->present();
- }
-}
+ // The Slang compiler assigns locations to parameters in a deterministic
+ // fashion, so it is possible for a programmer to hard-code locations
+ // into their application code that will match up with their shaders.
+ //
+ // Hard-coding of locations can become intractable as an application needs
+ // to support more different target platforms and graphics APIs, as well
+ // as more shaders with different specialized variants.
+ //
+ // Rather than rely on hard-coded locations, our examples will make use of
+ // reflection information provided by the Slang compiler (see `programLayout`
+ // above), and our example graphics API layer will translate that reflection
+ // information into a layout for a "root shader object."
+ //
+ // The root object will store values/bindings for all of the parameters in
+ // the `IShaderProgram` used to create the pipeline state. At a conceptual
+ // level we can think of `rootObject` as representing the "global scope" of
+ // the shader program that was loaded; it has entries for each global shader
+ // parameter that was declared.
+ //
+ // Readers who are familiar with D3D12 or Vulkan might think of this root
+ // layout as being similar in spirit to a "root signature" or "pipeline layout."
+ //
+ // We start parameter binding by binding the pipeline state in command encoder.
+ // This method will return a transient root shader object for us to write our
+ // shader parameters into.
+ //
+ auto rootObject = renderEncoder->bindPipeline(gPipelineState);
+
+ // We will update the model-view-projection matrix that is passed
+ // into the shader code via the `Uniforms` buffer on a per-frame
+ // basis, even though the data that is loaded does not change
+ // per-frame (we always use an identity matrix).
+ //
+ auto deviceInfo = gDevice->getDeviceInfo();
+ // We know that `rootObject` is a root shader object created
+ // from our program, and that it is set up to hold values for
+ // all the parameter of that program. In order to actually
+ // set values, we need to be able to look up the location
+ // of speciic parameter that we want to set.
+ //
+ // Our example graphics API layer supports this operation
+ // with the idea of a *shader cursor* which can be thought
+ // of as pointing "into" a particular shader object at
+ // some location/offset. This design choice abstracts over
+ // the many ways that different platforms and APIs represent
+ // the necessary offset information.
+ //
+ // We construct an initial shader cursor that points at the
+ // entire shader program. You can think of this as akin to
+ // a diretory path of `/` for the root directory in a file
+ // system.
+ //
+ ShaderCursor rootCursor(rootObject);
+ //
+ // Next, we use a convenience overload of `operator[]` to
+ // navigate from the root cursor down to the parameter we
+ // want to set.
+ //
+ // The operation `rootCursor["Uniforms"]` looks up the
+ // offset/location of the global shader parameter `Uniforms`
+ // (which is a uniform/constant buffer), and the subsequent
+ // `["modelViewProjection"]` step navigates from there down
+ // to the member named `modelViewProjection` in that buffer.
+ //
+ // Once we have formed a cursor that "points" at the
+ // model-view projection matrix, we can set its data directly.
+ //
+ rootCursor["Uniforms"]["modelViewProjection"].setData(
+ deviceInfo.identityProjectionMatrix,
+ sizeof(float) * 16);
+ //
+ // Some readers might be concerned about the performance o
+ // the above operations because of the use of strings. For
+ // those readers, here are two things to note:
+ //
+ // * While these `operator[]` steps do need to perform string
+ // comparisons, they do *not* make copies of the strings or
+ // perform any heap allocation.
+ //
+ // * There are other overloads of `operator[]` that use the
+ // *index* of a parameter/field instead of its name, and those
+ // operations have fixed/constant overhead and perform no
+ // string comparisons. The indices used are independent of
+ // the target platform and graphics API, and can thus be
+ // hard-coded even in cross-platform code.
+ //
+
+ // We also need to set up a few pieces of fixed-function pipeline
+ // state that are not bound by the pipeline state above.
+ //
+ renderEncoder->setVertexBuffer(0, gVertexBuffer);
+ renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList);
+
+ // Finally, we are ready to issue a draw call for a single triangle.
+ //
+ renderEncoder->draw(3);
+ renderEncoder->endEncoding();
+ commandBuffer->close();
+ gQueue->executeCommandBuffer(commandBuffer);
+
+ if (!isTestMode())
+ {
+ // With that, we are done drawing for one frame, and ready for the next.
+ //
+ gSwapchain->present();
+ }
+ }
};
// This macro instantiates an appropriate main function to