summaryrefslogtreecommitdiff
path: root/examples/experimental/heterogeneous-hello-world/main.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2021-03-04 16:25:58 -0800
committerGitHub <noreply@github.com>2021-03-04 16:25:58 -0800
commita5ac4999b4dea546a7ef824669ab1809224b6448 (patch)
tree15bb22eb98a94f7f81489deef55396461501d3dc /examples/experimental/heterogeneous-hello-world/main.cpp
parent13ff0bd345990c0fdfb7b52ebd5339cddb04889e (diff)
Refactor `gfx` to surface `CommandBuffer` interface. (#1735)
* Refactor `gfx` to surface `CommandBuffer` interface. * Fixes. * Fix code review issues, and make vulkan runnable on devices without VK_EXT_extended_dynamic_states. * Update solution files * Move out-of-date examples to examples/experimental Co-authored-by: Yong He <yhe@nvidia.com>
Diffstat (limited to 'examples/experimental/heterogeneous-hello-world/main.cpp')
-rw-r--r--examples/experimental/heterogeneous-hello-world/main.cpp380
1 files changed, 380 insertions, 0 deletions
diff --git a/examples/experimental/heterogeneous-hello-world/main.cpp b/examples/experimental/heterogeneous-hello-world/main.cpp
new file mode 100644
index 000000000..372fcd615
--- /dev/null
+++ b/examples/experimental/heterogeneous-hello-world/main.cpp
@@ -0,0 +1,380 @@
+// This example is out of date and currently disabled from build.
+// The `gfx` layer has been refactored with a new command list based
+// model. The example must be updated to use the new `gfx` interface
+// before it can be included in build.
+
+#if 0
+// main.cpp
+
+// This file implements an extremely simple example of loading and
+// executing a Slang shader program. This is primarily an example
+// of how to use Slang as a "drop-in" replacement for an existing
+// HLSL compiler like the `D3DCompile` API. More advanced usage
+// of advanced Slang language and API features is left to the
+// next example.
+//
+// The comments in the file will attempt to explain concepts as
+// they are introduced.
+//
+// Of course, in order to use the Slang API, we need to include
+// its header. We have set up the build options for this project
+// so that it is as simple as:
+//
+#include <slang.h>
+//
+// Other build setups are possible, and Slang doesn't assume that
+// its include directory must be added to your global include
+// path.
+
+// For the purposes of keeping the demo code as simple as possible,
+// while still retaining some level of portability, our examples
+// make use of a small platform and graphics API abstraction layer,
+// which is included in the Slang source distribution under the
+// `tools/` directory.
+//
+// Applications can of course use Slang without ever touching this
+// abstraction layer, so we will not focus on it when explaining
+// examples, except in places where best practices for interacting
+// with Slang may depend on an application/engine making certain
+// design choices in their abstraction layer.
+//
+#include "slang-com-ptr.h"
+#include "slang-gfx.h"
+#include "tools/graphics-app-framework/window.h"
+#include "../../prelude/slang-cpp-types.h"
+#include "source/core/slang-basic.h"
+
+using namespace gfx;
+
+// We create global ref pointers to avoid dereferencing values
+//
+ComPtr<gfx::IShaderProgram> gShaderProgram;
+Slang::ComPtr<gfx::IRenderer> gRenderer;
+
+ComPtr<gfx::IBufferResource> gStructuredBuffer;
+
+ComPtr<gfx::IPipelineLayout> gPipelineLayout;
+ComPtr<gfx::IPipelineState> gPipelineState;
+ComPtr<gfx::IDescriptorSetLayout> gDescriptorSetLayout;
+ComPtr<gfx::IDescriptorSet> gDescriptorSet;
+
+// Boilerplate types to help the slan-generated file
+//
+struct gfx_Window_0;
+struct gfx_Renderer_0;
+struct gfx_BufferResource_0;
+struct gfx_ShaderProgram_0;
+struct gfx_DescriptorSetLayout_0;
+struct gfx_PipelineLayout_0;
+struct gfx_DescriptorSet_0;
+struct gfx_PipelineState_0;
+
+bool executeComputation_0();
+extern unsigned char __computeMain[];
+extern size_t __computeMainSize;
+
+gfx::IShaderProgram* loadShaderProgram(gfx::IRenderer* renderer, unsigned char computeCode[], size_t computeCodeSize)
+{
+ // We extract the begin/end pointers to the output code buffers directly
+ //
+ char unsigned const* computeCodeEnd = computeCode + computeCodeSize;
+
+ // Now we use the operations of the example graphics API abstraction
+ // layer to load shader code into the underlying API.
+ //
+ // Reminder: this section does not involve the Slang API at all.
+ //
+
+ gfx::IShaderProgram::KernelDesc kernelDescs[] =
+ {
+ { gfx::StageType::Compute, computeCode, computeCodeEnd },
+ };
+
+ gfx::IShaderProgram::Desc programDesc = {};
+ programDesc.pipelineType = gfx::PipelineType::Compute;
+ programDesc.kernels = &kernelDescs[0];
+ programDesc.kernelCount = 1;
+
+ gShaderProgram = renderer->createProgram(programDesc);
+
+ return gShaderProgram;
+}
+
+// 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.
+//
+gfx::Window* createWindow(int windowWidth, int windowHeight)
+{
+ // Create a window for our application to render into.
+ //
+ WindowDesc windowDesc;
+ windowDesc.title = "Hello, World!";
+ windowDesc.width = windowWidth;
+ windowDesc.height = windowHeight;
+ return createWindow(windowDesc);
+ //return globalWindow;
+}
+
+gfx::IRenderer* createRenderer(
+ int windowWidth,
+ int windowHeight,
+ gfx::Window* window)
+{
+ // Initialize the rendering layer.
+ //
+ // Note: for now we are hard-coding logic to use the
+ // Direct3D11 back-end for the graphics API abstraction.
+ // A future version of this example may support multiple
+ // platforms/APIs.
+ //
+ IRenderer::Desc rendererDesc = {};
+ rendererDesc.rendererType = gfx::RendererType::DirectX11;
+ Result res = gfxCreateRenderer(&rendererDesc, gRenderer.writeRef());
+
+ if (SLANG_FAILED(res)) return nullptr;
+ return gRenderer;
+}
+
+gfx::IBufferResource* createStructuredBuffer(gfx::IRenderer* renderer, float* initialArray)
+{
+ // Create a structured buffer for storing the data for computation
+ //
+ int structuredBufferSize = 4 * sizeof(float);
+
+ IBufferResource::Desc structuredBufferDesc;
+ structuredBufferDesc.init(structuredBufferSize);
+ structuredBufferDesc.setDefaults(IResource::Usage::UnorderedAccess);
+ structuredBufferDesc.elementSize = 4;
+ structuredBufferDesc.cpuAccessFlags = IResource::AccessFlag::Read;
+
+ gStructuredBuffer = renderer->createBufferResource(
+ IResource::Usage::UnorderedAccess,
+ structuredBufferDesc,
+ initialArray);
+ return gStructuredBuffer;
+}
+
+gfx::IDescriptorSetLayout* buildDescriptorSetLayout(gfx::IRenderer* renderer)
+{
+ // Our example graphics API usess a "modern" D3D12/Vulkan style
+ // of resource binding, so now we will dive into describing and
+ // allocating "descriptor sets."
+ //
+ // First, we need to construct a descriptor set *layout*.
+ //
+ IDescriptorSetLayout::SlotRangeDesc slotRanges[] =
+ {
+ IDescriptorSetLayout::SlotRangeDesc(DescriptorSlotType::StorageBuffer),
+ };
+ IDescriptorSetLayout::Desc descriptorSetLayoutDesc;
+ descriptorSetLayoutDesc.slotRangeCount = 1;
+ descriptorSetLayoutDesc.slotRanges = &slotRanges[0];
+ gDescriptorSetLayout = renderer->createDescriptorSetLayout(descriptorSetLayoutDesc);
+ return gDescriptorSetLayout;
+}
+
+gfx::IPipelineLayout* buildPipeline(gfx::IRenderer* renderer, gfx::IDescriptorSetLayout* descriptorSetLayout)
+{
+ // Next we will allocate a pipeline layout, which specifies
+ // that we will render with only a single descriptor set bound.
+ //
+
+ IPipelineLayout::DescriptorSetDesc descriptorSets[] =
+ {
+ IPipelineLayout::DescriptorSetDesc(descriptorSetLayout),
+ };
+ IPipelineLayout::Desc pipelineLayoutDesc;
+ pipelineLayoutDesc.renderTargetCount = 1;
+ pipelineLayoutDesc.descriptorSetCount = 1;
+ pipelineLayoutDesc.descriptorSets = &descriptorSets[0];
+ gPipelineLayout = renderer->createPipelineLayout(pipelineLayoutDesc);
+
+ return gPipelineLayout;
+}
+
+gfx::IDescriptorSet* buildDescriptorSet(
+ gfx::IRenderer* renderer,
+ gfx::IDescriptorSetLayout* descriptorSetLayout,
+ gfx::IBufferResource* structuredBuffer)
+{
+ // Once we have the descriptor set layout, we can allocate
+ // and fill in a descriptor set to hold our parameters.
+ //
+ gDescriptorSet = renderer->createDescriptorSet(descriptorSetLayout, gfx::IDescriptorSet::Flag::Transient);
+ if(!gDescriptorSet) return nullptr;
+
+ // Once we have the bufferResource created, we can fill in
+ // a descriptor set for creating a structured buffer
+ //
+ IResourceView::Desc resourceViewDesc;
+ resourceViewDesc.type = IResourceView::Type::UnorderedAccess;
+ auto resourceView = renderer->createBufferView(structuredBuffer, resourceViewDesc);
+ gDescriptorSet->setResource(0, 0, resourceView);
+
+ return gDescriptorSet;
+}
+
+gfx::IPipelineState* buildPipelineState(
+ gfx::IShaderProgram* shaderProgram,
+ gfx::IRenderer* renderer,
+ gfx::IPipelineLayout* pipelineLayout)
+{
+ // Following the D3D12/Vulkan style of API, we need a pipeline state object
+ // (PSO) to encapsulate the configuration of the overall graphics pipeline.
+ //
+ ComputePipelineStateDesc desc;
+ desc.pipelineLayout = pipelineLayout;
+ desc.program = shaderProgram;
+ gPipelineState = renderer->createComputePipelineState(desc);
+ return gPipelineState;
+}
+
+void printInitialValues(float* initialArray, int length)
+{
+ // Print out the values before the computation
+ printf("Before:\n");
+ for (int i = 0; i < length; i++)
+ {
+ printf("%f, ", initialArray[i]);
+ }
+ printf("\n");
+}
+
+void dispatchComputation(
+ gfx::ICommandQueue* gQueue,
+ gfx::IPipelineState* gPipelineState,
+ gfx::IPipelineLayout* gPipelineLayout,
+ gfx::IDescriptorSet* gDescriptorSet,
+ unsigned int gridDimsX,
+ unsigned int gridDimsY,
+ unsigned int gridDimsZ)
+{
+ auto cmdBuf = gQueue->createCommandBuffer();
+ auto encoder = cmdBuf->encodeComputeCommands();
+ encoder->setPipelineState(gPipelineState);
+ encoder->setDescriptorSet(PipelineType::Compute, gPipelineLayout, 0, gDescriptorSet);
+ encoder->dispatchCompute(gridDimsX, gridDimsY, gridDimsZ);
+ encoder->endEncoding();
+ gQueue->executeCommandBuffer(cmdBuf);
+}
+
+void print_output(
+ gfx::IRenderer* renderer,
+ gfx::IBufferResource* structuredBuffer,
+ int length)
+{
+ ComPtr<ISlangBlob> blob;
+ renderer->readBufferResource(structuredBuffer, 0, length * sizeof(float), blob.writeRef());
+ if (float* outputData = (float*)blob->getBufferPointer())
+ {
+ // Print out the values the the kernel produced
+ printf("After: \n");
+ for (int i = 0; i < 4; i++)
+ {
+ printf("%f, ", outputData[i]);
+ }
+ printf("\n");
+ }
+}
+
+// Boilerplate functions to help the slang-generated file and types
+gfx_Window_0* createWindow_0(int32_t _0, int32_t _1)
+{
+ return (gfx_Window_0*)createWindow(_0, _1);
+}
+
+gfx_Renderer_0* createRenderer_0(int32_t _0, int32_t _1, gfx_Window_0* _2)
+{
+ return (gfx_Renderer_0*)createRenderer(_0, _1, (gfx::Window*)_2);
+}
+
+gfx_BufferResource_0* createStructuredBuffer_0(gfx_Renderer_0* _0, FixedArray<float, 4> _1)
+{
+ return (gfx_BufferResource_0*)createStructuredBuffer((gfx::IRenderer*)_0, (float*)&_1);
+}
+
+gfx_ShaderProgram_0* loadShaderProgram_0(gfx_Renderer_0* _0, unsigned char _1[], size_t _2)
+{
+ return (gfx_ShaderProgram_0*)loadShaderProgram((gfx::IRenderer*)_0, _1, _2);
+}
+
+gfx_DescriptorSetLayout_0* buildDescriptorSetLayout_0(gfx_Renderer_0* _0)
+{
+ return (gfx_DescriptorSetLayout_0*)buildDescriptorSetLayout((gfx::IRenderer*)_0);
+}
+
+gfx_PipelineLayout_0* buildPipeline_0(gfx_Renderer_0* _0, gfx_DescriptorSetLayout_0* _1)
+{
+ return (gfx_PipelineLayout_0*)buildPipeline((gfx::IRenderer*)_0, (gfx::IDescriptorSetLayout*)_1);
+}
+
+gfx_DescriptorSet_0* buildDescriptorSet_0(gfx_Renderer_0* _0, gfx_DescriptorSetLayout_0* _1, gfx_BufferResource_0* _2)
+{
+ return (gfx_DescriptorSet_0*)buildDescriptorSet(
+ (gfx::IRenderer*)_0,
+ (gfx::IDescriptorSetLayout*)_1,
+ (gfx::IBufferResource*)_2);
+}
+
+gfx_PipelineState_0* buildPipelineState_0(gfx_ShaderProgram_0* _0, gfx_Renderer_0* _1, gfx_PipelineLayout_0* _2)
+{
+ return (gfx_PipelineState_0*)buildPipelineState(
+ (gfx::IShaderProgram*)_0, (gfx::IRenderer*)_1,
+ (gfx::IPipelineLayout*)_2);
+}
+
+void printInitialValues_0(FixedArray<float, 4> _0, int32_t _1)
+{
+ printInitialValues((float*)&_0, _1);
+}
+
+void dispatchComputation_0(gfx_CommandQueue_0* _0, gfx_PipelineState_0* _1, gfx_PipelineLayout_0* _2, gfx_DescriptorSet_0* _3, unsigned int gridDimsX, unsigned int gridDimsY, unsigned int gridDimsZ)
+{
+ dispatchComputation(
+ (gfx::ICommandQueue*)_0,
+ (gfx::IPipelineState*)_1,
+ (gfx::IPipelineLayout*)_2,
+ (gfx::IDescriptorSet*)_3,
+ gridDimsX,
+ gridDimsY,
+ gridDimsZ);
+}
+
+RWStructuredBuffer<float> convertBuffer_0(gfx_BufferResource_0* _0) {
+ RWStructuredBuffer<float> result;
+ result.data = (float*)_0;
+ return result;
+}
+
+gfx_BufferResource_0* unconvertBuffer_0(RWStructuredBuffer<float> _0) {
+ return (gfx_BufferResource_0*)(_0.data);
+}
+
+void print_output_0(gfx_CommandQueue_0* _0, gfx_BufferResource_0* _1, int32_t _2)
+{
+ print_output((gfx::ICommandQueue*)_0, (gfx::IBufferResource*)_1, _2);
+}
+
+// This "inner" main function is used by the platform abstraction
+// layer to deal with differences in how an entry point needs
+// to be defined for different platforms.
+//
+void innerMain(ApplicationContext* context)
+{
+ // We construct an instance of our example application
+ // `struct` type, and then walk through the lifecyle
+ // of the application.
+
+ if (!(executeComputation_0()))
+ {
+ return exitApplication(context, 1);
+ }
+}
+
+// This macro instantiates an appropriate main function to
+// invoke the `innerMain` above.
+//
+GFX_CONSOLE_MAIN(innerMain)
+
+#endif