summaryrefslogtreecommitdiffstats
path: root/examples/gpu-printing
diff options
context:
space:
mode:
authorEllie Hermaszewska <ellieh@nvidia.com>2024-10-29 14:49:26 +0800
committerGitHub <noreply@github.com>2024-10-29 14:49:26 +0800
commitf65d756bff8d4c5cbc15bd0322a2ae8e6b896a21 (patch)
treeea1d61342cd29368e19135000ec2948813096205 /examples/gpu-printing
parenta729c15e9dce9f5116a38afc66329ab2ca4cea54 (diff)
format
* format * Minor test fixes * enable checking cpp format in ci
Diffstat (limited to 'examples/gpu-printing')
-rw-r--r--examples/gpu-printing/gpu-printing.cpp159
-rw-r--r--examples/gpu-printing/gpu-printing.h50
-rw-r--r--examples/gpu-printing/main.cpp209
3 files changed, 217 insertions, 201 deletions
diff --git a/examples/gpu-printing/gpu-printing.cpp b/examples/gpu-printing/gpu-printing.cpp
index aeca7aa9a..f71578554 100644
--- a/examples/gpu-printing/gpu-printing.cpp
+++ b/examples/gpu-printing/gpu-printing.cpp
@@ -2,7 +2,6 @@
#include "gpu-printing.h"
#include <assert.h>
-
#include <string.h>
// This file implements the CPU side of a simple GPU printing
@@ -39,7 +38,7 @@ void GPUPrinting::loadStrings(slang::ProgramLayout* slangReflection)
// that appear in the linked program.
//
SlangUInt hashedStringCount = slangReflection->getHashedStringCount();
- for( SlangUInt ii = 0; ii < hashedStringCount; ++ii )
+ for (SlangUInt ii = 0; ii < hashedStringCount; ++ii)
{
// For each string we can fetch its bytes from the Slang
// reflection data.
@@ -59,7 +58,8 @@ void GPUPrinting::loadStrings(slang::ProgramLayout* slangReflection)
// The `GPUPrinting` implementation will store the mapping
// from hash codes back to strings in a simple STL `map`.
//
- m_hashedStrings.insert(std::make_pair(hash, std::string(stringData, stringData + stringSize)));
+ m_hashedStrings.insert(
+ std::make_pair(hash, std::string(stringData, stringData + stringSize)));
}
}
@@ -73,12 +73,12 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// a granularity of 32-bits words, so we start by computing
// how many words, total, will fit in the buffer.
//
- uint32_t dataWordCount = uint32_t(dataSize/ sizeof(uint32_t));
+ uint32_t dataWordCount = uint32_t(dataSize / sizeof(uint32_t));
//
// If the buffer doesn't even have enough space for the leading counter,
// then there is nothing to print.
//
- if( dataWordCount < 1 )
+ if (dataWordCount < 1)
{
fprintf(stderr, "error: expected at least 4 bytes in GPU printing buffer\n");
return;
@@ -87,7 +87,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// Otherwise, we set ourselves up to start reading data from the buffer
// at a granularity of 32-bit words.
//
- const uint32_t* dataCursor = (const uint32_t*) data;
+ const uint32_t* dataCursor = (const uint32_t*)data;
// The first word of a printing buffer gives us the total number of
// words that were appended by GPU printing operations.
@@ -106,20 +106,25 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// larger buffer.
//
size_t totalBytesWritten = sizeof(uint32_t) * (wordsAppended + 1);
- if( totalBytesWritten > dataSize )
+ if (totalBytesWritten > dataSize)
{
- fprintf(stderr, "warning: GPU code attempted to write %llu bytes to the printing buffer, but only %llu bytes were available\n", (unsigned long long)totalBytesWritten, (unsigned long long)dataSize);
+ fprintf(
+ stderr,
+ "warning: GPU code attempted to write %llu bytes to the printing buffer, but only %llu "
+ "bytes were available\n",
+ (unsigned long long)totalBytesWritten,
+ (unsigned long long)dataSize);
// If the buffer is full, then we only want to read through
// to the end of what is available.
//
- dataEnd = ((const uint32_t*) data) + dataWordCount;
+ dataEnd = ((const uint32_t*)data) + dataWordCount;
}
// We will now proceed to read off "commands" from the buffer,
// and execute those commands to print things to `stdout`.
//
- while( dataCursor < dataEnd )
+ while (dataCursor < dataEnd)
{
// The first word of each command is encoded to hold both
// an "opcode" for the command, and the number of "payload"
@@ -135,7 +140,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// avoid crashes from a command trying to fetch data past
// the end of the buffer.
//
- if( payloadWordCount > size_t(dataCursor - dataEnd) )
+ if (payloadWordCount > size_t(dataCursor - dataEnd))
{
break;
}
@@ -149,7 +154,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
dataCursor += payloadWordCount;
// What to do with a command depends a lot on which "op" was selected.
- switch( op )
+ switch (op)
{
default:
// If we encounter an op that we don't understand, there is a change
@@ -176,21 +181,21 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// We will use a macro to avoid duplication the code shared
// between these cases.
//
- #define CASE(OP, FORMAT, TYPE) \
- case GPUPrintingOp::OP: \
- { \
- TYPE value; \
- assert(payloadWordCount >= (sizeof(value) / sizeof(uint32_t))); \
- memcpy(&value, payloadWords, sizeof(value)); \
- printf(FORMAT, value); \
- } \
- break
-
- CASE(Int32, "%d", int);
- CASE(UInt32, "%u", unsigned int);
- CASE(Float32, "%f", float);
-
- #undef CASE
+#define CASE(OP, FORMAT, TYPE) \
+ case GPUPrintingOp::OP: \
+ { \
+ TYPE value; \
+ assert(payloadWordCount >= (sizeof(value) / sizeof(uint32_t))); \
+ memcpy(&value, payloadWords, sizeof(value)); \
+ printf(FORMAT, value); \
+ } \
+ break
+
+ CASE(Int32, "%d", int);
+ CASE(UInt32, "%u", unsigned int);
+ CASE(Float32, "%f", float);
+
+#undef CASE
case GPUPrintingOp::String:
{
@@ -214,7 +219,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// to appear in the GPU code.
//
auto iter = m_hashedStrings.find(hash);
- if(iter == m_hashedStrings.end())
+ if (iter == m_hashedStrings.end())
{
// If we didn't have a string to match that hash code in
// our map, we can continue trying to print, but it is
@@ -230,7 +235,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
//
// TODO: This code isn't robust against strings with
// embeded null bytes.
- //s
+ // s
printf("%s", iter->second.c_str());
}
break;
@@ -248,7 +253,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
StringHash formatHash = *payloadWords++;
auto iter = m_hashedStrings.find(formatHash);
- if(iter == m_hashedStrings.end())
+ if (iter == m_hashedStrings.end())
{
// If we didn't have a string to match that hash code in
// our map, we can continue trying to print, but it is
@@ -270,14 +275,14 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
//
const char* cursor = format.c_str();
const char* end = cursor + format.length();
- while( cursor != end )
+ while (cursor != end)
{
int c = *cursor++;
// If we see a byte other than `%`, then we can just
// output it directly and keep scanning the format string.
//
- if( c != '%' )
+ if (c != '%')
{
putchar(c);
continue;
@@ -289,7 +294,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// If we are somehow at the end of the format
// string, then the format was bad.
//
- if( cursor == end )
+ if (cursor == end)
{
fprintf(stderr, "error: unexpected '%%' at and of format string\n");
break;
@@ -299,7 +304,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// the `%` character, then it is an escaped
// `%` so we should just emit it as-is and move along.
//
- if( *cursor == '%' )
+ if (*cursor == '%')
{
putchar(*cursor++);
continue;
@@ -317,52 +322,56 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
// read a single-byte specifier.
//
int specifier = *cursor++;
- switch( specifier )
+ switch (specifier)
{
default:
- fprintf(stderr, "error: unexpected format specifier '%c' (0x%X)\n", specifier, specifier);
+ fprintf(
+ stderr,
+ "error: unexpected format specifier '%c' (0x%X)\n",
+ specifier,
+ specifier);
break;
- // When processing each format speecifier, we will
- // read words from the payload, as necessary
- // to yield a value of the expected type.
- //
- // To reduce the amount of boilerplate, we will
- // use a macro to capture the shared code for
- // common cases.
- //
- #define CASE(CHAR, FORMAT, TYPE) \
- case CHAR: \
- { \
- assert(payloadWords != payloadWordsEnd); \
- TYPE value; \
- memcpy(&value, payloadWords, sizeof(value)); \
- payloadWords += sizeof(value) / sizeof(uint32_t); \
- printf(FORMAT, value); \
- } \
- break
+ // When processing each format speecifier, we will
+ // read words from the payload, as necessary
+ // to yield a value of the expected type.
+ //
+ // To reduce the amount of boilerplate, we will
+ // use a macro to capture the shared code for
+ // common cases.
+ //
+#define CASE(CHAR, FORMAT, TYPE) \
+ case CHAR: \
+ { \
+ assert(payloadWords != payloadWordsEnd); \
+ TYPE value; \
+ memcpy(&value, payloadWords, sizeof(value)); \
+ payloadWords += sizeof(value) / sizeof(uint32_t); \
+ printf(FORMAT, value); \
+ } \
+ break
case 'i': // `%i` is just an alias for `%d`
- CASE('d', "%d", int);
- CASE('u', "%u", unsigned int);
- CASE('x', "%x", unsigned int);
- CASE('X', "%X", unsigned int);
-
- // Note: all of our printing support for floating-point
- // values will use the `float` type instead of `double`.
- // This isn't compatible with C rules, but makes more sense
- // for GPU code.
- //
- CASE('f', "%f", float);
- CASE('F', "%F", float);
- CASE('e', "%e", float);
- CASE('E', "%E", float);
- CASE('g', "%g", float);
- CASE('G', "%G", float);
- CASE('c', "%c", int);
-
- #undef CASE
+ CASE('d', "%d", int);
+ CASE('u', "%u", unsigned int);
+ CASE('x', "%x", unsigned int);
+ CASE('X', "%X", unsigned int);
+
+ // Note: all of our printing support for floating-point
+ // values will use the `float` type instead of `double`.
+ // This isn't compatible with C rules, but makes more sense
+ // for GPU code.
+ //
+ CASE('f', "%f", float);
+ CASE('F', "%F", float);
+ CASE('e', "%e", float);
+ CASE('E', "%E", float);
+ CASE('g', "%g", float);
+ CASE('G', "%G", float);
+ CASE('c', "%c", int);
+
+#undef CASE
case 's':
{
@@ -373,7 +382,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
assert(payloadWords != payloadWordsEnd);
StringHash hash = *payloadWords++;
auto iter = m_hashedStrings.find(hash);
- if(iter == m_hashedStrings.end())
+ if (iter == m_hashedStrings.end())
{
fprintf(stderr, "error: string with unknown hash 0x%x\n", hash);
continue;
@@ -387,6 +396,4 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize)
break;
}
}
-
-
}
diff --git a/examples/gpu-printing/gpu-printing.h b/examples/gpu-printing/gpu-printing.h
index 64eaf770a..84c036548 100644
--- a/examples/gpu-printing/gpu-printing.h
+++ b/examples/gpu-printing/gpu-printing.h
@@ -19,39 +19,39 @@
#include <map>
#include <string>
- /// Stores state used for executing print commands generated by GPU shaders
+/// Stores state used for executing print commands generated by GPU shaders
struct GPUPrinting
{
public:
- /// Load any string literals used by a Slang program.
- ///
- /// The `slangReflection` should be the layout and reflection
- /// object for a Slang shader program that might need to produce
- /// printed output. This function will load any strings
- /// referenced by the program into its database for mapping
- /// string hashes back to the original strings.
- ///
+ /// Load any string literals used by a Slang program.
+ ///
+ /// The `slangReflection` should be the layout and reflection
+ /// object for a Slang shader program that might need to produce
+ /// printed output. This function will load any strings
+ /// referenced by the program into its database for mapping
+ /// string hashes back to the original strings.
+ ///
void loadStrings(slang::ProgramLayout* slangReflection);
- /// Process a buffer of GPU printing commands and write output to `stdout`.
- ///
- /// This function attempts to read print commands from the buffer
- /// pointed to by `data` and execute them to produce output.
- ///
- /// The buffer pointed at by `data` (of size `dataSize`) should be allocated
- /// in host-visible memory.
- ///
- /// Before executing GPU work, the first four bytes pointed to by `data`
- /// should have been cleared to zero.
- ///
- /// If GPU work has attempted to write more data than the buffer
- /// can fit, a warning will be printed to `stderr`, and printing commands
- /// that could not fit completely in the buffer will be skipped.
- ///
+ /// Process a buffer of GPU printing commands and write output to `stdout`.
+ ///
+ /// This function attempts to read print commands from the buffer
+ /// pointed to by `data` and execute them to produce output.
+ ///
+ /// The buffer pointed at by `data` (of size `dataSize`) should be allocated
+ /// in host-visible memory.
+ ///
+ /// Before executing GPU work, the first four bytes pointed to by `data`
+ /// should have been cleared to zero.
+ ///
+ /// If GPU work has attempted to write more data than the buffer
+ /// can fit, a warning will be printed to `stderr`, and printing commands
+ /// that could not fit completely in the buffer will be skipped.
+ ///
void processGPUPrintCommands(const void* data, size_t dataSize);
private:
typedef int StringHash;
- std::map<StringHash, std::string> m_hashedStrings;
+ std::map<StringHash, std::string> m_hashedStrings;
};
diff --git a/examples/gpu-printing/main.cpp b/examples/gpu-printing/main.cpp
index fd15661dd..fa9f919dc 100644
--- a/examples/gpu-printing/main.cpp
+++ b/examples/gpu-printing/main.cpp
@@ -1,17 +1,16 @@
// main.cpp
-#include <string>
-
+#include "slang-com-ptr.h"
#include "slang.h"
-#include "slang-com-ptr.h"
+#include <string>
using Slang::ComPtr;
+#include "examples/example-base/example-base.h"
+#include "gfx-util/shader-cursor.h"
#include "gpu-printing.h"
#include "slang-gfx.h"
-#include "gfx-util/shader-cursor.h"
-#include "tools/platform/window.h"
#include "source/core/slang-basic.h"
-#include "examples/example-base/example-base.h"
+#include "tools/platform/window.h"
using namespace gfx;
@@ -23,7 +22,9 @@ ComPtr<slang::ISession> createSlangSession(gfx::IDevice* device)
return slangSession;
}
-ComPtr<slang::IModule> compileShaderModuleFromFile(slang::ISession* slangSession, char const* filePath)
+ComPtr<slang::IModule> compileShaderModuleFromFile(
+ slang::ISession* slangSession,
+ char const* filePath)
{
ComPtr<slang::IModule> slangModule;
ComPtr<slang::IBlob> diagnosticBlob;
@@ -34,113 +35,121 @@ ComPtr<slang::IModule> compileShaderModuleFromFile(slang::ISession* slangSession
return slangModule;
}
-struct ExampleProgram: public TestBase
+struct ExampleProgram : public TestBase
{
-int gWindowWidth = 640;
-int gWindowHeight = 480;
+ int gWindowWidth = 640;
+ int gWindowHeight = 480;
-ComPtr<gfx::IDevice> gDevice;
+ ComPtr<gfx::IDevice> gDevice;
-ComPtr<slang::ISession> gSlangSession;
-ComPtr<slang::IModule> gSlangModule;
-ComPtr<gfx::IShaderProgram> gProgram;
+ ComPtr<slang::ISession> gSlangSession;
+ ComPtr<slang::IModule> gSlangModule;
+ ComPtr<gfx::IShaderProgram> gProgram;
-ComPtr<gfx::IPipelineState> gPipelineState;
+ ComPtr<gfx::IPipelineState> gPipelineState;
-Slang::Dictionary<int, std::string> gHashedStrings;
+ Slang::Dictionary<int, std::string> gHashedStrings;
-GPUPrinting gGPUPrinting;
+ GPUPrinting gGPUPrinting;
-ComPtr<gfx::IShaderProgram> loadComputeProgram(slang::IModule* slangModule, char const* entryPointName)
-{
- ComPtr<slang::IEntryPoint> entryPoint;
- slangModule->findEntryPointByName(entryPointName, entryPoint.writeRef());
-
- ComPtr<slang::IComponentType> linkedProgram;
- entryPoint->link(linkedProgram.writeRef());
-
- if (isTestMode())
+ ComPtr<gfx::IShaderProgram> loadComputeProgram(
+ slang::IModule* slangModule,
+ char const* entryPointName)
{
- printEntrypointHashes(1, 1, linkedProgram);
- }
+ ComPtr<slang::IEntryPoint> entryPoint;
+ slangModule->findEntryPointByName(entryPointName, entryPoint.writeRef());
- gGPUPrinting.loadStrings(linkedProgram->getLayout());
+ ComPtr<slang::IComponentType> linkedProgram;
+ entryPoint->link(linkedProgram.writeRef());
- gfx::IShaderProgram::Desc programDesc = {};
- programDesc.slangGlobalScope = linkedProgram;
+ if (isTestMode())
+ {
+ printEntrypointHashes(1, 1, linkedProgram);
+ }
- auto shaderProgram = gDevice->createProgram(programDesc);
+ gGPUPrinting.loadStrings(linkedProgram->getLayout());
- return shaderProgram;
-}
+ gfx::IShaderProgram::Desc programDesc = {};
+ programDesc.slangGlobalScope = linkedProgram;
-Result execute(int argc, char* argv[])
-{
- parseOption(argc, argv);
- IDevice::Desc deviceDesc;
- Result res = gfxCreateDevice(&deviceDesc, gDevice.writeRef());
- if(SLANG_FAILED(res)) return res;
-
- Slang::String path = resourceBase.resolveResource("kernels.slang");
-
- gSlangSession = createSlangSession(gDevice);
- gSlangModule = compileShaderModuleFromFile(gSlangSession, path.getBuffer());
- if(!gSlangModule)
- return SLANG_FAIL;
-
- gProgram = loadComputeProgram(gSlangModule, "computeMain");
- if(!gProgram)
- return SLANG_FAIL;
-
- ComputePipelineStateDesc desc;
- desc.program = gProgram;
- auto pipelineState = gDevice->createComputePipelineState(desc);
- if(!pipelineState) return SLANG_FAIL;
-
- gPipelineState = pipelineState;
-
- size_t printBufferSize = 4 * 1024; // use a small-ish (4KB) buffer for print output
-
- IBufferResource::Desc printBufferDesc = {};
- printBufferDesc.type = IResource::Type::Buffer;
- printBufferDesc.sizeInBytes = printBufferSize;
- printBufferDesc.elementSize = sizeof(uint32_t);
- printBufferDesc.defaultState = ResourceState::UnorderedAccess;
- printBufferDesc.allowedStates = ResourceStateSet(
- ResourceState::CopySource, ResourceState::CopyDestination, ResourceState::UnorderedAccess);
- printBufferDesc.memoryType = MemoryType::DeviceLocal;
- auto printBuffer = gDevice->createBufferResource(printBufferDesc);
-
- IResourceView::Desc printBufferViewDesc = {};
- printBufferViewDesc.type = IResourceView::Type::UnorderedAccess;
- printBufferViewDesc.format = Format::Unknown;
- auto printBufferView = gDevice->createBufferView(printBuffer, nullptr, printBufferViewDesc);
-
- ITransientResourceHeap::Desc transientResourceHeapDesc = {};
- transientResourceHeapDesc.constantBufferSize = 256;
- auto transientHeap = gDevice->createTransientResourceHeap(transientResourceHeapDesc);
-
- ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics};
- auto queue = gDevice->createCommandQueue(queueDesc);
- auto commandBuffer = transientHeap->createCommandBuffer();
- auto encoder = commandBuffer->encodeComputeCommands();
- auto rootShaderObject = encoder->bindPipeline(gPipelineState);
- auto cursor = ShaderCursor(rootShaderObject);
- cursor["gPrintBuffer"].setResource(printBufferView);
- encoder->dispatchCompute(1, 1, 1);
- encoder->bufferBarrier(printBuffer, ResourceState::UnorderedAccess, ResourceState::CopySource);
- encoder->endEncoding();
- commandBuffer->close();
- queue->executeCommandBuffer(commandBuffer);
-
- ComPtr<ISlangBlob> blob;
- gDevice->readBufferResource(printBuffer, 0, printBufferSize, blob.writeRef());
-
- gGPUPrinting.processGPUPrintCommands(blob->getBufferPointer(), printBufferSize);
-
- return SLANG_OK;
-}
+ auto shaderProgram = gDevice->createProgram(programDesc);
+
+ return shaderProgram;
+ }
+ Result execute(int argc, char* argv[])
+ {
+ parseOption(argc, argv);
+ IDevice::Desc deviceDesc;
+ Result res = gfxCreateDevice(&deviceDesc, gDevice.writeRef());
+ if (SLANG_FAILED(res))
+ return res;
+
+ Slang::String path = resourceBase.resolveResource("kernels.slang");
+
+ gSlangSession = createSlangSession(gDevice);
+ gSlangModule = compileShaderModuleFromFile(gSlangSession, path.getBuffer());
+ if (!gSlangModule)
+ return SLANG_FAIL;
+
+ gProgram = loadComputeProgram(gSlangModule, "computeMain");
+ if (!gProgram)
+ return SLANG_FAIL;
+
+ ComputePipelineStateDesc desc;
+ desc.program = gProgram;
+ auto pipelineState = gDevice->createComputePipelineState(desc);
+ if (!pipelineState)
+ return SLANG_FAIL;
+
+ gPipelineState = pipelineState;
+
+ size_t printBufferSize = 4 * 1024; // use a small-ish (4KB) buffer for print output
+
+ IBufferResource::Desc printBufferDesc = {};
+ printBufferDesc.type = IResource::Type::Buffer;
+ printBufferDesc.sizeInBytes = printBufferSize;
+ printBufferDesc.elementSize = sizeof(uint32_t);
+ printBufferDesc.defaultState = ResourceState::UnorderedAccess;
+ printBufferDesc.allowedStates = ResourceStateSet(
+ ResourceState::CopySource,
+ ResourceState::CopyDestination,
+ ResourceState::UnorderedAccess);
+ printBufferDesc.memoryType = MemoryType::DeviceLocal;
+ auto printBuffer = gDevice->createBufferResource(printBufferDesc);
+
+ IResourceView::Desc printBufferViewDesc = {};
+ printBufferViewDesc.type = IResourceView::Type::UnorderedAccess;
+ printBufferViewDesc.format = Format::Unknown;
+ auto printBufferView = gDevice->createBufferView(printBuffer, nullptr, printBufferViewDesc);
+
+ ITransientResourceHeap::Desc transientResourceHeapDesc = {};
+ transientResourceHeapDesc.constantBufferSize = 256;
+ auto transientHeap = gDevice->createTransientResourceHeap(transientResourceHeapDesc);
+
+ ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics};
+ auto queue = gDevice->createCommandQueue(queueDesc);
+ auto commandBuffer = transientHeap->createCommandBuffer();
+ auto encoder = commandBuffer->encodeComputeCommands();
+ auto rootShaderObject = encoder->bindPipeline(gPipelineState);
+ auto cursor = ShaderCursor(rootShaderObject);
+ cursor["gPrintBuffer"].setResource(printBufferView);
+ encoder->dispatchCompute(1, 1, 1);
+ encoder->bufferBarrier(
+ printBuffer,
+ ResourceState::UnorderedAccess,
+ ResourceState::CopySource);
+ encoder->endEncoding();
+ commandBuffer->close();
+ queue->executeCommandBuffer(commandBuffer);
+
+ ComPtr<ISlangBlob> blob;
+ gDevice->readBufferResource(printBuffer, 0, printBufferSize, blob.writeRef());
+
+ gGPUPrinting.processGPUPrintCommands(blob->getBufferPointer(), printBufferSize);
+
+ return SLANG_OK;
+ }
};
int main(int argc, char* argv[])