summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2021-01-26 13:32:03 -0800
committerGitHub <noreply@github.com>2021-01-26 13:32:03 -0800
commita90c850735664e2928e4cc961442a126c6859b97 (patch)
tree8b5e12113319ae87c57f5e616408eb955fe85a2c
parent50676c741e10ffe6f710c5de86387eaacd274a9a (diff)
Integrate reflection more deeply into gfx layer (#1677)
-rw-r--r--examples/gpu-printing/main.cpp2
-rw-r--r--examples/hello-world/main.cpp472
-rw-r--r--examples/hello-world/shaders.slang3
-rw-r--r--examples/heterogeneous-hello-world/main.cpp2
-rw-r--r--examples/model-viewer/main.cpp2
-rw-r--r--examples/shader-toy/main.cpp2
-rw-r--r--slang.h18
-rw-r--r--source/slang/slang-api.cpp8
-rwxr-xr-xsource/slang/slang-compiler.h1
-rw-r--r--source/slang/slang.cpp7
-rw-r--r--tools/gfx-util/shader-cursor.cpp4
-rw-r--r--tools/gfx-util/shader-cursor.h36
-rw-r--r--tools/gfx/cuda/render-cuda.cpp43
-rw-r--r--tools/gfx/d3d11/render-d3d11.cpp17
-rw-r--r--tools/gfx/d3d12/render-d3d12.cpp16
-rw-r--r--tools/gfx/open-gl/render-gl.cpp19
-rw-r--r--tools/gfx/render-graphics-common.cpp70
-rw-r--r--tools/gfx/render-graphics-common.h28
-rw-r--r--tools/gfx/render.h35
-rw-r--r--tools/gfx/renderer-shared.cpp68
-rw-r--r--tools/gfx/renderer-shared.h3
-rw-r--r--tools/gfx/vulkan/render-vk.cpp16
-rw-r--r--tools/graphics-app-framework/gui.cpp2
-rw-r--r--tools/render-test/render-test-main.cpp34
-rw-r--r--tools/render-test/slang-support.cpp45
-rw-r--r--tools/render-test/slang-support.h38
26 files changed, 645 insertions, 346 deletions
diff --git a/examples/gpu-printing/main.cpp b/examples/gpu-printing/main.cpp
index 57e096043..6a4aabf3a 100644
--- a/examples/gpu-printing/main.cpp
+++ b/examples/gpu-printing/main.cpp
@@ -100,7 +100,7 @@ ComPtr<gfx::IShaderProgram> loadComputeProgram(slang::IModule* slangModule, char
{ gfx::StageType::Compute, code, codeEnd },
};
- gfx::IShaderProgram::Desc programDesc;
+ gfx::IShaderProgram::Desc programDesc = {};
programDesc.pipelineType = gfx::PipelineType::Compute;
programDesc.kernels = &kernelDescs[0];
programDesc.kernelCount = 2;
diff --git a/examples/hello-world/main.cpp b/examples/hello-world/main.cpp
index 959aa2881..cdd998e35 100644
--- a/examples/hello-world/main.cpp
+++ b/examples/hello-world/main.cpp
@@ -33,6 +33,7 @@
// design choices in their abstraction layer.
//
#include "gfx/render.h"
+#include "gfx-util/shader-cursor.h"
#include "tools/graphics-app-framework/window.h"
#include "slang-com-ptr.h"
#include "source/core/slang-basic.h"
@@ -64,146 +65,185 @@ static const Vertex kVertexData[kVertexCount] =
struct HelloWorld
{
-// We will start with a function that will invoke the Slang compiler
-// to generate target-specific code from a shader file, and then
-// use that to initialize an API shader program.
+// We will start with the code related to loading and using the Slang compiler.
//
-// Note that `Renderer` and `ShaderProgram` here are types from
-// the graphics API abstraction layer, and *not* part of the
-// Slang API. This function is representative of code that a user
-// might write to integrate Slang into their renderer/engine.
+// Applications interact with the Slang compiler through a "session" object.
+// There are actually two types of session:
//
-ComPtr<gfx::IShaderProgram> loadShaderProgram(gfx::IRenderer* renderer)
-{
- // First, we need to create a "session" for interacting with the Slang
- // compiler. This scopes all of our application's interactions
- // with the Slang library. At the moment, creating a session causes
- // Slang to load and validate its standard library, so this is a
- // somewhat heavy-weight operation. When possible, an application
- // should try to re-use the same session across multiple compiles.
- //
- SlangSession* slangSession = spCreateSession(NULL);
-
- // A compile request represents a single invocation of the compiler,
- // to process some inputs and produce outputs (or errors).
- //
- SlangCompileRequest* slangRequest = spCreateCompileRequest(slangSession);
-
- // We would like to request a single target (output) format: DirectX shader bytecode (DXBC)
- int targetIndex = spAddCodeGenTarget(slangRequest, SLANG_DXBC);
-
- // We will specify the desired "profile" for this one target in terms of the
- // DirectX "shader model" that should be supported.
- //
- spSetTargetProfile(slangRequest, targetIndex, spFindProfile(slangSession, "sm_4_0"));
-
- // A compile request can include one or more "translation units," which more or
- // less amount to individual source files (think `.c` files, not the `.h` files they
- // might include).
- //
- // For this example, our code will all be in the Slang language. The user may
- // also specify HLSL input here, but that currently doesn't affect the compiler's
- // behavior much.
- //
- int translationUnitIndex = spAddTranslationUnit(slangRequest, SLANG_SOURCE_LANGUAGE_SLANG, nullptr);
-
- // We will load source code for our translation unit from the file `shaders.slang`.
- // There are also variations of this API for adding source code from application-provided buffers.
- //
- spAddTranslationUnitSourceFile(slangRequest, translationUnitIndex, "shaders.slang");
-
- // Next we will specify the entry points we'd like to compile.
- // It is often convenient to put more than one entry point in the same file,
- // and the Slang API makes it convenient to use a single run of the compiler
- // to compile all entry points.
- //
- // For each entry point, we need to specify the name of a function, the
- // translation unit in which that function can be found, and the stage
- // that we need to compile for (e.g., vertex, fragment, geometry, ...).
- //
- char const* vertexEntryPointName = "vertexMain";
- char const* fragmentEntryPointName = "fragmentMain";
- int vertexIndex = spAddEntryPoint(slangRequest, translationUnitIndex, vertexEntryPointName, SLANG_STAGE_VERTEX);
- int fragmentIndex = spAddEntryPoint(slangRequest, translationUnitIndex, fragmentEntryPointName, SLANG_STAGE_FRAGMENT);
-
- // Once all of the input options for the compiler have been specified,
- // we can invoke `spCompile` to run the compiler and see if any errors
- // were detected.
- //
- const SlangResult compileRes = spCompile(slangRequest);
+// * The *global session* represents a loaded instance of the Slang library
+// (e.g., `slang.dll` and is used to scope allocations/resources that are
+// truly global across all compiles, such as the Slang "standard library")
+//
+// * A *session* is used to scope one or more compile actions such as
+// loading modules, generating code, and performing reflection.
+//
+// For our simple application, we will allocate a single session that is used
+// for all compilation.
+//
+ComPtr<slang::IGlobalSession> slangGlobalSession;
+ComPtr<slang::ISession> slangSession;
- // Even if there were no errors that forced compilation to fail, the
- // compiler may have produced "diagnostic" output such as warnings.
- // We will go ahead and print that output here.
- //
- if(auto diagnostics = spGetDiagnosticOutput(slangRequest))
+// 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 )
{
- reportError("%s", diagnostics);
+ reportError("%s", (const char*) diagnosticsBlob->getBufferPointer());
}
+}
- // If compilation failed, there is no point in continuing any further.
- if(SLANG_FAILED(compileRes))
+// 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::IRenderer* renderer,
+ gfx::IShaderProgram** outProgram)
+{
+ // The first step in interacting with the Slang API is to create a "global session,"
+ // which represents an instance of the Slang API loaded from the library.
+ //
+ if( !slangGlobalSession )
{
- spDestroyCompileRequest(slangRequest);
- spDestroySession(slangSession);
- return nullptr;
+ SLANG_RETURN_ON_FAIL(slang_createGlobalSession(SLANG_API_VERSION, slangGlobalSession.writeRef()));
}
- // If compilation was successful, then we will extract the code for
- // our two entry points as "blobs".
- //
- // If you are using a D3D API, then your application may want to
- // take advantage of the fact taht these blobs are binary compatible
- // with the `ID3DBlob`, `ID3D10Blob`, etc. interfaces.
- //
-
- ISlangBlob* vertexShaderBlob = nullptr;
- spGetEntryPointCodeBlob(slangRequest, vertexIndex, 0, &vertexShaderBlob);
-
- ISlangBlob* fragmentShaderBlob = nullptr;
- spGetEntryPointCodeBlob(slangRequest, fragmentIndex, 0, &fragmentShaderBlob);
-
- // We extract the begin/end pointers to the output code buffers
- // using operations on the `ISlangBlob` interface.
- //
- char const* vertexCode = (char const*) vertexShaderBlob->getBufferPointer();
- char const* vertexCodeEnd = vertexCode + vertexShaderBlob->getBufferSize();
-
- char const* fragmentCode = (char const*) fragmentShaderBlob->getBufferPointer();
- char const* fragmentCodeEnd = fragmentCode + fragmentShaderBlob->getBufferSize();
-
- // Once we have extracted the output blobs, it is safe to destroy
- // the compile request and even the session.
+ // Next, we need to create a compilation session (`slang::ISession`) that will provide
+ // a scope to all the compilation and loading of code we do.
//
- spDestroyCompileRequest(slangRequest);
- spDestroySession(slangSession);
-
- // Now we use the operations of the example graphics API abstraction
- // layer to load shader code into the underlying API.
+ // In an application like this, which doesn't make use of preprocessor-based specialization,
+ // we can create a single session and use it for the duration of the application.
+ // One important service the session provides is re-use of modules that have already
+ // been compiled, so that if two Slang files `import` the same module, the compiler
+ // will only load and check that module once.
//
- // Reminder: this section does not involve the Slang API at all.
- //
-
- gfx::IShaderProgram::KernelDesc kernelDescs[] =
+ if( !slangSession )
{
- { gfx::StageType::Vertex, vertexCode, vertexCodeEnd },
- { gfx::StageType::Fragment, fragmentCode, fragmentCodeEnd },
- };
+ // When creating a session we need to tell it what code generation targets we may
+ // want code generated for. It is valid to have zero or more targets, but many
+ // applications will only want one, corresponding to the graphics API they plan to use.
+ // This application is currently hard-coded to use D3D11, so we set up for compilation
+ // to DX bytecode.
+ //
+ // Note: the `TargetDesc` can also be used to set things like optimization settings
+ // for each target, but this application doesn't care to set any of that stuff.
+ //
+ slang::TargetDesc targetDesc = {};
+ targetDesc.format = SLANG_DXBC;
+ targetDesc.profile = spFindProfile(slangGlobalSession, "sm_4_0");
+
+ // The session can be set up with a few other options, notably:
+ //
+ // * Any search paths that should be used when resolving `import` or `#include` directives.
+ //
+ // * Any preprocessor macros to pre-define when reading in files.
+ //
+ // This application doesn't plan to make heavy use of the preprocessor, and all its
+ // shader files are in the same directory, so we just use the default options (which
+ // will lead to the only search path being the current working directory).
+ //
+ slang::SessionDesc sessionDesc = {};
+ sessionDesc.targetCount = 1;
+ sessionDesc.targets = &targetDesc;
+
+ SLANG_RETURN_ON_FAIL(slangGlobalSession->createSession(sessionDesc, slangSession.writeRef()));
+ }
- gfx::IShaderProgram::Desc programDesc;
+ // Once the session has been created, 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.
+ //
+ ComPtr<slang::IBlob> diagnosticsBlob;
+ slang::IModule* module = slangSession->loadModule("shaders", 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()));
+
+ // 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.pipelineType = gfx::PipelineType::Graphics;
- programDesc.kernels = &kernelDescs[0];
- programDesc.kernelCount = 2;
-
- auto shaderProgram = renderer->createProgram(programDesc);
-
- // Once we've used the output blobs from the Slang compiler to initialize
- // the API-specific shader program, we can release their memory.
- //
- vertexShaderBlob->release();
- fragmentShaderBlob->release();
+ programDesc.slangProgram = linkedProgram;
+ SLANG_RETURN_ON_FAIL(renderer->createProgram(programDesc, outProgram));
- return shaderProgram;
+ return SLANG_OK;
}
//
@@ -231,11 +271,10 @@ int gWindowHeight = 768;
gfx::ApplicationContext* gAppContext;
gfx::Window* gWindow;
Slang::ComPtr<gfx::IRenderer> gRenderer;
-ComPtr<gfx::IBufferResource> gConstantBuffer;
-ComPtr<gfx::IPipelineLayout> gPipelineLayout;
+//ComPtr<gfx::IShaderObjectLayout> gRootLayout;
ComPtr<gfx::IPipelineState> gPipelineState;
-ComPtr<gfx::IDescriptorSet> gDescriptorSet;
+ComPtr<gfx::IShaderObject> gRootObject;
ComPtr<gfx::IBufferResource> gVertexBuffer;
@@ -269,26 +308,6 @@ Slang::Result initialize()
if(SLANG_FAILED(res)) return res;
}
- // Create a constant buffer for passing the model-view-projection matrix.
- //
- // Note: the Slang API supports reflection which could be used
- // to query the size of the `Uniform` constant buffer, but we
- // will not deal with that here because Slang also supports
- // applications that want to hard-code things like memory
- // layout and parameter locations.
- //
- int constantBufferSize = 16 * sizeof(float);
-
- IBufferResource::Desc constantBufferDesc;
- constantBufferDesc.init(constantBufferSize);
- constantBufferDesc.setDefaults(IResource::Usage::ConstantBuffer);
- constantBufferDesc.cpuAccessFlags = IResource::AccessFlag::Write;
-
- gConstantBuffer = gRenderer->createBufferResource(
- IResource::Usage::ConstantBuffer,
- constantBufferDesc);
- if(!gConstantBuffer) return SLANG_FAIL;
-
// Now we will create objects needed to configur the "input assembler"
// (IA) stage of the D3D pipeline.
//
@@ -318,57 +337,45 @@ Slang::Result initialize()
// Now we will use our `loadShaderProgram` function to load
// the code from `shaders.slang` into the graphics API.
//
- ComPtr<IShaderProgram> shaderProgram = loadShaderProgram(gRenderer);
- if(!shaderProgram) return SLANG_FAIL;
+ ComPtr<IShaderProgram> shaderProgram;
+ SLANG_RETURN_ON_FAIL(loadShaderProgram(gRenderer, shaderProgram.writeRef()));
- // Our example graphics API usess a "modern" D3D12/Vulkan style
- // of resource binding, so now we will dive into describing and
- // allocating "descriptor sets."
+ // 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.
//
- // First, we need to construct a descriptor set *layout*.
+ // 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.
//
- IDescriptorSetLayout::SlotRangeDesc slotRanges[] =
- {
- IDescriptorSetLayout::SlotRangeDesc(DescriptorSlotType::UniformBuffer),
- };
- IDescriptorSetLayout::Desc descriptorSetLayoutDesc;
- descriptorSetLayoutDesc.slotRangeCount = 1;
- descriptorSetLayoutDesc.slotRanges = &slotRanges[0];
- auto descriptorSetLayout = gRenderer->createDescriptorSetLayout(descriptorSetLayoutDesc);
- if(!descriptorSetLayout) return SLANG_FAIL;
-
- // Next we will allocate a pipeline layout, which specifies
- // that we will render with only a single descriptor set bound.
+ // 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.
//
-
- IPipelineLayout::DescriptorSetDesc descriptorSets[] =
- {
- IPipelineLayout::DescriptorSetDesc( descriptorSetLayout ),
- };
- IPipelineLayout::Desc pipelineLayoutDesc;
- pipelineLayoutDesc.renderTargetCount = 1;
- pipelineLayoutDesc.descriptorSetCount = 1;
- pipelineLayoutDesc.descriptorSets = &descriptorSets[0];
- auto pipelineLayout = gRenderer->createPipelineLayout(pipelineLayoutDesc);
- if(!pipelineLayout) return SLANG_FAIL;
-
- gPipelineLayout = pipelineLayout;
-
- // Once we have the descriptor set layout, we can allocate
- // and fill in a descriptor set to hold our parameters.
+ // 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."
//
- auto descriptorSet = gRenderer->createDescriptorSet(descriptorSetLayout);
- if(!descriptorSet) return SLANG_FAIL;
-
- descriptorSet->setConstantBuffer(0, 0, gConstantBuffer);
-
- gDescriptorSet = descriptorSet;
+ // 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(gRenderer->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.
//
GraphicsPipelineStateDesc desc;
- desc.pipelineLayout = gPipelineLayout;
desc.inputLayout = inputLayout;
desc.program = shaderProgram;
desc.renderTargetCount = 1;
@@ -398,34 +405,85 @@ void renderFrame()
gRenderer->setClearColor(kClearColor);
gRenderer->clearFrame();
- // We update our constant buffer per-frame, just for the purposes
- // of the example, but we don't actually load different data
- // per-frame (we always use an identity projection).
+ // 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).
//
- if(float* data = (float*) gRenderer->map(gConstantBuffer, MapFlavor::WriteDiscard))
+ static const float kIdentity[] =
{
- static const float kIdentity[] =
- {
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1 };
- memcpy(data, kIdentity, sizeof(kIdentity));
-
- gRenderer->unmap(gConstantBuffer);
- }
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1,
+ };
+ //
+ // We know that `gRootObject` 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(gRootObject);
+ //
+ // 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(kIdentity, sizeof(kIdentity));
+ //
+ // 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.
+ //
// Now we configure our graphics pipeline state by setting the
- // PSO, binding our descriptor set (which references the
- // constant buffer that we wrote to above), and setting
- // some additional bits of state, before drawing our triangle.
+ // PSO, binding our root shader object to it (which references
+ // the `Uniforms` buffer that will filled in above).
//
gRenderer->setPipelineState(PipelineType::Graphics, gPipelineState);
- gRenderer->setDescriptorSet(PipelineType::Graphics, gPipelineLayout, 0, gDescriptorSet);
+ gRenderer->bindRootShaderObject(PipelineType::Graphics, gRootObject);
+ // We also need to set up a few pieces of fixed-function pipeline
+ // state that are not bound by the pipeline state above.
+ //
gRenderer->setVertexBuffer(0, gVertexBuffer, sizeof(Vertex));
gRenderer->setPrimitiveTopology(PrimitiveTopology::TriangleList);
+ // Finally, we are ready to issue a draw call for a single triangle.
+ //
gRenderer->draw(3);
// With that, we are done drawing for one frame, and ready for the next.
diff --git a/examples/hello-world/shaders.slang b/examples/hello-world/shaders.slang
index 2df26b3d9..fe35db9c8 100644
--- a/examples/hello-world/shaders.slang
+++ b/examples/hello-world/shaders.slang
@@ -38,6 +38,8 @@ struct VertexStageOutput
CoarseVertex coarseVertex : CoarseVertex;
float4 sv_position : SV_Position;
};
+
+[shader("vertex")]
VertexStageOutput vertexMain(
AssembledVertex assembledVertex)
{
@@ -54,6 +56,7 @@ VertexStageOutput vertexMain(
// Fragment Shader
+[shader("fragment")]
float4 fragmentMain(
CoarseVertex coarseVertex : CoarseVertex) : SV_Target
{
diff --git a/examples/heterogeneous-hello-world/main.cpp b/examples/heterogeneous-hello-world/main.cpp
index 8cf3894ed..8610a5fa2 100644
--- a/examples/heterogeneous-hello-world/main.cpp
+++ b/examples/heterogeneous-hello-world/main.cpp
@@ -85,7 +85,7 @@ gfx::IShaderProgram* loadShaderProgram(gfx::IRenderer* renderer, unsigned char c
{ gfx::StageType::Compute, computeCode, computeCodeEnd },
};
- gfx::IShaderProgram::Desc programDesc;
+ gfx::IShaderProgram::Desc programDesc = {};
programDesc.pipelineType = gfx::PipelineType::Compute;
programDesc.kernels = &kernelDescs[0];
programDesc.kernelCount = 1;
diff --git a/examples/model-viewer/main.cpp b/examples/model-viewer/main.cpp
index 720d421e2..384cc5eac 100644
--- a/examples/model-viewer/main.cpp
+++ b/examples/model-viewer/main.cpp
@@ -960,7 +960,7 @@ RefPtr<EffectVariant> createEffectVaraint(
spDestroyCompileRequest(slangRequest);
// We use the graphics API to load a program into the GPU
- gfx::IShaderProgram::Desc programDesc;
+ gfx::IShaderProgram::Desc programDesc = {};
programDesc.pipelineType = gfx::PipelineType::Graphics;
programDesc.kernels = kernelDescs.data();
programDesc.kernelCount = kernelDescs.size();
diff --git a/examples/shader-toy/main.cpp b/examples/shader-toy/main.cpp
index 23193496b..044c1805b 100644
--- a/examples/shader-toy/main.cpp
+++ b/examples/shader-toy/main.cpp
@@ -351,7 +351,7 @@ Result loadShaderProgram(gfx::IRenderer* renderer, ComPtr<gfx::IShaderProgram>&
{ gfx::StageType::Fragment, fragmentCode, fragmentCodeEnd },
};
- gfx::IShaderProgram::Desc programDesc;
+ gfx::IShaderProgram::Desc programDesc = {};
programDesc.pipelineType = gfx::PipelineType::Graphics;
programDesc.kernels = &kernelDescs[0];
programDesc.kernelCount = 2;
diff --git a/slang.h b/slang.h
index 96364f443..1e93a4f55 100644
--- a/slang.h
+++ b/slang.h
@@ -3692,6 +3692,18 @@ namespace slang
virtual SLANG_NO_THROW SlangResult SLANG_MCALL addTargetCapability(
SlangInt targetIndex,
SlangCapabilityID capability) = 0;
+
+ /** Get the (linked) program for a compile request, including all entry points.
+
+ The resulting program will include all of the global-scope modules for the
+ translation units in the program, plus any modules that they `import`
+ (transitively), specialized to any global specialization arguments that
+ were provided via the API, as well as all entry points specified for compilation,
+ specialized to their entry-point specialization arguments.
+ */
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL getProgramWithEntryPoints(
+ slang::IComponentType** outProgram) = 0;
+
};
#define SLANG_UUID_ICompileRequest { 0x96d33993, 0x317c, 0x4db5, { 0xaf, 0xd8, 0x66, 0x6e, 0xe7, 0x72, 0x48, 0xe2 } };
@@ -4127,6 +4139,12 @@ SLANG_EXTERN_C SLANG_API SlangResult spCompileRequest_getProgram(
SlangCompileRequest* request,
slang::IComponentType** outProgram);
+/** @see slang::ICompileRequest::getProgramWithEntryPoints
+*/
+SLANG_EXTERN_C SLANG_API SlangResult spCompileRequest_getProgramWithEntryPoints(
+ SlangCompileRequest* request,
+ slang::IComponentType** outProgram);
+
/** @see slang::ICompileRequest::getEntryPoint
*/
SLANG_EXTERN_C SLANG_API SlangResult spCompileRequest_getEntryPoint(
diff --git a/source/slang/slang-api.cpp b/source/slang/slang-api.cpp
index 4595bac51..56dc44c04 100644
--- a/source/slang/slang-api.cpp
+++ b/source/slang/slang-api.cpp
@@ -620,6 +620,14 @@ SLANG_API SlangResult spCompileRequest_getProgram(
return request->getProgram(outProgram);
}
+SLANG_API SlangResult spCompileRequest_getProgramWithEntryPoints(
+ slang::ICompileRequest* request,
+ slang::IComponentType** outProgram)
+{
+ SLANG_ASSERT(request);
+ return request->getProgramWithEntryPoints(outProgram);
+}
+
SLANG_API SlangResult spCompileRequest_getModule(
slang::ICompileRequest* request,
SlangInt translationUnitIndex,
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index 62def6f0f..ac2d72862 100755
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -1920,6 +1920,7 @@ namespace Slang
virtual SLANG_NO_THROW SlangReflection* SLANG_MCALL getReflection() SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setCommandLineCompilerMode() SLANG_OVERRIDE;
virtual SLANG_NO_THROW SlangResult SLANG_MCALL addTargetCapability(SlangInt targetIndex, SlangCapabilityID capability) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL getProgramWithEntryPoints(slang::IComponentType** outProgram) SLANG_OVERRIDE;
EndToEndCompileRequest(
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index c82d5cf65..b711a5327 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -4324,6 +4324,13 @@ SlangResult EndToEndCompileRequest::getProgram(slang::IComponentType** outProgra
return SLANG_OK;
}
+SlangResult EndToEndCompileRequest::getProgramWithEntryPoints(slang::IComponentType** outProgram)
+{
+ auto program = getSpecializedGlobalAndEntryPointsComponentType();
+ *outProgram = Slang::ComPtr<slang::IComponentType>(program).detach();
+ return SLANG_OK;
+}
+
SlangResult EndToEndCompileRequest::getModule(SlangInt translationUnitIndex, slang::IModule** outModule)
{
auto module = getFrontEndReq()->getTranslationUnit(translationUnitIndex)->getModule();
diff --git a/tools/gfx-util/shader-cursor.cpp b/tools/gfx-util/shader-cursor.cpp
index f80803bdd..769643e75 100644
--- a/tools/gfx-util/shader-cursor.cpp
+++ b/tools/gfx-util/shader-cursor.cpp
@@ -20,7 +20,7 @@ Result gfx::ShaderCursor::getDereferenced(ShaderCursor& outCursor) const
}
}
-Result ShaderCursor::getField(const char* name, const char* nameEnd, ShaderCursor& outCursor)
+Result ShaderCursor::getField(const char* name, const char* nameEnd, ShaderCursor& outCursor) const
{
// If this cursor is invalid, then can't possible fetch a field.
//
@@ -118,7 +118,7 @@ Result ShaderCursor::getField(const char* name, const char* nameEnd, ShaderCurso
return SLANG_E_INVALID_ARG;
}
-ShaderCursor ShaderCursor::getElement(SlangInt index)
+ShaderCursor ShaderCursor::getElement(SlangInt index) const
{
// TODO: need to auto-dereference various buffer types...
diff --git a/tools/gfx-util/shader-cursor.h b/tools/gfx-util/shader-cursor.h
index 3f5cfb090..04dddc3aa 100644
--- a/tools/gfx-util/shader-cursor.h
+++ b/tools/gfx-util/shader-cursor.h
@@ -42,7 +42,7 @@ struct ShaderCursor
Result getDereferenced(ShaderCursor& outCursor) const;
- ShaderCursor getDereferenced()
+ ShaderCursor getDereferenced() const
{
ShaderCursor result;
getDereferenced(result);
@@ -53,20 +53,20 @@ struct ShaderCursor
/// points at.
///
/// If the operation succeeds, then the field cursor is written to `outCursor`.
- Result getField(const char* nameBegin, const char* nameEnd, ShaderCursor& outCursor);
+ Result getField(const char* nameBegin, const char* nameEnd, ShaderCursor& outCursor) const;
- ShaderCursor getField(const char* name)
+ ShaderCursor getField(const char* name) const
{
ShaderCursor cursor;
getField(name, nullptr, cursor);
return cursor;
}
- ShaderCursor getElement(SlangInt index);
+ ShaderCursor getElement(SlangInt index) const;
static Result followPath(const char* path, ShaderCursor& ioCursor);
- ShaderCursor getPath(const char* path)
+ ShaderCursor getPath(const char* path) const
{
ShaderCursor result(*this);
followPath(path, result);
@@ -80,29 +80,45 @@ struct ShaderCursor
, m_typeLayout(object->getElementTypeLayout())
{}
- SlangResult setData(void const* data, size_t size)
+ SlangResult setData(void const* data, size_t size) const
{
return m_baseObject->setData(m_offset, data, size);
}
- SlangResult setObject(IShaderObject* object)
+ SlangResult setObject(IShaderObject* object) const
{
return m_baseObject->setObject(m_offset, object);
}
- SlangResult setResource(IResourceView* resourceView)
+ SlangResult setResource(IResourceView* resourceView) const
{
return m_baseObject->setResource(m_offset, resourceView);
}
- SlangResult setSampler(ISamplerState* sampler)
+ SlangResult setSampler(ISamplerState* sampler) const
{
return m_baseObject->setSampler(m_offset, sampler);
}
- SlangResult setCombinedTextureSampler(IResourceView* textureView, ISamplerState* sampler)
+ SlangResult setCombinedTextureSampler(IResourceView* textureView, ISamplerState* sampler) const
{
return m_baseObject->setCombinedTextureSampler(m_offset, textureView, sampler);
}
+
+ /// Produce a cursor to the field with the given `name`.
+ ///
+ /// This is a convenience wrapper around `getField()`.
+ ShaderCursor operator[](const char* name) const
+ {
+ return getField(name);
+ }
+
+ /// Produce a cursor to the element or field with the given `index`.
+ ///
+ /// This is a convenience wrapper around `getElement()`.
+ ShaderCursor operator[](SlangInt index) const
+ {
+ return getElement(index);
+ }
};
}
diff --git a/tools/gfx/cuda/render-cuda.cpp b/tools/gfx/cuda/render-cuda.cpp
index 0e4ee6c13..d1e320224 100644
--- a/tools/gfx/cuda/render-cuda.cpp
+++ b/tools/gfx/cuda/render-cuda.cpp
@@ -241,6 +241,8 @@ public:
RefPtr<TextureCUDAResource> textureResource = nullptr;
};
+class CUDAProgramLayout;
+
class CUDAShaderProgram : public IShaderProgram, public RefObject
{
public:
@@ -255,6 +257,9 @@ public:
CUmodule cudaModule = nullptr;
CUfunction cudaKernel;
String kernelName;
+ ComPtr<slang::IComponentType> slangProgram;
+ RefPtr<CUDAProgramLayout> layout;
+
~CUDAShaderProgram()
{
if (cudaModule)
@@ -1260,16 +1265,6 @@ private:
return SLANG_OK;
}
- virtual SLANG_NO_THROW Result SLANG_MCALL createRootShaderObjectLayout(
- slang::ProgramLayout* layout, IShaderObjectLayout** outLayout) override
- {
- RefPtr<CUDAProgramLayout> cudaLayout;
- cudaLayout = new CUDAProgramLayout(layout);
- cudaLayout->programLayout = layout;
- *outLayout = cudaLayout.detach();
- return SLANG_OK;
- }
-
virtual SLANG_NO_THROW Result SLANG_MCALL
createShaderObject(IShaderObjectLayout* layout, IShaderObject** outObject) override
{
@@ -1280,10 +1275,13 @@ private:
}
virtual SLANG_NO_THROW Result SLANG_MCALL
- createRootShaderObject(IShaderObjectLayout* layout, IShaderObject** outObject) override
+ createRootShaderObject(IShaderProgram* program, IShaderObject** outObject) override
{
+ auto cudaProgram = dynamic_cast<CUDAShaderProgram*>(program);
+ auto cudaLayout = cudaProgram->layout;
+
RefPtr<CUDARootShaderObject> result = new CUDARootShaderObject();
- SLANG_RETURN_ON_FAIL(result->init(this, dynamic_cast<CUDAShaderObjectLayout*>(layout)));
+ SLANG_RETURN_ON_FAIL(result->init(this, cudaLayout));
*outObject = result.detach();
return SLANG_OK;
}
@@ -1300,6 +1298,11 @@ private:
virtual SLANG_NO_THROW Result SLANG_MCALL
createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram) override
{
+ if( desc.kernelCount == 0 )
+ {
+ return createProgramFromSlang(this, desc, outProgram);
+ }
+
if (desc.kernelCount != 1)
return SLANG_E_INVALID_ARG;
RefPtr<CUDAShaderProgram> cudaProgram = new CUDAShaderProgram();
@@ -1307,6 +1310,22 @@ private:
SLANG_CUDA_RETURN_ON_FAIL(
cuModuleGetFunction(&cudaProgram->cudaKernel, cudaProgram->cudaModule, desc.kernels[0].entryPointName));
cudaProgram->kernelName = desc.kernels[0].entryPointName;
+
+ auto slangProgram = desc.slangProgram;
+ if( slangProgram )
+ {
+ cudaProgram->slangProgram = slangProgram;
+
+ auto slangProgramLayout = slangProgram->getLayout();
+ if(!slangProgramLayout)
+ return SLANG_FAIL;
+
+ RefPtr<CUDAProgramLayout> cudaLayout;
+ cudaLayout = new CUDAProgramLayout(slangProgramLayout);
+ cudaLayout->programLayout = slangProgramLayout;
+ cudaProgram->layout = cudaLayout;
+ }
+
*outProgram = cudaProgram.detach();
return SLANG_OK;
}
diff --git a/tools/gfx/d3d11/render-d3d11.cpp b/tools/gfx/d3d11/render-d3d11.cpp
index a2cf63a8f..40e617a1f 100644
--- a/tools/gfx/d3d11/render-d3d11.cpp
+++ b/tools/gfx/d3d11/render-d3d11.cpp
@@ -331,17 +331,9 @@ public:
List<ComPtr<ID3D11SamplerState>> m_samplers;
};
- class ShaderProgramImpl : public IShaderProgram, public RefObject
+ class ShaderProgramImpl : public GraphicsCommonShaderProgram
{
public:
- SLANG_REF_OBJECT_IUNKNOWN_ALL
- IShaderProgram* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IShaderProgram)
- return static_cast<IShaderProgram*>(this);
- return nullptr;
- }
- public:
ComPtr<ID3D11VertexShader> m_vertexShader;
ComPtr<ID3D11PixelShader> m_pixelShader;
ComPtr<ID3D11ComputeShader> m_computeShader;
@@ -1785,6 +1777,11 @@ void D3D11Renderer::drawIndexed(UInt indexCount, UInt startIndex, UInt baseVerte
Result D3D11Renderer::createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram)
{
+ if( desc.kernelCount == 0 )
+ {
+ return createProgramFromSlang(this, desc, outProgram);
+ }
+
if (desc.pipelineType == PipelineType::Compute)
{
auto computeKernel = desc.findKernel(StageType::Compute);
@@ -1799,6 +1796,7 @@ Result D3D11Renderer::createProgram(const IShaderProgram::Desc& desc, IShaderPro
RefPtr<ShaderProgramImpl> shaderProgram = new ShaderProgramImpl();
shaderProgram->m_computeShader.swap(computeShader);
+ initProgramCommon(shaderProgram, desc);
*outProgram = shaderProgram.detach();
return SLANG_OK;
@@ -1822,6 +1820,7 @@ Result D3D11Renderer::createProgram(const IShaderProgram::Desc& desc, IShaderPro
RefPtr<ShaderProgramImpl> shaderProgram = new ShaderProgramImpl();
shaderProgram->m_vertexShader.swap(vertexShader);
shaderProgram->m_pixelShader.swap(pixelShader);
+ initProgramCommon(shaderProgram, desc);
*outProgram = shaderProgram.detach();
return SLANG_OK;
diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp
index 74dc19dd7..648fc3052 100644
--- a/tools/gfx/d3d12/render-d3d12.cpp
+++ b/tools/gfx/d3d12/render-d3d12.cpp
@@ -202,17 +202,9 @@ protected:
UINT64 m_fenceValue; ///< The fence value when rendering this Frame is complete
};
- class ShaderProgramImpl : public IShaderProgram, public RefObject
+ class ShaderProgramImpl : public GraphicsCommonShaderProgram
{
public:
- SLANG_REF_OBJECT_IUNKNOWN_ALL
- IShaderProgram* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IShaderProgram)
- return static_cast<IShaderProgram*>(this);
- return nullptr;
- }
- public:
PipelineType m_pipelineType;
List<uint8_t> m_vertexShader;
List<uint8_t> m_pixelShader;
@@ -2955,6 +2947,11 @@ void D3D12Renderer::setDescriptorSet(PipelineType pipelineType, IPipelineLayout*
Result D3D12Renderer::createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram)
{
+ if( desc.kernelCount == 0 )
+ {
+ return createProgramFromSlang(this, desc, outProgram);
+ }
+
RefPtr<ShaderProgramImpl> program(new ShaderProgramImpl());
program->m_pipelineType = desc.pipelineType;
@@ -2971,6 +2968,7 @@ Result D3D12Renderer::createProgram(const IShaderProgram::Desc& desc, IShaderPro
program->m_vertexShader.insertRange(0, (const uint8_t*) vertexKernel->codeBegin, vertexKernel->getCodeSize());
program->m_pixelShader.insertRange(0, (const uint8_t*) fragmentKernel->codeBegin, fragmentKernel->getCodeSize());
}
+ initProgramCommon(program, desc);
*outProgram = program.detach();
return SLANG_OK;
diff --git a/tools/gfx/open-gl/render-gl.cpp b/tools/gfx/open-gl/render-gl.cpp
index 7ee73366b..49fd6b005 100644
--- a/tools/gfx/open-gl/render-gl.cpp
+++ b/tools/gfx/open-gl/render-gl.cpp
@@ -381,16 +381,8 @@ public:
List<RefPtr<SamplerStateImpl>> m_samplers;
};
- class ShaderProgramImpl : public IShaderProgram, public RefObject
+ class ShaderProgramImpl : public GraphicsCommonShaderProgram
{
- public:
- SLANG_REF_OBJECT_IUNKNOWN_ALL
- IShaderProgram* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IShaderProgram)
- return static_cast<IShaderProgram*>(this);
- return nullptr;
- }
public:
ShaderProgramImpl(WeakSink<GLRenderer>* renderer, GLuint id):
m_renderer(renderer),
@@ -1485,6 +1477,11 @@ SLANG_NO_THROW Result SLANG_MCALL
Result GLRenderer::createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram)
{
+ if( desc.kernelCount == 0 )
+ {
+ return createProgramFromSlang(this, desc, outProgram);
+ }
+
auto programID = glCreateProgram();
if(desc.pipelineType == PipelineType::Compute )
{
@@ -1534,7 +1531,9 @@ Result GLRenderer::createProgram(const IShaderProgram::Desc& desc, IShaderProgra
return SLANG_FAIL;
}
- *outProgram = new ShaderProgramImpl(m_weakRenderer, programID);
+ RefPtr<ShaderProgramImpl> program = new ShaderProgramImpl(m_weakRenderer, programID);
+ initProgramCommon(program, desc);
+ *outProgram = program.detach();
return SLANG_OK;
}
diff --git a/tools/gfx/render-graphics-common.cpp b/tools/gfx/render-graphics-common.cpp
index 747659d11..593d4708c 100644
--- a/tools/gfx/render-graphics-common.cpp
+++ b/tools/gfx/render-graphics-common.cpp
@@ -1287,27 +1287,36 @@ Result SLANG_MCALL
}
Result SLANG_MCALL GraphicsAPIRenderer::createRootShaderObject(
- IShaderObjectLayout* rootLayout, IShaderObject** outObject)
+ IShaderProgram* program,
+ IShaderObject** outObject)
{
+ auto commonProgram = dynamic_cast<GraphicsCommonShaderProgram*>(program);
+
RefPtr<ProgramVars> shaderObject;
SLANG_RETURN_ON_FAIL(ProgramVars::create(this,
- dynamic_cast<GraphicsCommonProgramLayout*>(rootLayout),
+ commonProgram->getLayout(),
shaderObject.writeRef()));
*outObject = shaderObject.detach();
return SLANG_OK;
}
-Result SLANG_MCALL GraphicsAPIRenderer::createRootShaderObjectLayout(
- slang::ProgramLayout* layout, IShaderObjectLayout** outLayout)
+Result GraphicsAPIRenderer::initProgramCommon(
+ GraphicsCommonShaderProgram* program,
+ IShaderProgram::Desc const& desc)
{
+ auto slangProgram = desc.slangProgram;
+ if(!slangProgram)
+ return SLANG_OK;
+
+ auto slangReflection = slangProgram->getLayout(0);
+ if(!slangReflection)
+ return SLANG_FAIL;
+
RefPtr<GraphicsCommonProgramLayout> programLayout;
- auto slangReflection = layout;
{
GraphicsCommonProgramLayout::Builder builder(this);
builder.addGlobalParams(slangReflection->getGlobalParamsVarLayout());
- // TODO: Also need to reflect entry points here.
-
SlangInt entryPointCount = slangReflection->getEntryPointCount();
for (SlangInt e = 0; e < entryPointCount; ++e)
{
@@ -1324,7 +1333,10 @@ Result SLANG_MCALL GraphicsAPIRenderer::createRootShaderObjectLayout(
SLANG_RETURN_ON_FAIL(builder.build(programLayout.writeRef()));
}
- *outLayout = programLayout.detach();
+
+ program->m_slangProgram = slangProgram;
+ program->m_layout = programLayout;
+
return SLANG_OK;
}
@@ -1360,11 +1372,44 @@ SLANG_NO_THROW bool SLANG_MCALL gfx::GraphicsAPIRenderer::hasFeature(const char*
return m_features.findFirstIndex([&](Slang::String x) { return x == featureName; }) != -1;
}
+GraphicsCommonShaderProgram::~GraphicsCommonShaderProgram()
+{
+ // Note: It might not seem like this destructor is needed at all, since
+ // it is empty.
+ //
+ // In pratice, though, it seems to be required because the `m_layout`
+ // field is declared in the coresponding header before the `GraphicsCommonProgramLayout`
+ // is declared (we only have a forward declaration).
+ //
+ // `m_layout` is a `RefPtr`, and it seems that the compiler (or at least
+ // the Visual Studio compiler) either cannot synthesize a destructor for
+ // the type that properly destructs the field, or it simply synthesizes
+ // an incorect destructor.
+ //
+ // I suspect that part of the problem stems from the way that `GraphicsCommonProgramLayout`
+ // inherits from `RefObject` via multiple inheritance.
+ //
+ // No matter what, defining the destructor here in a file where
+ // the declaration of `GraphicsCommonProgramLayout` is visible
+ // seems to result in a correct destructor being emitted.
+ //
+ // TODO: Ther simpler and more robust fix would be to move the declaration
+ // of `GraphicsCommonProgramLayout` and related types to the header.
+}
+
+IShaderProgram* GraphicsCommonShaderProgram::getInterface(const Guid& guid)
+{
+ if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IShaderProgram)
+ return static_cast<IShaderProgram*>(this);
+ return nullptr;
+}
+
void GraphicsAPIRenderer::preparePipelineDesc(GraphicsPipelineStateDesc& desc)
{
- if (desc.rootShaderObjectLayout)
+ if (!desc.pipelineLayout)
{
- auto rootLayout = dynamic_cast<GraphicsCommonProgramLayout*>(desc.rootShaderObjectLayout);
+ auto program = dynamic_cast<GraphicsCommonShaderProgram*>(desc.program);
+ auto rootLayout = program->getLayout();
desc.renderTargetCount = rootLayout->getRenderTargetCount();
desc.pipelineLayout = rootLayout->getPipelineLayout();
}
@@ -1372,9 +1417,10 @@ void GraphicsAPIRenderer::preparePipelineDesc(GraphicsPipelineStateDesc& desc)
void GraphicsAPIRenderer::preparePipelineDesc(ComputePipelineStateDesc& desc)
{
- if (desc.rootShaderObjectLayout)
+ if (!desc.pipelineLayout)
{
- auto rootLayout = dynamic_cast<GraphicsCommonProgramLayout*>(desc.rootShaderObjectLayout);
+ auto program = dynamic_cast<GraphicsCommonShaderProgram*>(desc.program);
+ auto rootLayout = program->getLayout();
desc.pipelineLayout = rootLayout->getPipelineLayout();
}
}
diff --git a/tools/gfx/render-graphics-common.h b/tools/gfx/render-graphics-common.h
index 1c04302ce..3a07f2993 100644
--- a/tools/gfx/render-graphics-common.h
+++ b/tools/gfx/render-graphics-common.h
@@ -5,6 +5,25 @@
namespace gfx
{
+class GraphicsCommonProgramLayout;
+
+class GraphicsCommonShaderProgram : public IShaderProgram, public Slang::RefObject
+{
+public:
+ SLANG_REF_OBJECT_IUNKNOWN_ALL
+
+ IShaderProgram* getInterface(const Slang::Guid& guid);
+
+ GraphicsCommonProgramLayout* getLayout() const { return m_layout; }
+
+protected:
+ ~GraphicsCommonShaderProgram();
+
+private:
+ friend class GraphicsAPIRenderer;
+ ComPtr<slang::IComponentType> m_slangProgram;
+ Slang::RefPtr<GraphicsCommonProgramLayout> m_layout;
+};
class GraphicsAPIRenderer : public IRenderer, public Slang::RefObject
{
@@ -15,18 +34,21 @@ public:
virtual SLANG_NO_THROW bool SLANG_MCALL hasFeature(const char* featureName) SLANG_OVERRIDE;
virtual SLANG_NO_THROW Result SLANG_MCALL createShaderObjectLayout(
slang::TypeLayoutReflection* typeLayout, IShaderObjectLayout** outLayout) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW Result SLANG_MCALL createRootShaderObjectLayout(
- slang::ProgramLayout* programLayout, IShaderObjectLayout** outLayout) SLANG_OVERRIDE;
virtual SLANG_NO_THROW Result SLANG_MCALL
createShaderObject(IShaderObjectLayout* layout, IShaderObject** outObject) SLANG_OVERRIDE;
virtual SLANG_NO_THROW Result SLANG_MCALL createRootShaderObject(
- IShaderObjectLayout* rootLayout, IShaderObject** outObject) SLANG_OVERRIDE;
+ IShaderProgram* program,
+ IShaderObject** outObject) SLANG_OVERRIDE;
virtual SLANG_NO_THROW Result SLANG_MCALL
bindRootShaderObject(PipelineType pipelineType, IShaderObject* object) SLANG_OVERRIDE;
void preparePipelineDesc(GraphicsPipelineStateDesc& desc);
void preparePipelineDesc(ComputePipelineStateDesc& desc);
IRenderer* getInterface(const Slang::Guid& guid);
+ Result initProgramCommon(
+ GraphicsCommonShaderProgram* program,
+ IShaderProgram::Desc const& desc);
+
protected:
Slang::List<Slang::String> m_features;
};
diff --git a/tools/gfx/render.h b/tools/gfx/render.h
index eeef00a8f..4c3b71645 100644
--- a/tools/gfx/render.h
+++ b/tools/gfx/render.h
@@ -71,6 +71,8 @@ enum class StageType
ClosestHit,
Miss,
Callable,
+ Amplification,
+ Mesh,
CountOf,
};
@@ -124,9 +126,13 @@ public:
struct Desc
{
PipelineType pipelineType;
+
KernelDesc const* kernels;
Int kernelCount;
+ /// Use instead of `kernels`/`kernelCount` if loading a Slang program.
+ slang::IComponentType* slangProgram;
+
/// Find and return the kernel for `stage`, if present.
KernelDesc const* findKernel(StageType stage) const
{
@@ -1026,14 +1032,15 @@ struct BlendDesc
struct GraphicsPipelineStateDesc
{
IShaderProgram* program;
- // Application should set either pipelineLayout or rootShaderObjectLayout, but not both.
+
+ // If `pipelineLayout` is null, then layout information will be extracted
+ // from `program`, which must have been created with Slang reflection info.
IPipelineLayout* pipelineLayout = nullptr;
- // Application should set either pipelineLayout or rootShaderObjectLayout, but not both.
- IShaderObjectLayout* rootShaderObjectLayout = nullptr;
+
IInputLayout* inputLayout;
UInt framebufferWidth;
UInt framebufferHeight;
- UInt renderTargetCount = 0; // Not used if rootShaderObjectLayout is set.
+ UInt renderTargetCount = 0; // Only used if `pipelineLayout` is non-null
DepthStencilDesc depthStencil;
RasterizerDesc rasterizer;
BlendDesc blend;
@@ -1042,8 +1049,10 @@ struct GraphicsPipelineStateDesc
struct ComputePipelineStateDesc
{
IShaderProgram* program;
+
+ // If `pipelineLayout` is null, then layout information will be extracted
+ // from `program`, which must have been created with Slang reflection info.
IPipelineLayout* pipelineLayout = nullptr;
- IShaderObjectLayout* rootShaderObjectLayout = nullptr;
};
class IPipelineState : public ISlangUnknown
@@ -1197,16 +1206,6 @@ public:
return layout;
}
- virtual SLANG_NO_THROW Result SLANG_MCALL createRootShaderObjectLayout(
- slang::ProgramLayout* layout, IShaderObjectLayout** outLayout) = 0;
-
- inline ComPtr<IShaderObjectLayout> createRootShaderObjectLayout(slang::ProgramLayout* layout)
- {
- ComPtr<IShaderObjectLayout> result;
- SLANG_RETURN_NULL_ON_FAIL(createRootShaderObjectLayout(layout, result.writeRef()));
- return result;
- }
-
virtual SLANG_NO_THROW Result SLANG_MCALL createShaderObject(IShaderObjectLayout* layout, IShaderObject** outObject) = 0;
inline ComPtr<IShaderObject> createShaderObject(IShaderObjectLayout* layout)
@@ -1216,12 +1215,12 @@ public:
return object;
}
- virtual SLANG_NO_THROW Result SLANG_MCALL createRootShaderObject(IShaderObjectLayout* layout, IShaderObject** outObject) = 0;
+ virtual SLANG_NO_THROW Result SLANG_MCALL createRootShaderObject(IShaderProgram* program, IShaderObject** outObject) = 0;
- inline ComPtr<IShaderObject> createRootShaderObject(IShaderObjectLayout* layout)
+ inline ComPtr<IShaderObject> createRootShaderObject(IShaderProgram* program)
{
ComPtr<IShaderObject> object;
- SLANG_RETURN_NULL_ON_FAIL(createRootShaderObject(layout, object.writeRef()));
+ SLANG_RETURN_NULL_ON_FAIL(createRootShaderObject(program, object.writeRef()));
return object;
}
diff --git a/tools/gfx/renderer-shared.cpp b/tools/gfx/renderer-shared.cpp
index 94154bc42..2072d52ef 100644
--- a/tools/gfx/renderer-shared.cpp
+++ b/tools/gfx/renderer-shared.cpp
@@ -1,6 +1,8 @@
#include "renderer-shared.h"
#include "render-graphics-common.h"
+using namespace Slang;
+
namespace gfx
{
@@ -27,5 +29,71 @@ IResource* TextureResource::getInterface(const Slang::Guid& guid)
SLANG_NO_THROW IResource::Type SLANG_MCALL TextureResource::getType() { return m_type; }
SLANG_NO_THROW ITextureResource::Desc* SLANG_MCALL TextureResource::getDesc() { return &m_desc; }
+gfx::StageType mapStage(SlangStage stage)
+{
+ switch( stage )
+ {
+ default:
+ return gfx::StageType::Unknown;
+
+ case SLANG_STAGE_AMPLIFICATION: return gfx::StageType::Amplification;
+ case SLANG_STAGE_ANY_HIT: return gfx::StageType::AnyHit;
+ case SLANG_STAGE_CALLABLE: return gfx::StageType::Callable;
+ case SLANG_STAGE_CLOSEST_HIT: return gfx::StageType::ClosestHit;
+ case SLANG_STAGE_COMPUTE: return gfx::StageType::Compute;
+ case SLANG_STAGE_DOMAIN: return gfx::StageType::Domain;
+ case SLANG_STAGE_FRAGMENT: return gfx::StageType::Fragment;
+ case SLANG_STAGE_GEOMETRY: return gfx::StageType::Geometry;
+ case SLANG_STAGE_HULL: return gfx::StageType::Hull;
+ case SLANG_STAGE_INTERSECTION: return gfx::StageType::Intersection;
+ case SLANG_STAGE_MESH: return gfx::StageType::Mesh;
+ case SLANG_STAGE_MISS: return gfx::StageType::Miss;
+ case SLANG_STAGE_RAY_GENERATION: return gfx::StageType::RayGeneration;
+ case SLANG_STAGE_VERTEX: return gfx::StageType::Vertex;
+ }
+}
+
+Result createProgramFromSlang(IRenderer* renderer, IShaderProgram::Desc const& originalDesc, IShaderProgram** outProgram)
+{
+ SlangInt targetIndex = 0;
+ auto slangProgram = originalDesc.slangProgram;
+
+ auto programLayout = slangProgram->getLayout(targetIndex);
+ if(!programLayout)
+ return SLANG_FAIL;
+
+ Int entryPointCount = (Int) programLayout->getEntryPointCount();
+ if(entryPointCount == 0)
+ return SLANG_FAIL;
+
+ List<IShaderProgram::KernelDesc> kernelDescs;
+ List<ComPtr<slang::IBlob>> kernelBlobs;
+ for( Int i = 0; i < entryPointCount; ++i )
+ {
+ ComPtr<slang::IBlob> entryPointCodeBlob;
+ SLANG_RETURN_ON_FAIL(slangProgram->getEntryPointCode(i, targetIndex, entryPointCodeBlob.writeRef()));
+
+ auto entryPointLayout = programLayout->getEntryPointByIndex(i);
+
+ kernelBlobs.add(entryPointCodeBlob);
+
+ IShaderProgram::KernelDesc kernelDesc;
+ kernelDesc.codeBegin = entryPointCodeBlob->getBufferPointer();
+ kernelDesc.codeEnd = (const char*) kernelDesc.codeBegin + entryPointCodeBlob->getBufferSize();
+ kernelDesc.entryPointName = entryPointLayout->getName();
+ kernelDesc.stage = mapStage(entryPointLayout->getStage());
+
+ kernelDescs.add(kernelDesc);
+ }
+ SLANG_ASSERT(kernelDescs.getCount() == entryPointCount);
+
+ IShaderProgram::Desc programDesc;
+ programDesc.pipelineType = originalDesc.pipelineType;
+ programDesc.slangProgram = slangProgram;
+ programDesc.kernelCount = kernelDescs.getCount();
+ programDesc.kernels = kernelDescs.getBuffer();
+
+ return renderer->createProgram(programDesc, outProgram);
+}
} // namespace gfx
diff --git a/tools/gfx/renderer-shared.h b/tools/gfx/renderer-shared.h
index 47cc9328d..c2924a7fd 100644
--- a/tools/gfx/renderer-shared.h
+++ b/tools/gfx/renderer-shared.h
@@ -67,4 +67,7 @@ public:
protected:
Desc m_desc;
};
+
+Result createProgramFromSlang(IRenderer* renderer, IShaderProgram::Desc const& desc, IShaderProgram** outProgram);
+
}
diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp
index 88cd52ad7..5afe3e3b4 100644
--- a/tools/gfx/vulkan/render-vk.cpp
+++ b/tools/gfx/vulkan/render-vk.cpp
@@ -307,17 +307,9 @@ public:
VkDeviceSize size;
};
- class ShaderProgramImpl: public IShaderProgram, public RefObject
+ class ShaderProgramImpl: public GraphicsCommonShaderProgram
{
public:
- SLANG_REF_OBJECT_IUNKNOWN_ALL
- IShaderProgram* getInterface(const Guid& guid)
- {
- if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IShaderProgram)
- return static_cast<IShaderProgram*>(this);
- return nullptr;
- }
- public:
ShaderProgramImpl(const VulkanApi& api, PipelineType pipelineType):
m_api(&api),
@@ -2835,6 +2827,11 @@ void VKRenderer::setDescriptorSet(PipelineType pipelineType, IPipelineLayout* la
Result VKRenderer::createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram)
{
+ if( desc.kernelCount == 0 )
+ {
+ return createProgramFromSlang(this, desc, outProgram);
+ }
+
RefPtr<ShaderProgramImpl> impl = new ShaderProgramImpl(m_api, desc.pipelineType);
if( desc.pipelineType == PipelineType::Compute)
{
@@ -2849,6 +2846,7 @@ Result VKRenderer::createProgram(const IShaderProgram::Desc& desc, IShaderProgra
impl->m_vertex = compileEntryPoint(*vertexKernel, VK_SHADER_STAGE_VERTEX_BIT, impl->m_buffers[0], impl->m_modules[0]);
impl->m_fragment = compileEntryPoint(*fragmentKernel, VK_SHADER_STAGE_FRAGMENT_BIT, impl->m_buffers[1], impl->m_modules[1]);
}
+ initProgramCommon(impl, desc);
*outProgram = impl.detach();
return SLANG_OK;
}
diff --git a/tools/graphics-app-framework/gui.cpp b/tools/graphics-app-framework/gui.cpp
index 777614d58..fded0d76a 100644
--- a/tools/graphics-app-framework/gui.cpp
+++ b/tools/graphics-app-framework/gui.cpp
@@ -139,7 +139,7 @@ GUI::GUI(Window* window, IRenderer* inRenderer)
{ gfx::StageType::Fragment, fragmentCode, fragmentCodeEnd },
};
- gfx::IShaderProgram::Desc programDesc;
+ gfx::IShaderProgram::Desc programDesc = {};
programDesc.pipelineType = gfx::PipelineType::Graphics;
programDesc.kernels = &kernelDescs[0];
programDesc.kernelCount = 2;
diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp
index 926887a77..6e35db639 100644
--- a/tools/render-test/render-test-main.cpp
+++ b/tools/render-test/render-test-main.cpp
@@ -111,6 +111,8 @@ protected:
Options::ShaderProgramType shaderType,
const ShaderCompilerUtil::Input& input);
+ virtual void finalizeImpl();
+
uint64_t m_startTicks;
// variables for state to be used for rendering...
@@ -165,6 +167,8 @@ public:
virtual Result writeBindingOutput(BindRoot* bindRoot, const char* fileName) override;
protected:
+ virtual void finalizeImpl() SLANG_OVERRIDE;
+
ComPtr<IShaderObject> m_programVars;
ShaderOutputPlan m_outputPlan;
};
@@ -586,12 +590,11 @@ SlangResult ShaderObjectRenderTestApp::initialize(
// Slang's reflection API to tell us what the parameters of the program are.
//
auto slangReflection = (slang::ProgramLayout*) spGetReflection(m_compilationOutput.output.getRequestForReflection());
- ComPtr<IShaderObjectLayout> programLayout = renderer->createRootShaderObjectLayout(slangReflection);
// Once we have determined the layout of all the parameters we need to bind,
// we will create a shader object to use for storing and binding those parameters.
//
- m_programVars = renderer->createRootShaderObject(programLayout);
+ m_programVars = renderer->createRootShaderObject(m_shaderProgram);
// Now we need to assign from the input parameter data that was parsed into
// the program vars we allocated.
@@ -601,9 +604,6 @@ SlangResult ShaderObjectRenderTestApp::initialize(
m_renderer = renderer;
- // TODO(tfoley): use each API's reflection interface to query the constant-buffer size needed
-// m_constantBufferSize = 16 * sizeof(float);
-
{
switch(m_options.shaderType)
{
@@ -614,7 +614,6 @@ SlangResult ShaderObjectRenderTestApp::initialize(
case Options::ShaderProgramType::Compute:
{
ComputePipelineStateDesc desc;
- desc.rootShaderObjectLayout = programLayout.get();
desc.program = m_shaderProgram;
m_pipelineState = renderer->createComputePipelineState(desc);
@@ -648,7 +647,6 @@ SlangResult ShaderObjectRenderTestApp::initialize(
SLANG_RETURN_ON_FAIL(renderer->createBufferResource(IResource::Usage::VertexBuffer, vertexBufferDesc, kVertexData, m_vertexBuffer.writeRef()));
GraphicsPipelineStateDesc desc;
- desc.rootShaderObjectLayout = programLayout.get();
desc.program = m_shaderProgram;
desc.inputLayout = inputLayout;
@@ -662,6 +660,12 @@ SlangResult ShaderObjectRenderTestApp::initialize(
return m_pipelineState ? SLANG_OK : SLANG_FAIL;
}
+void ShaderObjectRenderTestApp::finalizeImpl()
+{
+ m_programVars = nullptr;
+ RenderTestApp::finalizeImpl();
+}
+
Result RenderTestApp::_initializeShaders(
SlangSession* session,
IRenderer* renderer,
@@ -730,6 +734,18 @@ void RenderTestApp::runCompute()
void RenderTestApp::finalize()
{
+ finalizeImpl();
+
+ m_inputLayout = nullptr;
+ m_vertexBuffer = nullptr;
+ m_shaderProgram = nullptr;
+ m_pipelineState = nullptr;
+
+ m_renderer = nullptr;
+}
+
+void RenderTestApp::finalizeImpl()
+{
}
Result LegacyRenderTestApp::writeBindingOutput(BindRoot* bindRoot, const char* fileName)
@@ -1328,7 +1344,9 @@ static SlangResult _innerMain(Slang::StdWriters* stdWriters, SlangSession* sessi
app = new LegacyRenderTestApp();
SLANG_RETURN_ON_FAIL(app->initialize(session, renderer, options, input));
window->show();
- return window->runLoop(app);
+ SLANG_RETURN_ON_FAIL(window->runLoop(app));
+ app->finalize();
+ return SLANG_OK;
}
}
diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp
index 300cab4d7..c6d2b971e 100644
--- a/tools/render-test/slang-support.cpp
+++ b/tools/render-test/slang-support.cpp
@@ -50,6 +50,44 @@ gfx::StageType translateStage(SlangStage slangStage)
}
}
+void ShaderCompilerUtil::Output::set(
+ PipelineType pipelineType,
+ const IShaderProgram::KernelDesc* inKernelDescs,
+ Slang::Index kernelDescCount,
+ slang::IComponentType* inSlangProgram)
+{
+ kernelDescs.clear();
+ kernelDescs.addRange(inKernelDescs, kernelDescCount);
+ slangProgram = inSlangProgram;
+ desc.pipelineType = pipelineType;
+ desc.kernels = kernelDescs.getBuffer();
+ desc.kernelCount = kernelDescCount;
+ desc.slangProgram = inSlangProgram;
+}
+
+void ShaderCompilerUtil::Output::reset()
+{
+ {
+ desc.pipelineType = PipelineType::Unknown;
+ desc.slangProgram = nullptr;
+ desc.kernels = nullptr;
+ desc.kernelCount = 0;
+ }
+
+ kernelDescs.clear();
+ if (m_requestForKernels && session)
+ {
+ spDestroyCompileRequest(m_requestForKernels);
+ }
+ if (m_extraRequestForReflection && session)
+ {
+ spDestroyCompileRequest(m_extraRequestForReflection);
+ }
+ session = nullptr;
+ m_requestForKernels = nullptr;
+ m_extraRequestForReflection = nullptr;
+}
+
/* static */ SlangResult ShaderCompilerUtil::_compileProgramImpl(SlangSession* session, const Options& options, const Input& input, const ShaderCompileRequest& request, Output& out)
{
out.reset();
@@ -168,7 +206,8 @@ gfx::StageType translateStage(SlangStage slangStage)
SLANG_RETURN_ON_FAIL(res);
-
+ ComPtr<slang::IComponentType> linkedSlangProgram;
+
List<ShaderCompileRequest::EntryPoint> actualEntryPoints;
if(input.passThrough == SLANG_PASS_THROUGH_NONE)
{
@@ -178,6 +217,7 @@ gfx::StageType translateStage(SlangStage slangStage)
// loading of code.
//
auto reflection = slang::ProgramLayout::get(slangRequest);
+ SLANG_RETURN_ON_FAIL(spCompileRequest_getProgramWithEntryPoints(slangRequest, linkedSlangProgram.writeRef()));
// Get the amount of entry points in reflection
Index entryPointCount = Index(reflection->getEntryPointCount());
@@ -226,7 +266,7 @@ gfx::StageType translateStage(SlangStage slangStage)
kernelDescs.add(kernelDesc);
}
- out.set(input.pipelineType, kernelDescs.getBuffer(), kernelDescs.getCount());
+ out.set(input.pipelineType, kernelDescs.getBuffer(), kernelDescs.getCount(), linkedSlangProgram);
return SLANG_OK;
}
@@ -277,6 +317,7 @@ gfx::StageType translateStage(SlangStage slangStage)
SLANG_RETURN_ON_FAIL(_compileProgramImpl(session, options, input, request, out));
out.m_extraRequestForReflection = slangOutput.getRequestForReflection();
+ out.desc.slangProgram = slangOutput.desc.slangProgram;
slangOutput.m_requestForKernels = nullptr;
return SLANG_OK;
diff --git a/tools/render-test/slang-support.h b/tools/render-test/slang-support.h
index 06651ec73..c08d18567 100644
--- a/tools/render-test/slang-support.h
+++ b/tools/render-test/slang-support.h
@@ -58,35 +58,12 @@ struct ShaderCompilerUtil
struct Output
{
- void set(PipelineType pipelineType, const IShaderProgram::KernelDesc* inKernelDescs, Slang::Index kernelDescCount)
- {
- kernelDescs.clear();
- kernelDescs.addRange(inKernelDescs, kernelDescCount);
- desc.pipelineType = pipelineType;
- desc.kernels = kernelDescs.getBuffer();
- desc.kernelCount = kernelDescCount;
- }
- void reset()
- {
- {
- desc.pipelineType = PipelineType::Unknown;
- desc.kernels = nullptr;
- desc.kernelCount = 0;
- }
-
- kernelDescs.clear();
- if (m_requestForKernels && session)
- {
- spDestroyCompileRequest(m_requestForKernels);
- }
- if (m_extraRequestForReflection && session)
- {
- spDestroyCompileRequest(m_extraRequestForReflection);
- }
- session = nullptr;
- m_requestForKernels = nullptr;
- m_extraRequestForReflection = nullptr;
- }
+ void set(
+ PipelineType pipelineType,
+ const IShaderProgram::KernelDesc* kernelDescs,
+ Slang::Index kernelDescCount,
+ slang::IComponentType* slangProgram);
+ void reset();
~Output()
{
reset();
@@ -105,7 +82,8 @@ struct ShaderCompilerUtil
}
Slang::List<IShaderProgram::KernelDesc> kernelDescs;
- IShaderProgram::Desc desc;
+ ComPtr<slang::IComponentType> slangProgram;
+ IShaderProgram::Desc desc = {};
/// Compile request that owns the lifetime of compiled kernel code.
SlangCompileRequest* m_requestForKernels = nullptr;