yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie Hermaszewskaformatf65d756bf

master
6.8 KiB223 linesraw
1// cuda-command-queue.cpp
2#include "cuda-command-queue.h"
3
4#include "cuda-buffer.h"
5#include "cuda-command-buffer.h"
6#include "cuda-query.h"
7#include "cuda-shader-object-layout.h"
8
9namespace gfx
10{
11#ifdef GFX_ENABLE_CUDA
12using namespace Slang;
13
14namespace cuda
15{
16
17ICommandQueue* CommandQueueImpl::getInterface(const Guid& guid)
18{
19    if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ICommandQueue)
20        return static_cast<ICommandQueue*>(this);
21    return nullptr;
22}
23
24void CommandQueueImpl::init(DeviceImpl* inRenderer)
25{
26    renderer = inRenderer;
27    m_desc.type = ICommandQueue::QueueType::Graphics;
28    cuStreamCreate(&stream, 0);
29}
30CommandQueueImpl::~CommandQueueImpl()
31{
32    cuStreamSynchronize(stream);
33    cuStreamDestroy(stream);
34    currentPipeline = nullptr;
35    currentRootObject = nullptr;
36}
37
38SLANG_NO_THROW void SLANG_MCALL CommandQueueImpl::executeCommandBuffers(
39    GfxCount count,
40    ICommandBuffer* const* commandBuffers,
41    IFence* fence,
42    uint64_t valueToSignal)
43{
44    SLANG_UNUSED(valueToSignal);
45    // TODO: implement fence.
46    assert(fence == nullptr);
47    for (GfxIndex i = 0; i < count; i++)
48    {
49        execute(static_cast<CommandBufferImpl*>(commandBuffers[i]));
50    }
51}
52
53SLANG_NO_THROW void SLANG_MCALL CommandQueueImpl::waitOnHost()
54{
55    auto resultCode = cuStreamSynchronize(stream);
56    if (resultCode != CUDA_SUCCESS)
57        SLANG_CUDA_HANDLE_ERROR(resultCode);
58}
59
60SLANG_NO_THROW Result SLANG_MCALL CommandQueueImpl::waitForFenceValuesOnDevice(
61    GfxCount fenceCount,
62    IFence** fences,
63    uint64_t* waitValues)
64{
65    return SLANG_FAIL;
66}
67
68SLANG_NO_THROW Result SLANG_MCALL CommandQueueImpl::getNativeHandle(InteropHandle* outHandle)
69{
70    return SLANG_FAIL;
71}
72
73void CommandQueueImpl::setPipelineState(IPipelineState* state)
74{
75    currentPipeline = dynamic_cast<ComputePipelineStateImpl*>(state);
76}
77
78Result CommandQueueImpl::bindRootShaderObject(IShaderObject* object)
79{
80    currentRootObject = dynamic_cast<RootShaderObjectImpl*>(object);
81    if (currentRootObject)
82        return SLANG_OK;
83    return SLANG_E_INVALID_ARG;
84}
85
86void CommandQueueImpl::dispatchCompute(int x, int y, int z)
87{
88    // Specialize the compute kernel based on the shader object bindings.
89    RefPtr<PipelineStateBase> newPipeline;
90    renderer->maybeSpecializePipeline(currentPipeline, currentRootObject, newPipeline);
91    currentPipeline = static_cast<ComputePipelineStateImpl*>(newPipeline.Ptr());
92
93    // Find out thread group size from program reflection.
94    auto& kernelName = currentPipeline->shaderProgram->kernelName;
95    auto programLayout = static_cast<RootShaderObjectLayoutImpl*>(currentRootObject->getLayout());
96    int kernelId = programLayout->getKernelIndex(kernelName.getUnownedSlice());
97    SLANG_ASSERT(kernelId != -1);
98    UInt threadGroupSize[3];
99    programLayout->getKernelThreadGroupSize(kernelId, threadGroupSize);
100
101    // Copy global parameter data to the `SLANG_globalParams` symbol.
102    {
103        CUdeviceptr globalParamsSymbol = 0;
104        size_t globalParamsSymbolSize = 0;
105        cuModuleGetGlobal(
106            &globalParamsSymbol,
107            &globalParamsSymbolSize,
108            currentPipeline->shaderProgram->cudaModule,
109            "SLANG_globalParams");
110
111        CUdeviceptr globalParamsCUDAData = (CUdeviceptr)currentRootObject->getBuffer();
112        cuMemcpyAsync(
113            (CUdeviceptr)globalParamsSymbol,
114            (CUdeviceptr)globalParamsCUDAData,
115            globalParamsSymbolSize,
116            0);
117    }
118    //
119    // The argument data for the entry-point parameters are already
120    // stored in host memory in a CUDAEntryPointShaderObject, as expected by cuLaunchKernel.
121    //
122    auto entryPointBuffer = currentRootObject->entryPointObjects[kernelId]->getBuffer();
123    auto entryPointDataSize = currentRootObject->entryPointObjects[kernelId]->getBufferSize();
124
125    void* extraOptions[] = {
126        CU_LAUNCH_PARAM_BUFFER_POINTER,
127        entryPointBuffer,
128        CU_LAUNCH_PARAM_BUFFER_SIZE,
129        &entryPointDataSize,
130        CU_LAUNCH_PARAM_END,
131    };
132
133    // Once we have all the necessary data extracted and/or
134    // set up, we can launch the kernel and see what happens.
135    //
136    auto cudaLaunchResult = cuLaunchKernel(
137        currentPipeline->shaderProgram->cudaKernel,
138        x,
139        y,
140        z,
141        int(threadGroupSize[0]),
142        int(threadGroupSize[1]),
143        int(threadGroupSize[2]),
144        0,
145        stream,
146        nullptr,
147        extraOptions);
148
149    SLANG_ASSERT(cudaLaunchResult == CUDA_SUCCESS);
150}
151
152void CommandQueueImpl::copyBuffer(
153    IBufferResource* dst,
154    size_t dstOffset,
155    IBufferResource* src,
156    size_t srcOffset,
157    size_t size)
158{
159    auto dstImpl = static_cast<BufferResourceImpl*>(dst);
160    auto srcImpl = static_cast<BufferResourceImpl*>(src);
161    cuMemcpy(
162        (CUdeviceptr)((uint8_t*)dstImpl->m_cudaMemory + dstOffset),
163        (CUdeviceptr)((uint8_t*)srcImpl->m_cudaMemory + srcOffset),
164        size);
165}
166
167void CommandQueueImpl::uploadBufferData(
168    IBufferResource* dst,
169    size_t offset,
170    size_t size,
171    void* data)
172{
173    auto dstImpl = static_cast<BufferResourceImpl*>(dst);
174    cuMemcpy((CUdeviceptr)((uint8_t*)dstImpl->m_cudaMemory + offset), (CUdeviceptr)data, size);
175}
176
177void CommandQueueImpl::writeTimestamp(IQueryPool* pool, SlangInt index)
178{
179    auto poolImpl = static_cast<QueryPoolImpl*>(pool);
180    cuEventRecord(poolImpl->m_events[index], stream);
181}
182
183void CommandQueueImpl::execute(CommandBufferImpl* commandBuffer)
184{
185    for (auto& cmd : commandBuffer->m_commands)
186    {
187        switch (cmd.name)
188        {
189        case CommandName::SetPipelineState:
190            setPipelineState(commandBuffer->getObject<PipelineStateBase>(cmd.operands[0]));
191            break;
192        case CommandName::BindRootShaderObject:
193            bindRootShaderObject(commandBuffer->getObject<ShaderObjectBase>(cmd.operands[0]));
194            break;
195        case CommandName::DispatchCompute:
196            dispatchCompute(int(cmd.operands[0]), int(cmd.operands[1]), int(cmd.operands[2]));
197            break;
198        case CommandName::CopyBuffer:
199            copyBuffer(
200                commandBuffer->getObject<BufferResource>(cmd.operands[0]),
201                cmd.operands[1],
202                commandBuffer->getObject<BufferResource>(cmd.operands[2]),
203                cmd.operands[3],
204                cmd.operands[4]);
205            break;
206        case CommandName::UploadBufferData:
207            uploadBufferData(
208                commandBuffer->getObject<BufferResource>(cmd.operands[0]),
209                cmd.operands[1],
210                cmd.operands[2],
211                commandBuffer->getData<uint8_t>(cmd.operands[3]));
212            break;
213        case CommandName::WriteTimestamp:
214            writeTimestamp(
215                commandBuffer->getObject<QueryPoolBase>(cmd.operands[0]),
216                (SlangInt)cmd.operands[1]);
217        }
218    }
219}
220
221} // namespace cuda
222#endif
223} // namespace gfx