1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
#include "core/slang-basic.h"
#include "core/slang-blob.h"
#include "gfx-test-util.h"
#include "gfx-util/shader-cursor.h"
#include "slang-gfx.h"
#include "unit-test/slang-unit-test.h"
using namespace gfx;
namespace gfx_test
{
// In this test,
// we will run a compute shader that compiles to HLSL with a reference to the macro
// "DOWNSTREAM_VALUE" that will be provided to dxc through slang's link-time compiler options. The
// test verifies that `IComponentType2::linkWithOptions()` is able to produce a linked
// IComponentType with additional compiler options. Here we will specify a DownstreamArg compiler
// option to define the value of DOWNSTREAM_VALUE when running dxc.
//
static Slang::Result loadProgram(
gfx::IDevice* device,
Slang::ComPtr<gfx::IShaderProgram>& outShaderProgram,
const char* shaderModuleName,
const char* entryPointName,
slang::ProgramLayout*& slangReflection)
{
Slang::ComPtr<slang::ISession> slangSession;
SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef()));
Slang::ComPtr<slang::IBlob> diagnosticsBlob;
slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef());
diagnoseIfNeeded(diagnosticsBlob);
if (!module)
return SLANG_FAIL;
ComPtr<slang::IEntryPoint> computeEntryPoint;
SLANG_RETURN_ON_FAIL(
module->findEntryPointByName(entryPointName, computeEntryPoint.writeRef()));
Slang::List<slang::IComponentType*> componentTypes;
componentTypes.add(module);
componentTypes.add(computeEntryPoint);
Slang::ComPtr<slang::IComponentType> composedProgram;
SlangResult result = slangSession->createCompositeComponentType(
componentTypes.getBuffer(),
componentTypes.getCount(),
composedProgram.writeRef(),
diagnosticsBlob.writeRef());
diagnoseIfNeeded(diagnosticsBlob);
SLANG_RETURN_ON_FAIL(result);
ComPtr<slang::IComponentType> linkedProgram;
slang::CompilerOptionEntry entry;
entry.name = slang::CompilerOptionName::DownstreamArgs;
entry.value.kind = slang::CompilerOptionValueKind::String;
entry.value.stringValue0 = "dxc";
entry.value.stringValue1 = "-DDOWNSTREAM_VALUE=4.0";
result = composedProgram
->linkWithOptions(linkedProgram.writeRef(), 1, &entry, diagnosticsBlob.writeRef());
diagnoseIfNeeded(diagnosticsBlob);
SLANG_RETURN_ON_FAIL(result);
composedProgram = linkedProgram;
slangReflection = composedProgram->getLayout();
gfx::IShaderProgram::Desc programDesc = {};
programDesc.slangGlobalScope = composedProgram.get();
auto shaderProgram = device->createProgram(programDesc);
outShaderProgram = shaderProgram;
return SLANG_OK;
}
void linkTimeOptionTestImpl(IDevice* device, UnitTestContext* context)
{
Slang::ComPtr<ITransientResourceHeap> transientHeap;
ITransientResourceHeap::Desc transientHeapDesc = {};
transientHeapDesc.constantBufferSize = 4096;
GFX_CHECK_CALL_ABORT(
device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef()));
ComPtr<IShaderProgram> shaderProgram;
slang::ProgramLayout* slangReflection;
GFX_CHECK_CALL_ABORT(
loadProgram(device, shaderProgram, "link-time-options", "computeMain", slangReflection));
ComputePipelineStateDesc pipelineDesc = {};
pipelineDesc.program = shaderProgram.get();
ComPtr<gfx::IPipelineState> pipelineState;
GFX_CHECK_CALL_ABORT(
device->createComputePipelineState(pipelineDesc, pipelineState.writeRef()));
const int numberCount = 4;
float initialData[] = {0.0f, 0.0f, 0.0f, 0.0f};
IBufferResource::Desc bufferDesc = {};
bufferDesc.sizeInBytes = numberCount * sizeof(float);
bufferDesc.format = gfx::Format::Unknown;
bufferDesc.elementSize = sizeof(float);
bufferDesc.allowedStates = ResourceStateSet(
ResourceState::ShaderResource,
ResourceState::UnorderedAccess,
ResourceState::CopyDestination,
ResourceState::CopySource);
bufferDesc.defaultState = ResourceState::UnorderedAccess;
bufferDesc.memoryType = MemoryType::DeviceLocal;
ComPtr<IBufferResource> numbersBuffer;
GFX_CHECK_CALL_ABORT(
device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef()));
ComPtr<IResourceView> bufferView;
IResourceView::Desc viewDesc = {};
viewDesc.type = IResourceView::Type::UnorderedAccess;
viewDesc.format = Format::Unknown;
GFX_CHECK_CALL_ABORT(
device->createBufferView(numbersBuffer, nullptr, viewDesc, bufferView.writeRef()));
// 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();
auto rootObject = encoder->bindPipeline(pipelineState);
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);
encoder->dispatchCompute(1, 1, 1);
encoder->endEncoding();
commandBuffer->close();
queue->executeCommandBuffer(commandBuffer);
queue->waitOnHost();
}
compareComputeResult(device, numbersBuffer, Slang::makeArray<float>(4.0));
}
SLANG_UNIT_TEST(linkTimeOptionD3D12)
{
runTestImpl(linkTimeOptionTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12);
}
} // namespace gfx_test
|