https://github.com/shader-slang/slang
Raw File
Tip revision: af63ee4e4df8a4a7a8eead72780222eaeb746f34 authored by Tim Foley on 25 February 2021, 03:22:31 UTC
Partial fix for macro expasnion of token pastes (#1727)
Tip revision: af63ee4
slang-gfx.h
// render.h
#pragma once

#include <float.h>
#include <assert.h>

#include "slang.h"
#include "slang-com-ptr.h"
#include "slang-com-helper.h"


#if defined(SLANG_GFX_DYNAMIC)
#    if defined(_MSC_VER)
#        ifdef SLANG_GFX_DYNAMIC_EXPORT
#            define SLANG_GFX_API SLANG_DLL_EXPORT
#        else
#            define SLANG_GFX_API __declspec(dllimport)
#        endif
#    else
// TODO: need to consider compiler capabilities
//#     ifdef SLANG_DYNAMIC_EXPORT
#        define SLANG_GFX_API SLANG_DLL_EXPORT
//#     endif
#    endif
#endif

#ifndef SLANG_GFX_API
#    define SLANG_GFX_API
#endif

namespace gfx {

using Slang::ComPtr;

typedef SlangResult Result;

// Had to move here, because Options needs types defined here
typedef SlangInt Int;
typedef SlangUInt UInt;

// Declare opaque type
class IInputLayout: public ISlangUnknown
{
};
#define SLANG_UUID_IInputLayout                                                         \
    {                                                                                  \
        0x45223711, 0xa84b, 0x455c, { 0xbe, 0xfa, 0x49, 0x37, 0x42, 0x1e, 0x8e, 0x2e } \
    }

enum class PipelineType
{
    Unknown,
    Graphics,
    Compute,
    RayTracing,
    CountOf,
};

enum class StageType
{
    Unknown,
    Vertex,
    Hull,
    Domain,
    Geometry,
    Fragment,
    Compute,
    RayGeneration,
    Intersection,
    AnyHit,
    ClosestHit,
    Miss,
    Callable,
    Amplification,
    Mesh,
    CountOf,
};

enum class RendererType
{
    Unknown,
    DirectX11,
    DirectX12,
    OpenGl,
    Vulkan,
    CPU,
    CUDA,
    CountOf,
};

enum class ProjectionStyle
{
    Unknown,
    OpenGl, 
    DirectX,
    Vulkan,
    CountOf,
};

/// The style of the binding
enum class BindingStyle
{
    Unknown,
    DirectX,
    OpenGl,
    Vulkan,
    CPU,
    CUDA,
    CountOf,
};

class IShaderProgram: public ISlangUnknown
{
public:

    struct KernelDesc
    {
        StageType   stage;
        void const* codeBegin;
        void const* codeEnd;
        char const* entryPointName;

        UInt getCodeSize() const { return (char const*)codeEnd - (char const*)codeBegin; }
    };

    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
        {
            for(Int ii = 0; ii < kernelCount; ++ii)
                if(kernels[ii].stage == stage)
                    return &kernels[ii];
            return nullptr;
        }
    };
};
#define SLANG_UUID_IShaderProgram                                                       \
    {                                                                                  \
        0x9d32d0ad, 0x915c, 0x4ffd, { 0x91, 0xe2, 0x50, 0x85, 0x54, 0xa0, 0x4a, 0x76 } \
    }

/// Different formats of things like pixels or elements of vertices
/// NOTE! Any change to this type (adding, removing, changing order) - must also be reflected in changes to RendererUtil
enum class Format
{
    Unknown,

    RGBA_Float32,
    RGB_Float32,
    RG_Float32,
    R_Float32,

    RGBA_Unorm_UInt8,
    BGRA_Unorm_UInt8,

    R_UInt16,
    R_UInt32,

    D_Float32,
    D_Unorm24_S8,

    CountOf,
};

struct InputElementDesc
{
    char const* semanticName;
    UInt        semanticIndex;
    Format      format;
    UInt        offset;
};

enum class MapFlavor
{
    Unknown,                    ///< Unknown mapping type
    HostRead,
    HostWrite,
    WriteDiscard,
};

enum class PrimitiveTopology
{
    TriangleList,
};

class IResource: public ISlangUnknown
{
public:
        /// The type of resource.
        /// NOTE! The order needs to be such that all texture types are at or after Texture1D (otherwise isTexture won't work correctly)
    enum class Type
    {
        Unknown,            ///< Unknown
        Buffer,             ///< A buffer (like a constant/index/vertex buffer)
        Texture1D,          ///< A 1d texture
        Texture2D,          ///< A 2d texture
        Texture3D,          ///< A 3d texture
        TextureCube,        ///< A cubemap consists of 6 Texture2D like faces
        CountOf,
    };

        /// Describes how a resource is to be used
    enum class Usage
    {
        Unknown = -1,
        VertexBuffer = 0,
        IndexBuffer,
        ConstantBuffer,
        StreamOutput,
        RenderTarget,
        DepthRead,
        DepthWrite,
        UnorderedAccess,
        PixelShaderResource,
        NonPixelShaderResource,
        GenericRead,
        CountOf,
    };

        /// Binding flags describe all of the ways a resource can be bound - and therefore used
    struct BindFlag
    {
        enum Enum
        {
            VertexBuffer            = 0x001,
            IndexBuffer             = 0x002,
            ConstantBuffer          = 0x004,
            StreamOutput            = 0x008,
            RenderTarget            = 0x010,
            DepthStencil            = 0x020,
            UnorderedAccess         = 0x040,
            PixelShaderResource     = 0x080,
            NonPixelShaderResource  = 0x100,
        };
    };

        /// Combinations describe how a resource can be accessed (typically by the host/cpu)
    struct AccessFlag
    {
        enum Enum
        {
            Read = 0x1,
            Write = 0x2
        };
    };

        /// Base class for Descs
    struct DescBase
    {
        bool canBind(BindFlag::Enum bindFlag) const { return (bindFlags & bindFlag) != 0; }
        bool hasCpuAccessFlag(AccessFlag::Enum accessFlag) { return (cpuAccessFlags & accessFlag) != 0; }

        Type type = Type::Unknown;

        int bindFlags = 0;          ///< Combination of Resource::BindFlag or 0 (and will use initialUsage to set)
        int cpuAccessFlags = 0;     ///< Combination of Resource::AccessFlag
    };

    inline static BindFlag::Enum getDefaultBindFlagsFromUsage(IResource::Usage usage)
    {
        switch (usage)
        {
        case Usage::VertexBuffer:
            return BindFlag::VertexBuffer;
        case Usage::IndexBuffer:
            return BindFlag::IndexBuffer;
        case Usage::ConstantBuffer:
            return BindFlag::ConstantBuffer;
        case Usage::StreamOutput:
            return BindFlag::StreamOutput;
        case Usage::RenderTarget:
            return BindFlag::RenderTarget;
        case Usage::DepthRead:
        case Usage::DepthWrite:
            return BindFlag::DepthStencil;
        case Usage::UnorderedAccess:
            return BindFlag::Enum(BindFlag::UnorderedAccess | BindFlag::PixelShaderResource |
                BindFlag::NonPixelShaderResource);
        case Usage::PixelShaderResource:
            return BindFlag::PixelShaderResource;
        case Usage::NonPixelShaderResource:
            return BindFlag::NonPixelShaderResource;
        case Usage::GenericRead:
            return BindFlag::Enum(
                BindFlag::PixelShaderResource |
                BindFlag::NonPixelShaderResource);
        default:
            return BindFlag::Enum(-1);
        }
    }

    virtual SLANG_NO_THROW Type SLANG_MCALL getType() = 0;
};
#define SLANG_UUID_IResource                                                           \
    {                                                                                  \
        0xa0e39f34, 0x8398, 0x4522, { 0x95, 0xc2, 0xeb, 0xc0, 0xf9, 0x84, 0xef, 0x3f } \
    }

class IBufferResource: public IResource
{
public:
    struct Desc: public DescBase
    {
        void init(size_t sizeInBytesIn)
        {
            sizeInBytes = sizeInBytesIn;
            elementSize = 0;
            format = Format::Unknown;
        }
        void setDefaults(Usage initialUsage)
        {
            if (bindFlags == 0)
            {
                bindFlags = getDefaultBindFlagsFromUsage(initialUsage);
            }
        }
        size_t sizeInBytes;     ///< Total size in bytes
        int elementSize;        ///< Get the element stride. If > 0, this is a structured buffer
        Format format;
    };
    virtual SLANG_NO_THROW Desc* SLANG_MCALL getDesc() = 0;
};
#define SLANG_UUID_IBufferResource                                                     \
    {                                                                                  \
        0x1b274efe, 0x5e37, 0x492b, { 0x82, 0x6e, 0x7e, 0xe7, 0xe8, 0xf5, 0xa4, 0x9b } \
    }

template <typename T> T _slang_gfx_max(T v0, T v1) { return v0 > v1 ? v0 : v1; }

static inline unsigned int _slang_gfx_ones32(unsigned int x)
{
    /* 32-bit recursive reduction using SWAR...
            but first step is mapping 2-bit values
            into sum of 2 1-bit values in sneaky way
    */
    x -= ((x >> 1) & 0x55555555);
    x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
    x = (((x >> 4) + x) & 0x0f0f0f0f);
    x += (x >> 8);
    x += (x >> 16);
    return (x & 0x0000003f);
}

static inline unsigned int _slang_gfx_log2Floor(unsigned int x)
{
    x |= (x >> 1);
    x |= (x >> 2);
    x |= (x >> 4);
    x |= (x >> 8);
    x |= (x >> 16);
    return (_slang_gfx_ones32(x >> 1));
}

class ITextureResource: public IResource
{
public:
    struct SampleDesc
    {
        void init()
        {
            numSamples = 1;
            quality = 0;
        }
        int numSamples;                     ///< Number of samples per pixel
        int quality;                        ///< The quality measure for the samples
    };

    struct Size
    {
        void init()
        {
            width = height = depth = 1;
        }
        void init(int widthIn, int heightIn = 1, int depthIn = 1)
        {
            width = widthIn;
            height = heightIn;
            depth = depthIn;
        }
            /// Given the type works out the maximum dimension size
        int calcMaxDimension(Type type) const
        {
            switch (type)
            {
            case IResource::Type::Texture1D:
                return this->width;
            case IResource::Type::Texture3D:
                return _slang_gfx_max(_slang_gfx_max(this->width, this->height), this->depth);
            case IResource::Type::TextureCube: // fallthru
            case IResource::Type::Texture2D:
                {
                    return _slang_gfx_max(this->width, this->height);
                }
            default:
                return 0;
            }
        }

        SLANG_FORCE_INLINE static int calcMipSize(int width, int mipLevel)
        {
            width = width >> mipLevel;
            return width > 0 ? width : 1;
        }
            /// Given a size, calculates the size at a mip level
        Size calcMipSize(int mipLevel) const
        {
            Size size;
            size.width = calcMipSize(this->width, mipLevel);
            size.height = calcMipSize(this->height, mipLevel);
            size.depth = calcMipSize(this->depth, mipLevel);
            return size;
        }

        int width;              ///< Width in pixels
        int height;             ///< Height in pixels (if 2d or 3d)
        int depth;              ///< Depth (if 3d)
    };

    struct Desc: public DescBase
    {
            /// Initialize with default values
        void init(Type typeIn)
        {
            this->type = typeIn;
            this->size.init();

            this->format = Format::Unknown;
            this->arraySize = 0;
            this->numMipLevels = 0;
            this->sampleDesc.init();

            this->bindFlags = 0;
            this->cpuAccessFlags = 0;
        }
            /// Initialize different dimensions. For cubemap, use init2D
        void init1D(Format formatIn, int widthIn, int numMipMapsIn = 0)
        {
            this->type = Type::Texture1D;
            this->size.init(widthIn);

            this->format = formatIn;
            this->arraySize = 0;
            this->numMipLevels = numMipMapsIn;
            this->sampleDesc.init();

            this->bindFlags = 0;
            this->cpuAccessFlags = 0;
        }

        void init2D(Type typeIn, Format formatIn, int widthIn, int heightIn, int numMipMapsIn = 0)
        {
            assert(typeIn == Type::Texture2D || typeIn == Type::TextureCube);

            this->type = typeIn;
            this->size.init(widthIn, heightIn);

            this->format = formatIn;
            this->arraySize = 0;
            this->numMipLevels = numMipMapsIn;
            this->sampleDesc.init();

            this->bindFlags = 0;
            this->cpuAccessFlags = 0;
        }

        void init3D(Format formatIn, int widthIn, int heightIn, int depthIn, int numMipMapsIn = 0)
        {
            this->type = Type::Texture3D;
            this->size.init(widthIn, heightIn, depthIn);

            this->format = formatIn;
            this->arraySize = 0;
            this->numMipLevels = numMipMapsIn;
            this->sampleDesc.init();

            this->bindFlags = 0;
            this->cpuAccessFlags = 0;
        }

            /// Given the type, calculates the number of mip maps. 0 on error
        int calcNumMipLevels() const
        {
            const int maxDimensionSize = this->size.calcMaxDimension(type);
            return (maxDimensionSize > 0) ? (_slang_gfx_log2Floor(maxDimensionSize) + 1) : 0;
        }
            /// Calculate the total number of sub resources. 0 on error.
        int calcNumSubResources() const
        {
            const int numMipMaps =
                (this->numMipLevels > 0) ? this->numMipLevels : calcNumMipLevels();
            const int arrSize = (this->arraySize > 0) ? this->arraySize : 1;

            switch (type)
            {
            case IResource::Type::Texture1D:
            case IResource::Type::Texture2D:
                {
                    return numMipMaps * arrSize;
                }
            case IResource::Type::Texture3D:
                {
                    // can't have arrays of 3d textures
                    assert(this->arraySize <= 1);
                    return numMipMaps * this->size.depth;
                }
            case IResource::Type::TextureCube:
                {
                    // There are 6 faces to a cubemap
                    return numMipMaps * arrSize * 6;
                }
            default:
                return 0;
            }
        }

            /// Calculate the effective array size - in essence the amount if mip map sets needed.
            /// In practice takes into account if the arraySize is 0 (it's not an array, but it will still have at least one mip set)
            /// and if the type is a cubemap (multiplies the amount of mip sets by 6)
        int calcEffectiveArraySize() const
        {
            const int arrSize = (this->arraySize > 0) ? this->arraySize : 1;

            switch (type)
            {
            case IResource::Type::Texture1D: // fallthru
            case IResource::Type::Texture2D:
                {
                    return arrSize;
                }
            case IResource::Type::TextureCube:
                return arrSize * 6;
            case IResource::Type::Texture3D:
                return 1;
            default:
                return 0;
            }
        }

            /// Use type to fix the size values (and array size).
            /// For example a 1d texture, should have height and depth set to 1.
        void fixSize()
        {
            switch (type)
            {
            case IResource::Type::Texture1D:
                {
                    this->size.height = 1;
                    this->size.depth = 1;
                    break;
                }
            case IResource::Type::TextureCube:
            case IResource::Type::Texture2D:
                {
                    this->size.depth = 1;
                    break;
                }
            case IResource::Type::Texture3D:
                {
                    // Can't have an array
                    this->arraySize = 0;
                    break;
                }
            default:
                break;
            }
        }

            /// Set up default parameters based on type and usage
        void setDefaults(Usage initialUsage)
        {
            fixSize();
            if (this->bindFlags == 0)
            {
                this->bindFlags = getDefaultBindFlagsFromUsage(initialUsage);
            }
            if (this->numMipLevels <= 0)
            {
                this->numMipLevels = calcNumMipLevels();
            }
        }

        Size size;

        int arraySize;          ///< Array size

        int numMipLevels;       ///< Number of mip levels - if 0 will create all mip levels
        Format format;          ///< The resources format
        SampleDesc sampleDesc;  ///< How the resource is sampled
        float optimalClearValue[4] = {0.0f, 0.0f, 0.0f, 0.0f};
    };

        /// The ordering of the subResources is
        /// forall (effectiveArraySize)
        ///     forall (mip levels)
        ///         forall (depth levels)
    struct Data
    {
        ptrdiff_t* mipRowStrides;           ///< The row stride for a mip map
        int numMips;                        ///< The number of mip maps
        const void*const* subResources;     ///< Pointers to each full mip subResource
        int numSubResources;                ///< The total amount of subResources. Typically = numMips * depth * arraySize
    };

    virtual SLANG_NO_THROW Desc* SLANG_MCALL getDesc() = 0;
};
#define SLANG_UUID_ITextureResource                                                    \
    {                                                                                  \
        0xcf88a31c, 0x6187, 0x46c5, { 0xa4, 0xb7, 0xeb, 0x58, 0xc7, 0x33, 0x40, 0x17 } \
    } 

// Needed for building on cygwin with gcc
#undef Always
#undef None

enum class ComparisonFunc : uint8_t
{
    Never           = 0,
    Less            = 0x01,
    Equal           = 0x02,
    LessEqual       = 0x03,
    Greater         = 0x04,
    NotEqual        = 0x05,
    GreaterEqual    = 0x06,
    Always          = 0x07,
};

enum class TextureFilteringMode
{
    Point,
    Linear,
};

enum class TextureAddressingMode
{
    Wrap,
    ClampToEdge,
    ClampToBorder,
    MirrorRepeat,
    MirrorOnce,
};

enum class TextureReductionOp
{
    Average,
    Comparison,
    Minimum,
    Maximum,
};

class ISamplerState : public ISlangUnknown
{
public:
    struct Desc
    {
        TextureFilteringMode    minFilter       = TextureFilteringMode::Linear;
        TextureFilteringMode    magFilter       = TextureFilteringMode::Linear;
        TextureFilteringMode    mipFilter       = TextureFilteringMode::Linear;
        TextureReductionOp      reductionOp     = TextureReductionOp::Average;
        TextureAddressingMode   addressU        = TextureAddressingMode::Wrap;
        TextureAddressingMode   addressV        = TextureAddressingMode::Wrap;
        TextureAddressingMode   addressW        = TextureAddressingMode::Wrap;
        float                   mipLODBias      = 0.0f;
        uint32_t                maxAnisotropy   = 1;
        ComparisonFunc          comparisonFunc  = ComparisonFunc::Never;
        float                   borderColor[4]  = { 1.0f, 1.0f, 1.0f, 1.0f };
        float                   minLOD          = -FLT_MAX;
        float                   maxLOD          = FLT_MAX;
    };
};
#define SLANG_UUID_ISamplerState                                                        \
    {                                                                                  \
        0x8b8055df, 0x9377, 0x401d, { 0x91, 0xff, 0x3f, 0xa3, 0xbf, 0x66, 0x64, 0xf4 } \
    }


enum class DescriptorSlotType
{
    Unknown,

    Sampler,
    CombinedImageSampler,
    SampledImage,
    StorageImage,
    UniformTexelBuffer,
    StorageTexelBuffer,
    UniformBuffer,
    ReadOnlyStorageBuffer,
    StorageBuffer,
    DynamicUniformBuffer,
    DynamicStorageBuffer,
    InputAttachment,
    RootConstant,
    InlineUniformBlock,
    RayTracingAccelerationStructure,
};

class IDescriptorSetLayout : public ISlangUnknown
{
public:
    struct SlotRangeDesc
    {
        DescriptorSlotType  type            = DescriptorSlotType::Unknown;
        UInt                count           = 1;

            /// The underlying API-specific binding/register to use for this slot range.
            ///
            /// A value of `-1` indicates that the implementation should
            /// automatically compute the binding/register to use
            /// based on the preceeding slot range(s).
            ///
            /// Some implementations do not have a concept of bindings/regsiters
            /// for slot ranges, and will ignore this field.
            ///
        Int                 binding         = -1;

        SlotRangeDesc()
        {}

        SlotRangeDesc(
            DescriptorSlotType  type,
            UInt                count = 1)
            : type(type)
            , count(count)
        {}
    };

    struct Desc
    {
        UInt                    slotRangeCount  = 0;
        SlotRangeDesc const*    slotRanges      = nullptr;
    };
};
#define SLANG_UUID_IDescriptorSetLayout                                                 \
    {                                                                                  \
        0x9fe39a2f, 0xdf8b, 0x4690, { 0x90, 0x6a, 0x10, 0x1e, 0xed, 0xf9, 0xbe, 0xc0 } \
    }


class IPipelineLayout : public ISlangUnknown
{
public:
    struct DescriptorSetDesc
    {
        IDescriptorSetLayout*    layout          = nullptr;

            /// The underlying API-specific space/set number to use for this set.
            ///
            /// A value of `-1` indicates that the implementation should
            /// automatically compute the space/set to use basd on
            /// the preceeding set(s)
            ///
            /// Some implementations do not have a concept of space/set numbers
            /// for descriptor sets, and will ignore this field.
            ///
        Int                     space = -1;

        DescriptorSetDesc()
        {}

        DescriptorSetDesc(
            IDescriptorSetLayout*    layout)
            : layout(layout)
        {}
    };

    struct Desc
    {
        UInt                        renderTargetCount   = 0;
        UInt                        descriptorSetCount  = 0;
        DescriptorSetDesc const*    descriptorSets      = nullptr;
    };
};
#define SLANG_UUID_IPipelineLayout                                                      \
    {                                                                                  \
        0x9d644a9a, 0x3e6f, 0x4350, { 0xa3, 0x5a, 0xe8, 0xe3, 0xbc, 0xef, 0xb9, 0xcf } \
    }

class IResourceView : public ISlangUnknown
{
public:
    enum class Type
    {
        Unknown,

        RenderTarget,
        DepthStencil,
        ShaderResource,
        UnorderedAccess,
    };

    struct RenderTargetDesc
    {
        // The resource shape of this render target view.
        IResource::Type shape;
        uint32_t mipSlice;
        uint32_t arrayIndex;
        uint32_t arraySize;
        uint32_t planeIndex;
    };

    struct Desc
    {
        Type    type;
        Format  format;

        // Fields for `RenderTarget` and `DepthStencil` views.
        RenderTargetDesc renderTarget;
    };
};
#define SLANG_UUID_IResourceView                                                       \
    {                                                                                 \
        0x7b6c4926, 0x884, 0x408c, { 0xad, 0x8a, 0x50, 0x3a, 0x8e, 0x23, 0x98, 0xa4 } \
    }


class IDescriptorSet : public ISlangUnknown
{
public:
    struct Flag
    {
        enum Enum
        {
            None = 0,
            Transient = 1,
            Persistent = 2
        };
    };
    virtual SLANG_NO_THROW void SLANG_MCALL setConstantBuffer(UInt range, UInt index, IBufferResource* buffer) = 0;
    virtual SLANG_NO_THROW void SLANG_MCALL
        setResource(UInt range, UInt index, IResourceView* view) = 0;
    virtual SLANG_NO_THROW void SLANG_MCALL
        setSampler(UInt range, UInt index, ISamplerState* sampler) = 0;
    virtual SLANG_NO_THROW void SLANG_MCALL setCombinedTextureSampler(
        UInt range,
        UInt index,
        IResourceView*   textureView,
        ISamplerState*   sampler) = 0;
    virtual SLANG_NO_THROW void SLANG_MCALL
        setRootConstants(
        UInt range,
        UInt offset,
        UInt size,
        void const* data) = 0;
};
#define SLANG_UUID_IDescriptorSet                                                     \
    {                                                                                \
        0x29a881ea, 0xd7, 0x41d4, { 0xa3, 0x2d, 0x6c, 0x78, 0x4b, 0x79, 0xda, 0x2e } \
    }


struct ShaderOffset
{
    SlangInt uniformOffset = 0;
    SlangInt bindingRangeIndex = 0;
    SlangInt bindingArrayIndex = 0;
};

class IShaderObject : public ISlangUnknown
{
public:
    SLANG_NO_THROW ComPtr<IShaderObject> SLANG_MCALL getObject(ShaderOffset const& offset)
    {
        ComPtr<IShaderObject> object = nullptr;
        SLANG_RETURN_NULL_ON_FAIL(getObject(offset, object.writeRef()));
        return object;
    }

    virtual SLANG_NO_THROW slang::TypeLayoutReflection* SLANG_MCALL getElementTypeLayout() = 0;
    virtual SLANG_NO_THROW UInt SLANG_MCALL getEntryPointCount() = 0;

    ComPtr<IShaderObject> getEntryPoint(UInt index)
    {
        ComPtr<IShaderObject> entryPoint = nullptr;
        SLANG_RETURN_NULL_ON_FAIL(getEntryPoint(index, entryPoint.writeRef()));
        return entryPoint;
    }
    virtual SLANG_NO_THROW Result SLANG_MCALL
        getEntryPoint(UInt index, IShaderObject** entryPoint) = 0;
    virtual SLANG_NO_THROW Result SLANG_MCALL
        setData(ShaderOffset const& offset, void const* data, size_t size) = 0;
    virtual SLANG_NO_THROW Result SLANG_MCALL
        getObject(ShaderOffset const& offset, IShaderObject** object) = 0;
    virtual SLANG_NO_THROW Result SLANG_MCALL
        setObject(ShaderOffset const& offset, IShaderObject* object) = 0;
    virtual SLANG_NO_THROW Result SLANG_MCALL
        setResource(ShaderOffset const& offset, IResourceView* resourceView) = 0;
    virtual SLANG_NO_THROW Result SLANG_MCALL
        setSampler(ShaderOffset const& offset, ISamplerState* sampler) = 0;
    virtual SLANG_NO_THROW Result SLANG_MCALL setCombinedTextureSampler(
        ShaderOffset const& offset, IResourceView* textureView, ISamplerState* sampler) = 0;
};
#define SLANG_UUID_IShaderObject                                                       \
    {                                                                                 \
        0xc1fa997e, 0x5ca2, 0x45ae, { 0x9b, 0xcb, 0xc4, 0x35, 0x9e, 0x85, 0x5, 0x85 } \
    }


enum class StencilOp : uint8_t
{
    Keep,
    Zero,
    Replace,
    IncrementSaturate,
    DecrementSaturate,
    Invert,
    IncrementWrap,
    DecrementWrap,
};

enum class FillMode : uint8_t
{
    Solid,
    Wireframe,
};

enum class CullMode : uint8_t
{
    None,
    Front,
    Back,
};

enum class FrontFaceMode : uint8_t
{
    CounterClockwise,
    Clockwise,
};

struct DepthStencilOpDesc
{
    StencilOp       stencilFailOp       = StencilOp::Keep;
    StencilOp       stencilDepthFailOp  = StencilOp::Keep;
    StencilOp       stencilPassOp       = StencilOp::Keep;
    ComparisonFunc  stencilFunc         = ComparisonFunc::Always;
    uint32_t        stencilCompareMask  = 0xFFFFFFFF;
    uint32_t        stencilWriteMask    = 0xFFFFFFFF;
    uint32_t        stencilReference    = 0;
};

struct DepthStencilDesc
{
    bool            depthTestEnable     = true;
    bool            depthWriteEnable    = true;
    ComparisonFunc  depthFunc           = ComparisonFunc::Less;

    bool                stencilEnable       = false;
    uint32_t            stencilReadMask     = 0xFFFFFFFF;
    uint32_t            stencilWriteMask    = 0xFFFFFFFF;
    DepthStencilOpDesc  frontFace;
    DepthStencilOpDesc  backFace;

    uint32_t stencilRef = 0;
};

struct RasterizerDesc
{
    FillMode        fillMode                = FillMode::Solid;
    CullMode        cullMode                = CullMode::Back;
    FrontFaceMode   frontFace               = FrontFaceMode::CounterClockwise;
    int32_t         depthBias               = 0;
    float           depthBiasClamp          = 0.0f;
    float           slopeScaledDepthBias    = 0.0f;
    bool            depthClipEnable         = true;
    bool            scissorEnable           = false;
    bool            multisampleEnable       = false;
    bool            antialiasedLineEnable   = false;
};

enum class LogicOp
{
    NoOp,
};

enum class BlendOp
{
    Add,
    Subtract,
    ReverseSubtract,
    Min,
    Max,
};

enum class BlendFactor
{
    Zero,
    One,
    SrcColor,
    InvSrcColor,
    SrcAlpha,
    InvSrcAlpha,
    DestAlpha,
    InvDestAlpha,
    DestColor,
    InvDestColor,
    SrcAlphaSaturate,
    BlendColor,
    InvBlendColor,
    SecondarySrcColor,
    InvSecondarySrcColor,
    SecondarySrcAlpha,
    InvSecondarySrcAlpha,
};

namespace RenderTargetWriteMask
{
    typedef uint8_t Type;
    enum
    {
        EnableNone  = 0,
        EnableRed   = 0x01,
        EnableGreen = 0x02,
        EnableBlue  = 0x04,
        EnableAlpha = 0x08,
        EnableAll   = 0x0F,
    };
};
typedef RenderTargetWriteMask::Type RenderTargetWriteMaskT;

struct AspectBlendDesc
{
    BlendFactor     srcFactor   = BlendFactor::One;
    BlendFactor     dstFactor   = BlendFactor::Zero;
    BlendOp         op          = BlendOp::Add;
};

struct TargetBlendDesc
{
    AspectBlendDesc color;
    AspectBlendDesc alpha;

    LogicOp                 logicOp     = LogicOp::NoOp;
    RenderTargetWriteMaskT  writeMask   = RenderTargetWriteMask::EnableAll;
};

struct BlendDesc
{
    TargetBlendDesc const*  targets     = nullptr;
    UInt                    targetCount = 0;

    bool alphaToCoverateEnable  = false;
};

class IFramebufferLayout : public ISlangUnknown
{
public:
    struct AttachmentLayout
    {
        Format format;
        int sampleCount;
    };
    struct Desc
    {
        uint32_t renderTargetCount;
        AttachmentLayout* renderTargets;
        AttachmentLayout* depthStencil;
    };
};
#define SLANG_UUID_IFramebufferLayout                                                \
    {                                                                                \
        0xa838785, 0xc13a, 0x4832, { 0xad, 0x88, 0x64, 0x6, 0xb5, 0x4b, 0x5e, 0xba } \
    }

struct GraphicsPipelineStateDesc
{
    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;

    IInputLayout*       inputLayout;
    IFramebufferLayout* framebufferLayout;
    DepthStencilDesc    depthStencil;
    RasterizerDesc      rasterizer;
    BlendDesc           blend;
};

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;
};

class IPipelineState : public ISlangUnknown
{
};
#define SLANG_UUID_IPipelineState                                                      \
    {                                                                                 \
        0xca7e57d, 0x8a90, 0x44f3, { 0xbd, 0xb1, 0xfe, 0x9b, 0x35, 0x3f, 0x5a, 0x72 } \
    }


struct ScissorRect
{
    Int minX;
    Int minY;
    Int maxX;
    Int maxY;
};

struct Viewport
{
    float originX = 0.0f;
    float originY = 0.0f;
    float extentX = 0.0f;
    float extentY = 0.0f;
    float minZ    = 0.0f;
    float maxZ    = 1.0f;
};

class IFramebuffer : public ISlangUnknown
{
public:
    struct Desc
    {
        uint32_t renderTargetCount;
        IResourceView* const* renderTargetViews;
        IResourceView* depthStencilView;
        IFramebufferLayout* layout;
    };
};
#define SLANG_UUID_IFrameBuffer                                                       \
    {                                                                                 \
        0xf0c0d9a, 0x4ef3, 0x4e18, { 0x9b, 0xa9, 0x34, 0x60, 0xea, 0x69, 0x87, 0x95 } \
    }

class ISwapchain : public ISlangUnknown
{
public:
    struct Desc
    {
        Format format;
        uint32_t width, height;
        uint32_t imageCount;
        bool enableVSync;
    };
    virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() = 0;
    virtual SLANG_NO_THROW Result getImage(uint32_t index, ITextureResource** outResource) = 0;
    virtual SLANG_NO_THROW Result present() = 0;
    virtual SLANG_NO_THROW uint32_t acquireNextImage() = 0;
};
#define SLANG_UUID_ISwapchain                                                         \
    {                                                                                 \
        0xbe91ba6c, 0x784, 0x4308, { 0xa1, 0x0, 0x19, 0xc3, 0x66, 0x83, 0x44, 0xb2 }  \
    }

struct WindowHandle
{
    enum class Type
    {
        Unknown,
        Win32Handle,
        XLibHandle,
    };
    Type type;
    intptr_t handleValues[2];
    static WindowHandle FromHwnd(void* hwnd)
    {
        WindowHandle handle = {};
        handle.type = WindowHandle::Type::Win32Handle;
        handle.handleValues[0] = (intptr_t)(hwnd);
        return handle;
    }
    static WindowHandle FromXWindow(void* xdisplay, uint32_t xwindow)
    {
        WindowHandle handle = {};
        handle.type = WindowHandle::Type::XLibHandle;
        handle.handleValues[0] = (intptr_t)(xdisplay);
        handle.handleValues[1] = xwindow;
        return handle;
    }
};

class IRenderer: public ISlangUnknown
{
public:
    struct SlangDesc
    {
        slang::IGlobalSession* slangGlobalSession = nullptr; // (optional) A slang global session object. If null will create automatically.

        SlangMatrixLayoutMode defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_ROW_MAJOR;

        char const* const* searchPaths = nullptr;
        SlangInt            searchPathCount = 0;

        slang::PreprocessorMacroDesc const* preprocessorMacros = nullptr;
        SlangInt                        preprocessorMacroCount = 0;

        const char* targetProfile = nullptr; // (optional) Target shader profile. If null this will be set to platform dependent default.
        SlangFloatingPointMode floatingPointMode = SLANG_FLOATING_POINT_MODE_DEFAULT;
        SlangOptimizationLevel optimizationLevel = SLANG_OPTIMIZATION_LEVEL_DEFAULT;
    };

    struct Desc
    {
        RendererType rendererType; // The underlying API/Platform of the renderer.
        const char* adapter = nullptr;                  // Name to identify the adapter to use
        int requiredFeatureCount = 0;                   // Number of required features.
        const char** requiredFeatures = nullptr;        // Array of required feature names, whose size is `requiredFeatureCount`.
        int nvapiExtnSlot = -1;                         // The slot (typically UAV) used to identify NVAPI intrinsics. If >=0 NVAPI is required.
        ISlangFileSystem* shaderCacheFileSystem = nullptr; // The file system for loading cached shader kernels.
        SlangDesc slang = {};                           // Configurations for Slang.
    };

    virtual SLANG_NO_THROW bool SLANG_MCALL hasFeature(const char* feature) = 0;

        /// Returns a list of features supported by the renderer.
    virtual SLANG_NO_THROW Result SLANG_MCALL getFeatures(const char** outFeatures, UInt bufferSize, UInt* outFeatureCount) = 0;

    virtual SLANG_NO_THROW Result SLANG_MCALL getSlangSession(slang::ISession** outSlangSession) = 0;

    inline ComPtr<slang::ISession> getSlangSession()
    {
        ComPtr<slang::ISession> result;
        getSlangSession(result.writeRef());
        return result;
    }

    virtual SLANG_NO_THROW void SLANG_MCALL setClearColor(const float color[4]) = 0;
    virtual SLANG_NO_THROW void SLANG_MCALL clearFrame() = 0;
    virtual SLANG_NO_THROW void SLANG_MCALL beginFrame() = 0;
    virtual SLANG_NO_THROW void SLANG_MCALL
        makeSwapchainImagePresentable(ISwapchain* swapchain) = 0;
    virtual SLANG_NO_THROW void SLANG_MCALL endFrame() = 0;

        /// Create a texture resource. initData holds the initialize data to set the contents of the texture when constructed.
    virtual SLANG_NO_THROW Result SLANG_MCALL createTextureResource(
        IResource::Usage initialUsage,
        const ITextureResource::Desc& desc,
        const ITextureResource::Data* initData,
        ITextureResource** outResource) = 0;

        /// Create a texture resource. initData holds the initialize data to set the contents of the texture when constructed.
    inline SLANG_NO_THROW ComPtr<ITextureResource> createTextureResource(
        IResource::Usage initialUsage,
        const ITextureResource::Desc& desc,
        const ITextureResource::Data* initData = nullptr)
    {
        ComPtr<ITextureResource> resource;
        SLANG_RETURN_NULL_ON_FAIL(createTextureResource(initialUsage, desc, initData, resource.writeRef()));
        return resource;
    }

        /// Create a buffer resource
    virtual SLANG_NO_THROW Result SLANG_MCALL createBufferResource(
        IResource::Usage initialUsage,
        const IBufferResource::Desc& desc,
        const void* initData,
        IBufferResource** outResource) = 0;

    inline SLANG_NO_THROW ComPtr<IBufferResource> createBufferResource(
        IResource::Usage initialUsage,
        const IBufferResource::Desc& desc,
        const void* initData = nullptr)
    {
        ComPtr<IBufferResource> resource;
        SLANG_RETURN_NULL_ON_FAIL(createBufferResource(initialUsage, desc, initData, resource.writeRef()));
        return resource;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL
        createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler) = 0;

    inline ComPtr<ISamplerState> createSamplerState(ISamplerState::Desc const& desc)
    {
        ComPtr<ISamplerState> sampler;
        SLANG_RETURN_NULL_ON_FAIL(createSamplerState(desc, sampler.writeRef()));
        return sampler;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL createTextureView(
        ITextureResource* texture, IResourceView::Desc const& desc, IResourceView** outView) = 0;

    inline ComPtr<IResourceView> createTextureView(ITextureResource* texture, IResourceView::Desc const& desc)
    {
        ComPtr<IResourceView> view;
        SLANG_RETURN_NULL_ON_FAIL(createTextureView(texture, desc, view.writeRef()));
        return view;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL createBufferView(
        IBufferResource* buffer, IResourceView::Desc const& desc, IResourceView** outView) = 0;

    inline ComPtr<IResourceView> createBufferView(IBufferResource* buffer, IResourceView::Desc const& desc)
    {
        ComPtr<IResourceView> view;
        SLANG_RETURN_NULL_ON_FAIL(createBufferView(buffer, desc, view.writeRef()));
        return view;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL
        createFramebufferLayout(IFramebufferLayout::Desc const& desc, IFramebufferLayout** outFrameBuffer) = 0;
    inline ComPtr<IFramebufferLayout> createFramebufferLayout(IFramebufferLayout::Desc const& desc)
    {
        ComPtr<IFramebufferLayout> fb;
        SLANG_RETURN_NULL_ON_FAIL(createFramebufferLayout(desc, fb.writeRef()));
        return fb;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL
        createFramebuffer(IFramebuffer::Desc const& desc, IFramebuffer** outFrameBuffer) = 0;
    inline ComPtr<IFramebuffer> createFramebuffer(IFramebuffer::Desc const& desc)
    {
        ComPtr<IFramebuffer> fb;
        SLANG_RETURN_NULL_ON_FAIL(createFramebuffer(desc, fb.writeRef()));
        return fb;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL createSwapchain(
        ISwapchain::Desc const& desc, WindowHandle window, ISwapchain** outSwapchain) = 0;
    inline ComPtr<ISwapchain> createSwapchain(ISwapchain::Desc const& desc, WindowHandle window)
    {
        ComPtr<ISwapchain> swapchain;
        SLANG_RETURN_NULL_ON_FAIL(createSwapchain(desc, window, swapchain.writeRef()));
        return swapchain;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL createInputLayout(
        const InputElementDesc* inputElements, UInt inputElementCount, IInputLayout** outLayout) = 0;

    inline ComPtr<IInputLayout> createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount)
    {
        ComPtr<IInputLayout> layout;
        SLANG_RETURN_NULL_ON_FAIL(createInputLayout(inputElements, inputElementCount, layout.writeRef()));
        return layout;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL createDescriptorSetLayout(
        const IDescriptorSetLayout::Desc& desc, IDescriptorSetLayout** outLayout) = 0;

    inline ComPtr<IDescriptorSetLayout> createDescriptorSetLayout(const IDescriptorSetLayout::Desc& desc)
    {
        ComPtr<IDescriptorSetLayout> layout;
        SLANG_RETURN_NULL_ON_FAIL(createDescriptorSetLayout(desc, layout.writeRef()));
        return layout;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL createShaderObject(slang::TypeReflection* type, IShaderObject** outObject) = 0;

    inline ComPtr<IShaderObject> createShaderObject(slang::TypeReflection* type)
    {
        ComPtr<IShaderObject> object;
        SLANG_RETURN_NULL_ON_FAIL(createShaderObject(type, object.writeRef()));
        return object;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL createRootShaderObject(IShaderProgram* program, IShaderObject** outObject) = 0;

    inline ComPtr<IShaderObject> createRootShaderObject(IShaderProgram* program)
    {
        ComPtr<IShaderObject> object;
        SLANG_RETURN_NULL_ON_FAIL(createRootShaderObject(program, object.writeRef()));
        return object;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL bindRootShaderObject(PipelineType pipelineType, IShaderObject* object) = 0;

    virtual SLANG_NO_THROW Result SLANG_MCALL createPipelineLayout(const IPipelineLayout::Desc& desc, IPipelineLayout** outLayout) = 0;

    inline ComPtr<IPipelineLayout> createPipelineLayout(const IPipelineLayout::Desc& desc)
    {
        ComPtr<IPipelineLayout> layout;
        SLANG_RETURN_NULL_ON_FAIL(createPipelineLayout(desc, layout.writeRef()));
        return layout;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet::Flag::Enum flag, IDescriptorSet** outDescriptorSet) = 0;

    inline ComPtr<IDescriptorSet> createDescriptorSet(IDescriptorSetLayout* layout, IDescriptorSet::Flag::Enum flag)
    {
        ComPtr<IDescriptorSet> descriptorSet;
        SLANG_RETURN_NULL_ON_FAIL(createDescriptorSet(layout, flag, descriptorSet.writeRef()));
        return descriptorSet;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL createProgram(const IShaderProgram::Desc& desc, IShaderProgram** outProgram) = 0;

    inline ComPtr<IShaderProgram> createProgram(const IShaderProgram::Desc& desc)
    {
        ComPtr<IShaderProgram> program;
        SLANG_RETURN_NULL_ON_FAIL(createProgram(desc, program.writeRef()));
        return program;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL createGraphicsPipelineState(
        const GraphicsPipelineStateDesc&    desc,
        IPipelineState**                    outState) = 0;

    inline ComPtr<IPipelineState> createGraphicsPipelineState(
        const GraphicsPipelineStateDesc& desc)
    {
        ComPtr<IPipelineState> state;
        SLANG_RETURN_NULL_ON_FAIL(createGraphicsPipelineState(desc, state.writeRef()));
        return state;
    }

    virtual SLANG_NO_THROW Result SLANG_MCALL createComputePipelineState(
        const ComputePipelineStateDesc&    desc,
        IPipelineState**                     outState) = 0;

    inline ComPtr<IPipelineState> createComputePipelineState(
        const ComputePipelineStateDesc& desc)
    {
        ComPtr<IPipelineState> state;
        SLANG_RETURN_NULL_ON_FAIL(createComputePipelineState(desc, state.writeRef()));
        return state;
    }

        /// Read back texture resource and stores the result in `outBlob`.
    virtual SLANG_NO_THROW SlangResult SLANG_MCALL readTextureResource(
        ITextureResource* resource,
        ISlangBlob** outBlob,
        size_t* outRowPitch,
        size_t* outPixelSize) = 0;

    virtual SLANG_NO_THROW void* SLANG_MCALL map(IBufferResource* buffer, MapFlavor flavor) = 0;
    virtual SLANG_NO_THROW void SLANG_MCALL unmap(IBufferResource* buffer) = 0;

    virtual SLANG_NO_THROW void SLANG_MCALL setPrimitiveTopology(PrimitiveTopology topology) = 0;

    virtual SLANG_NO_THROW void SLANG_MCALL setDescriptorSet(
        PipelineType pipelineType,
        IPipelineLayout* layout,
        UInt index,
        IDescriptorSet* descriptorSet) = 0;

    virtual SLANG_NO_THROW void SLANG_MCALL setVertexBuffers(
        UInt startSlot,
        UInt slotCount,
        IBufferResource* const* buffers,
        const UInt* strides,
        const UInt* offsets) = 0;
    inline void setVertexBuffer(UInt slot, IBufferResource* buffer, UInt stride, UInt offset = 0);

    virtual SLANG_NO_THROW void SLANG_MCALL
        setIndexBuffer(IBufferResource* buffer, Format indexFormat, UInt offset = 0) = 0;

    virtual SLANG_NO_THROW void SLANG_MCALL setViewports(UInt count, Viewport const* viewports) = 0;
    inline void setViewport(Viewport const& viewport)
    {
        setViewports(1, &viewport);
    }

    virtual SLANG_NO_THROW void SLANG_MCALL setScissorRects(UInt count, ScissorRect const* rects) = 0;
    inline void setScissorRect(ScissorRect const& rect)
    {
        setScissorRects(1, &rect);
    }
    /// Sets the viewport, and sets the scissor rect to match the viewport.
    inline void setViewportAndScissor(Viewport const& viewport)
    {
        setViewports(1, &viewport);
        ScissorRect rect = {};
        rect.maxX = static_cast<gfx::Int>(viewport.extentX);
        rect.maxY = static_cast<gfx::Int>(viewport.extentY);
        setScissorRects(1, &rect);
    }
    virtual SLANG_NO_THROW void SLANG_MCALL setPipelineState(IPipelineState* state) = 0;
    virtual SLANG_NO_THROW void SLANG_MCALL setFramebuffer(IFramebuffer* framebuffer) = 0;

    virtual SLANG_NO_THROW void SLANG_MCALL draw(UInt vertexCount, UInt startVertex = 0) = 0;
    virtual SLANG_NO_THROW void SLANG_MCALL drawIndexed(UInt indexCount, UInt startIndex = 0, UInt baseVertex = 0) = 0;

    virtual SLANG_NO_THROW void SLANG_MCALL dispatchCompute(int x, int y, int z) = 0;

        /// Commit any buffered state changes or draw calls.
        /// presentFrame will commitAll implicitly before doing a present
    virtual SLANG_NO_THROW void SLANG_MCALL submitGpuWork() = 0;
        /// Blocks until Gpu work is complete
    virtual SLANG_NO_THROW void SLANG_MCALL waitForGpu() = 0;

        /// Get the type of this renderer
    virtual SLANG_NO_THROW RendererType SLANG_MCALL getRendererType() const = 0;
};

#define SLANG_UUID_IRenderer                                                             \
    {                                                                                    \
          0x715bdf26, 0x5135, 0x11eb, { 0xAE, 0x93, 0x02, 0x42, 0xAC, 0x13, 0x00, 0x02 } \
    }

// ----------------------------------------------------------------------------------------
inline void IRenderer::setVertexBuffer(UInt slot, IBufferResource* buffer, UInt stride, UInt offset)
{
    setVertexBuffers(slot, 1, &buffer, &stride, &offset);
}

// Global public functions

extern "C"
{
    /// Gets the size in bytes of a Format type. Returns 0 if a size is not defined/invalid
    SLANG_GFX_API size_t SLANG_MCALL gfxGetFormatSize(Format format);

    /// Gets the binding style from the type
    SLANG_GFX_API BindingStyle SLANG_MCALL gfxGetBindingStyle(RendererType type);

    /// Given a renderer type, gets a projection style
    SLANG_GFX_API ProjectionStyle SLANG_MCALL gfxGetProjectionStyle(RendererType type);

    /// Given the projection style returns an 'identity' matrix, which ensures x,y mapping to pixels
    /// is the same on all targets
    SLANG_GFX_API void SLANG_MCALL
        gfxGetIdentityProjection(ProjectionStyle style, float projMatrix[16]);

    /// Get the name of the renderer
    SLANG_GFX_API const char* SLANG_MCALL gfxGetRendererName(RendererType type);

    /// Given a type returns a function that can construct it, or nullptr if there isn't one
    SLANG_GFX_API SlangResult SLANG_MCALL gfxCreateRenderer(const IRenderer::Desc* desc, IRenderer** outRenderer);
}

}// renderer_test
back to top