summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/gpu-printing/main.cpp4
-rw-r--r--examples/hello-world/main.cpp77
-rw-r--r--examples/shader-object/main.cpp74
-rw-r--r--examples/shader-toy/main.cpp12
4 files changed, 79 insertions, 88 deletions
diff --git a/examples/gpu-printing/main.cpp b/examples/gpu-printing/main.cpp
index a0acb8159..265b4c5ff 100644
--- a/examples/gpu-printing/main.cpp
+++ b/examples/gpu-printing/main.cpp
@@ -121,9 +121,7 @@ Result execute()
auto queue = gDevice->createCommandQueue(queueDesc);
auto commandBuffer = transientHeap->createCommandBuffer();
auto encoder = commandBuffer->encodeComputeCommands();
- auto rootShaderObject = gDevice->createRootShaderObject(gProgram);
- encoder->setPipelineState(gPipelineState);
- encoder->bindRootShaderObject(rootShaderObject);
+ auto rootShaderObject = encoder->bindPipeline(gPipelineState);
encoder->dispatchCompute(1, 1, 1);
encoder->endEncoding();
commandBuffer->close();
diff --git a/examples/hello-world/main.cpp b/examples/hello-world/main.cpp
index 19413948a..6b9104072 100644
--- a/examples/hello-world/main.cpp
+++ b/examples/hello-world/main.cpp
@@ -206,7 +206,6 @@ gfx::Result loadShaderProgram(
// building an example program.
//
ComPtr<gfx::IPipelineState> gPipelineState;
-ComPtr<gfx::IShaderObject> gRootObject;
ComPtr<gfx::IBufferResource> gVertexBuffer;
// Now that we've covered the function that actually loads and
@@ -251,38 +250,6 @@ Slang::Result initialize()
ComPtr<IShaderProgram> shaderProgram;
SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, shaderProgram.writeRef()));
- // 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.
- //
- // 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 `shaderProgram`. 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.
- //
- // Multiple root objects can be created from the same program, and will have
- // separate storage for parameter values.
- //
- // 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."
- //
- ComPtr<IShaderObject> rootObject;
- SLANG_RETURN_ON_FAIL(gDevice->createRootShaderObject(shaderProgram, rootObject.writeRef()));
- gRootObject = rootObject;
-
// Following the D3D12/Vulkan style of API, we need a pipeline state object
// (PSO) to encapsulate the configuration of the overall graphics pipeline.
//
@@ -315,6 +282,38 @@ virtual void renderFrame(int frameBufferIndex) override
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.
+ //
+ // 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
@@ -322,8 +321,7 @@ virtual void renderFrame(int frameBufferIndex) override
//
auto deviceInfo = gDevice->getDeviceInfo();
- //
- // We know that `gRootObject` is a root shader object created
+ // 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
@@ -341,7 +339,7 @@ virtual void renderFrame(int frameBufferIndex) override
// a diretory path of `/` for the root directory in a file
// system.
//
- ShaderCursor rootCursor(gRootObject);
+ ShaderCursor rootCursor(rootObject);
//
// Next, we use a convenience overload of `operator[]` to
// navigate from the root cursor down to the parameter we
@@ -375,13 +373,6 @@ virtual void renderFrame(int frameBufferIndex) override
// hard-coded even in cross-platform code.
//
- // Now we configure our graphics pipeline state by setting the
- // PSO, binding our root shader object to it (which references
- // the `Uniforms` buffer that will filled in above).
- //
- renderEncoder->setPipelineState(gPipelineState);
- renderEncoder->bindRootShaderObject(gRootObject);
-
// We also need to set up a few pieces of fixed-function pipeline
// state that are not bound by the pipeline state above.
//
diff --git a/examples/shader-object/main.cpp b/examples/shader-object/main.cpp
index 9329a5418..6efe2f97d 100644
--- a/examples/shader-object/main.cpp
+++ b/examples/shader-object/main.cpp
@@ -136,7 +136,6 @@ int main()
// interacting with the graphics API.
Slang::ComPtr<gfx::IDevice> device;
IDevice::Desc deviceDesc = {};
- deviceDesc.deviceType = DeviceType::Vulkan;
SLANG_RETURN_ON_FAIL(gfxCreateDevice(&deviceDesc, device.writeRef()));
Slang::ComPtr<gfx::ITransientResourceHeap> transientHeap;
@@ -184,46 +183,51 @@ int main()
viewDesc.format = gfx::Format::Unknown;
SLANG_RETURN_ON_FAIL(device->createBufferView(numbersBuffer, viewDesc, bufferView.writeRef()));
- // Now comes the interesting part: binding the shader parameter for the
- // compute kernel that we about to launch. We would like to construct
- // a shader object that represents a `f(x)=x+1` transformation and apply
- // it to the numbers in `numbersBuffer`.
- // To start, we create a root shader object that represents the root level
- // scope of the shader parameters.
- ComPtr<gfx::IShaderObject> rootObject;
- SLANG_RETURN_ON_FAIL(device->createRootShaderObject(shaderProgram, rootObject.writeRef()));
- // We can set parameters directly with `rootObject`, but that requires us to use
- // the Slang reflection API to obtain the proper offsets into the root object for each parameter.
- // We implemented these logic in the `ShaderCursor` helper class, which simplifies the user
- // code to find shader parameters. Here we demonstrate how to set parameters with `ShaderCursor`.
- gfx::ShaderCursor entryPointCursor(rootObject->getEntryPoint(0)); // get a cursor the the first entry-point.
- // Bind buffer view to the entry point.
- entryPointCursor.getPath("buffer").setResource(bufferView);
-
- // Next, we create a shader object that represents the transformer we want to use.
- // To do so, we first need to lookup for the `AddTransformer` type defined in the shader code.
- slang::TypeReflection* addTransformerType = slangReflection->findTypeByName("AddTransformer");
-
- // 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, transformer.writeRef()));
- // Set the `c` field of the `AddTransformer`.
- float c = 1.0f;
- gfx::ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float));
-
- // Now the transformer object is ready, we can bind it to root object.
- entryPointCursor.getPath("transformer").setObject(transformer);
-
- // We have set up all required parameters in entry-point object, now it is time
- // to bind the pipeline and root object and launch the kernel.
+ // We have done all the set up work, now it is time to start recording a command buffer for
+ // GPU execution.
{
ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics};
auto queue = device->createCommandQueue(queueDesc);
auto commandBuffer = transientHeap->createCommandBuffer();
auto encoder = commandBuffer->encodeComputeCommands();
- encoder->setPipelineState(pipelineState);
- encoder->bindRootShaderObject(rootObject);
+
+
+ // Now comes the interesting part: binding the shader parameter for the
+ // compute kernel that we about to launch. We would like to construct
+ // a shader object that represents a `f(x)=x+1` transformation and apply
+ // it to the numbers in `numbersBuffer`.
+
+ // First, obtain a root shader object from command encoder to start parameter binding.
+ auto rootObject = encoder->bindPipeline(pipelineState);
+
+ // Next, we create a shader object that represents the transformer we want to use.
+ // To do so, we first need to lookup for the `AddTransformer` type defined in the shader
+ // code.
+ slang::TypeReflection* addTransformerType =
+ slangReflection->findTypeByName("AddTransformer");
+
+ // 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, transformer.writeRef()));
+ // Set the `c` field of the `AddTransformer`.
+ float c = 1.0f;
+ gfx::ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float));
+
+ // We can set parameters directly with `rootObject`, but that requires us to use
+ // the Slang reflection API to obtain the proper offsets into the root object for each
+ // parameter. We implemented these logic in the `ShaderCursor` helper class, which
+ // simplifies the user code to find shader parameters. Here we demonstrate how to set
+ // parameters with `ShaderCursor`.
+ gfx::ShaderCursor entryPointCursor(
+ rootObject->getEntryPoint(0)); // get a cursor the the first entry-point.
+ // Bind buffer view to the entry point.
+ entryPointCursor.getPath("buffer").setResource(bufferView);
+
+ // Bind the previously created transformer object to root object.
+ entryPointCursor.getPath("transformer").setObject(transformer);
+
encoder->dispatchCompute(1, 1, 1);
encoder->endEncoding();
commandBuffer->close();
diff --git a/examples/shader-toy/main.cpp b/examples/shader-toy/main.cpp
index a142c3c15..40c97e0f4 100644
--- a/examples/shader-toy/main.cpp
+++ b/examples/shader-toy/main.cpp
@@ -286,7 +286,6 @@ Result loadShaderProgram(gfx::IDevice* device, ComPtr<gfx::IShaderProgram>& outS
}
ComPtr<IShaderProgram> gShaderProgram;
-ComPtr<gfx::IShaderObject> gRootObject[kSwapchainImageCount];
ComPtr<gfx::IPipelineState> gPipelineState;
ComPtr<gfx::IBufferResource> gVertexBuffer;
@@ -371,10 +370,7 @@ virtual void renderFrame(int frameIndex) override
uniforms.iResolution[1] = float(windowHeight);
}
- gRootObject[frameIndex] = gDevice->createRootShaderObject(gShaderProgram);
- auto constantBuffer = gRootObject[frameIndex]->getObject(ShaderOffset());
- constantBuffer->setData(ShaderOffset(), &uniforms, sizeof(uniforms));
-
+
// Encode render commands.
auto encoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameIndex]);
@@ -383,8 +379,10 @@ virtual void renderFrame(int frameIndex) override
viewport.extentX = (float)windowWidth;
viewport.extentY = (float)windowHeight;
encoder->setViewportAndScissor(viewport);
- encoder->setPipelineState(gPipelineState);
- encoder->bindRootShaderObject(gRootObject[frameIndex]);
+ auto rootObject = encoder->bindPipeline(gPipelineState);
+ auto constantBuffer = rootObject->getObject(ShaderOffset());
+ constantBuffer->setData(ShaderOffset(), &uniforms, sizeof(uniforms));
+
encoder->setVertexBuffer(0, gVertexBuffer, sizeof(FullScreenTriangle::Vertex));
encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList);
encoder->draw(3);