summaryrefslogtreecommitdiffstats
path: root/LUTS/SSFD_4x4/dots_L11.png
blob: 2bf663760d0d03fccc7be439b981a848d5b320ea (plain)
ofshex dumpascii
0000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 80 00 00 00 80 08 00 00 00 00 e6 55 3e .PNG........IHDR..............U>
0020 17 00 00 01 11 49 44 41 54 78 da ed 9b c1 0e c3 30 08 43 fd ff 3f dd 5d 76 d8 d4 36 59 96 b8 46 .....IDATx......0.C..?.]v..6Y..F
0040 ca f3 d5 02 f9 52 70 09 e8 f8 80 de 38 6e e0 e0 85 80 4a 02 a4 76 06 0b 5f 49 80 d4 ce e0 e1 0b .....Rp.....8n....J..v.._I......
0060 09 90 da 19 4c bc ae f9 73 06 17 af 6b fa f4 b1 d8 78 dd d1 5f 2a 8d bc 00 00 a0 85 5e 21 31 c7 ....L...s...k....x.._*......^!1.
0080 f7 4a a9 39 be d7 4c 9e 8e 1f cd b0 3e 7e 2c c3 6c 7c 5c 40 cf 54 ba e3 e3 02 7a 3f 16 ee 78 04 .J.9..L.....>~,.l|\@.T....z?..x.
00a0 20 00 01 79 01 54 42 ba 61 01 43 92 b7 64 79 53 5a c0 96 03 00 76 9a 01 b8 0a cd 4f 83 4a 5f a9 ...y.TB.a.C..dySZ....v.....O.J_.
00c0 1d 18 d5 3a 9a cd e0 b0 7a 79 bb 1d 1f d7 af 35 1c d3 2f 26 11 01 0b 4d e7 f4 ab 59 48 c0 b2 1f ...:....zy.....5../&...M...YH...
00e0 8f e9 97 53 04 20 00 01 29 01 db 57 c2 ed bb 61 da 90 84 2d 59 d8 94 46 6d 39 00 00 14 1e 54 b2 ...S....)..W...a...-Y..Fm9....T.
0100 3f c0 fe 00 fb 03 ec 0f 20 00 01 08 60 7f 80 fd 01 f6 07 d8 1f 60 7f 00 00 f0 e0 0c e0 df 42 62 ?...........`........`........Bb
0120 de 1f 78 f0 d4 ab c0 b1 5b 81 73 3f 2e 2e b9 ba e5 f2 7a 5b 01 2f 4c b6 09 11 b5 88 73 f6 00 00 ..x.....[.s?......z[./L.....s...
0140 00 00 49 45 4e 44 ae 42 60 82 ..IEND.B`.
1' href='#n81'>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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
// main.cpp

#include <stdio.h>

// This file implements an extremely simple example of loading and
// executing a Slang shader program on the CPU.
//
// More information about generation C++ or CPU code can be found in docs/cpu-target.md
//
// NOTE! This test will only run on a system correctly where slang can find a suitable
// C++ compiler - such as clang/gcc/visual studio
//
// The comments in the file will attempt to explain concepts as
// they are introduced.
//
// Of course, in order to use the Slang API, we need to include
// its header. We have set up the build options for this project
// so that it is as simple as:
#include "slang.h"

// Allows use of ComPtr - which we can use to scope any 'com-like' pointers easily
#include "slang-com-ptr.h"
// Provides macros for handling SlangResult values easily
#include "slang-com-helper.h"

// This includes a useful small function for setting up the prelude (described more further below).
#include "../../source/core/slang-test-tool-util.h"
#include "examples/example-base/example-base.h"

// Slang namespace is used for elements support code (like core) which we use here
// for ComPtr<> and TestToolUtil
using namespace Slang;

// Slang source is converted into C++ code which is compiled by a backend compiler.
// That process uses a 'prelude' which defines types and functions that are needed
// for everything else to work.
//
// We include the prelude here, so we can directly use the types as were used by the
// compiled code. It is not necessary to include the prelude, as long as memory is
// laid out in the manner that the generated slang code expects.
#define SLANG_PRELUDE_NAMESPACE CPPPrelude
#include "../../prelude/slang-cpp-types.h"

static const ExampleResources resourceBase("cpu-hello-world");

struct UniformState;

static SlangResult _innerMain(int argc, char** argv)
{
    TestBase testBase;
    testBase.parseOption(argc, argv);

    // 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.
    //
    // NOTE that we use attach instead of setting via assignment, as assignment will increase
    // the refcount. spCreateSession returns a IGlobalSession with a refcount of 1.
    ComPtr<slang::IGlobalSession> slangSession;

    SLANG_RETURN_ON_FAIL(slang::createGlobalSession(slangSession.writeRef()));

    // As touched on earlier, in order to generate the final executable code,
    // the slang code is converted into C++, and that C++ needs a 'prelude' which
    // is just definitions that the generated code needed to work correctly.
    // There is a simple default definition of a prelude provided in the prelude
    // directory called 'slang-cpp-prelude.h'.
    //
    // We need to tell slang either the contents of the prelude, or suitable include/s
    // that will work. The actual API call to set the prelude is `setPrelude`
    // and this just sets for a specific language a bit of text placed before generated code.
    //
    // Most downstream C++ compilers work on files. In that case slang may generate temporary
    // files that contain the generated code. Typically the generated files  will not be in the
    // same directory as the original source so handling includes becomes awkward. The mechanism
    // used here is for the prelude code to be an *absolute* path to the 'slang-cpp-prelude.h' -
    // which means this will work wherever the generated code is, and allows accessing other files
    // via relative paths.
    //
    // Look at the source to TestToolUtil::setSessionDefaultPreludeFromExePath to see what's
    // involed.
    TestToolUtil::setSessionDefaultPreludeFromExePath(argv[0], slangSession);

    slang::SessionDesc sessionDesc = {};
    slang::TargetDesc targetDesc = {};
    targetDesc.format = SLANG_SHADER_HOST_CALLABLE;
    targetDesc.flags = SLANG_TARGET_FLAG_GENERATE_WHOLE_PROGRAM;

    sessionDesc.targets = &targetDesc;
    sessionDesc.targetCount = 1;

    ComPtr<slang::ISession> session;
    SLANG_RETURN_ON_FAIL(slangSession->createSession(sessionDesc, session.writeRef()));

    slang::IModule* slangModule = nullptr;
    {
        ComPtr<slang::IBlob> diagnosticBlob;
        Slang::String path = resourceBase.resolveResource("shader.slang");
        slangModule = session->loadModule(path.getBuffer(), diagnosticBlob.writeRef());
        diagnoseIfNeeded(diagnosticBlob);
        if (!slangModule)
            return -1;
    }

    ComPtr<slang::IEntryPoint> entryPoint;
    slangModule->findEntryPointByName("computeMain", entryPoint.writeRef());

    Slang::List<slang::IComponentType*> componentTypes;
    componentTypes.add(slangModule);
    componentTypes.add(entryPoint);

    ComPtr<slang::IComponentType> composedProgram;
    {
        ComPtr<slang::IBlob> diagnosticsBlob;
        SlangResult result = session->createCompositeComponentType(
            componentTypes.getBuffer(),
            componentTypes.getCount(),
            composedProgram.writeRef(),
            diagnosticsBlob.writeRef());
        diagnoseIfNeeded(diagnosticsBlob);
        SLANG_RETURN_ON_FAIL(result);
    }

    // Get the 'shared library' (note that this doesn't necessarily have to be implemented as a
    // shared library it's just an interface to executable code).
    ComPtr<ISlangSharedLibrary> sharedLibrary;
    {
        ComPtr<slang::IBlob> diagnosticsBlob;
        SlangResult result = composedProgram->getEntryPointHostCallable(
            0,
            0,
            sharedLibrary.writeRef(),
            diagnosticsBlob.writeRef());
        diagnoseIfNeeded(diagnosticsBlob);
        SLANG_RETURN_ON_FAIL(result);
        if (testBase.isTestMode())
        {
            testBase.printEntrypointHashes(1, 1, composedProgram);
        }
    }
    // Once we have the sharedLibrary, we no longer need the request
    // unless we want to use reflection, to for example workout how 'UniformState' and
    // 'UniformEntryPointParams' are laid out at runtime. We don't do that here - as we hard code
    // the structures.

    // Get the function we are going to execute
    const char entryPointName[] = "computeMain";
    CPPPrelude::ComputeFunc func =
        (CPPPrelude::ComputeFunc)sharedLibrary->findFuncByName(entryPointName);
    if (!func)
    {
        return SLANG_FAIL;
    }

    // Define the uniform state structure that is *specific* to our shader defined in shader.slang
    // That the layout of the structure can be determined through reflection, or can be inferred
    // from the original slang source. Look at the documentation in docs/cpu-target.md which
    // describes how different resources map. The order of the resources is in the order that they
    // are defined in the source.
    struct UniformState
    {
        CPPPrelude::RWStructuredBuffer<float> ioBuffer;
    };

    // the uniformState will be passed as a pointer to the CPU code
    UniformState uniformState;

    // The contents of the buffer are modified, so we'll copy it
    const float startBufferContents[] = {2.0f, -10.0f, -3.0f, 5.0f};
    float bufferContents[SLANG_COUNT_OF(startBufferContents)];
    memcpy(bufferContents, startBufferContents, sizeof(startBufferContents));

    // Set up the ioBuffer such that it uses bufferContents. It is important to set the .count
    // such that bounds checking can be performed in the kernel.
    uniformState.ioBuffer.data = bufferContents;
    uniformState.ioBuffer.count = SLANG_COUNT_OF(bufferContents);

    // In shader.slang, then entry point is attributed with `[numthreads(4, 1, 1)]` meaning each
    // group consists of 4 'thread' in x. Our input buffer is 4 wide, and we index the input array
    // via `SV_DispatchThreadID` so we only need to run a single group to execute over all of the 4
    // elements here. The group range from { 0, 0, 0 } -> { 1, 1, 1 } means it will execute over the
    // single group { 0, 0, 0 }.

    const CPPPrelude::uint3 startGroupID = {0, 0, 0};
    const CPPPrelude::uint3 endGroupID = {1, 1, 1};

    CPPPrelude::ComputeVaryingInput varyingInput;
    varyingInput.startGroupID = startGroupID;
    varyingInput.endGroupID = endGroupID;

    // We don't have any entry point parameters so that's passed as NULL
    // We need to cast our definition of the uniform state to the undefined CPPPrelude::UniformState
    // as that type is just a name to indicate what kind of thing needs to be passed in.
    func(&varyingInput, NULL, &uniformState);

    // bufferContents holds the output

    // Print out the values before the computation
    printf("Before:\n");
    for (float v : startBufferContents)
    {
        printf("%f, ", v);
    }
    printf("\n");

    // Print out the values the the kernel produced
    printf("After: \n");
    for (float v : bufferContents)
    {
        printf("%f, ", v);
    }
    printf("\n");

    return SLANG_OK;
}

int exampleMain(int argc, char** argv)
{
    return SLANG_SUCCEEDED(_innerMain(argc, argv)) ? 0 : -1;
}