shadercross

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 5, 2026 License: MIT Imports: 6 Imported by: 0

README

shadercross

These are bindings to the SDL_shadercross library. It allows you to compile HLSL code to shader formats of different platforms (DXBC, DXIL, SPIRV, MSL), allowing you to target DirectX, Metal, Vulkan with a single shader language (HLSL).

You can statically compile your HLSL code to all formats when releasing your game, using the shadercross binary. But doing so, every time you make a change to your HLSL code might slow you down during development.

So this is where using it as a library can make sense, as it is giving you much more runtime control, allowing features such as hot-reloading shader while your program is running.

Requirements

For these bindings to work, you will need a few dependencies that differ based on your platform.

You can either follow the build/installation guidelines from https://github.com/libsdl-org/SDL_shadercross or you can directly go to their github actions and download the artifacts of your system, containing all the required libraries.

Usage

package main

import (
	"fmt"
	"log"

	"github.com/Zyko0/go-sdl3/bin/binsdl"
	"github.com/Zyko0/go-sdl3/shadercross"
)

var (
	shaderSrc = `
cbuffer UBO : register(b0, space3)
{
    int mode : packoffset(c0);
};

Texture2D<float4> Texture : register(t0, space2);

float4 main(float2 TexCoord : TEXCOORD0) : SV_Target0
{
    float w, h;
    Texture.GetDimensions(w, h);
    int2 texelPos = int2(float2(w, h) * TexCoord);
    float4 mainTexel = Texture[texelPos];
    if (mode == 0)
    {
        return mainTexel;
    }
    else
    {
        float4 bottomTexel = Texture[texelPos + int2(0, 1)];
        float4 leftTexel = Texture[texelPos + int2(-1, 0)];
        float4 topTexel = Texture[texelPos + int2(0, -1)];
        float4 rightTexel = Texture[texelPos + int2(1, 0)];
        return ((((mainTexel * 0.2f) + (bottomTexel * 0.2f)) + (leftTexel * 0.20000000298023223876953125f)) + (topTexel * 0.20000000298023223876953125f)) + (rightTexel * 0.2f);
    }
}
`
)

func main() {
	defer binsdl.Load().Unload()

	err := shadercross.LoadLibrary(shadercross.Path())
	if err != nil {
		log.Fatal("couldn't load shadercross library: ", err)
	}
	defer shadercross.CloseLibrary()

	spirv, err := shadercross.CompileSPIRVFromHLSL(&shadercross.HLSLInfo{
		Source:      shaderSrc,
		Entrypoint:  "main",
		ShaderStage: shadercross.SHADERSTAGE_FRAGMENT,
	})
	if err != nil {
		log.Fatal("couldn't get HLSL shader formats:", err)
	}
	fmt.Println("SPIR-V bytes count:", len(spirv))

	spirvInfo := &shadercross.SPIRVInfo{
		Bytecode:    spirv,
		Entrypoint:  "main",
		ShaderStage: shadercross.SHADERSTAGE_FRAGMENT,
	}

	msl, err := shadercross.TranspileMSLFromSPIRV(spirvInfo)
	if err != nil {
		log.Fatal("couldn't transpile MSL from SPIR-V:", err)
	}
	fmt.Println("MSL from SPIR-V:", string(msl))

	hlsl, err := shadercross.TranspileHLSLFromSPIRV(spirvInfo)
	if err != nil {
		log.Fatal("couldn't transpile HLSL from SPIR-V:", err)
	}
	fmt.Println("HLSL from SPIR-V:", string(hlsl))
}

Outputs:

MSL (from SPIR-V)
#include <metal_stdlib>
#include <simd/simd.h>

using namespace metal;

struct type_UBO
{
    int mode;
};

struct main0_out
{
    float4 out_var_SV_Target0 [[color(0)]];
};

struct main0_in
{
    float2 in_var_TEXCOORD0 [[user(locn0)]];
};

fragment main0_out main0(main0_in in [[stage_in]], constant type_UBO& UBO [[buffer(0)]], texture2d<float> Texture [[texture(0)]])
{
    main0_out out = {};
    float4 _79;
    do
    {
        uint2 _37 = uint2(Texture.get_width(), Texture.get_height());
        int2 _44 = int2(float2(float(_37.x), float(_37.y)) * in.in_var_TEXCOORD0);
        float4 _47 = Texture.read(uint2(uint2(_44)), 0u);
        if (UBO.mode == 0)
        {
            _79 = _47;
            break;
        }
        else
        {
            _79 = ((((_47 * 0.20000000298023223876953125) + (Texture.read(uint2(uint2(_44 + int2(0, 1))), 0u) * 0.20000000298023223876953125)) + (Texture.read(uint2(uint2(_44 + int2(-1, 0))), 0u) * 0.20000000298023223876953125)) + (Texture.read(uint2(uint2(_44 + int2(0, -1))), 0u) * 0.20000000298023223876953125)) + (Texture.read(uint2(uint2(_44 + int2(1, 0))), 0u) * 0.20000000298023223876953125);
            break;
        }
        break; // unreachable workaround
    } while(false);
    out.out_var_SV_Target0 = _79;
    return out;
}
HLSL (from SPIR-V)
cbuffer type_UBO : register(b0, space3)
{
    int UBO_mode : packoffset(c0);
};

Texture2D<float4> Texture : register(t0, space2);

static float2 in_var_TEXCOORD0;
static float4 out_var_SV_Target0;

struct SPIRV_Cross_Input
{
    float2 in_var_TEXCOORD0 : TEXCOORD0;
};

struct SPIRV_Cross_Output
{
    float4 out_var_SV_Target0 : SV_Target0;
};

uint2 spvTextureSize(Texture2D<float4> Tex, uint Level, out uint Param)
{
    uint2 ret;
    Tex.GetDimensions(Level, ret.x, ret.y, Param);
    return ret;
}

void main_inner()
{
    float4 _79;
    do
    {
        uint _37_dummy_parameter;
        uint2 _37 = spvTextureSize(Texture, uint(0), _37_dummy_parameter);
        int2 _44 = int2(float2(float(_37.x), float(_37.y)) * in_var_TEXCOORD0);
        float4 _47 = Texture.Load(int3(uint2(_44), 0u));
        if (UBO_mode == 0)
        {
            _79 = _47;
            break;
        }
        else
        {
            _79 = ((((_47 * 0.20000000298023223876953125f) + (Texture.Load(int3(uint2(_44 + int2(0, 1)), 0u)) * 0.20000000298023223876953125f)) + (Texture.Load(int3(uint2(_44 + int2(-1, 0)), 0u)) * 0.20000000298023223876953125f)) + (Texture.Load(int3(uint2(_44 + int2(0, -1)), 0u)) * 0.20000000298023223876953125f)) + (Texture.Load(int3(uint2(_44 + int2(1, 0)), 0u)) * 0.20000000298023223876953125f);
            break;
        }
        break; // unreachable workaround
    } while(false);
    out_var_SV_Target0 = _79;
}

SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
    in_var_TEXCOORD0 = stage_input.in_var_TEXCOORD0;
    main_inner();
    SPIRV_Cross_Output stage_output;
    stage_output.out_var_SV_Target0 = out_var_SV_Target0;
    return stage_output;
}

Documentation

Index

Constants

View Source
const (
	PROP_SHADER_DEBUG_ENABLE_BOOLEAN         = "SDL_shadercross.spirv.debug.enable"
	PROP_SHADER_DEBUG_NAME_STRING            = "SDL_shadercross.spirv.debug.name"
	PROP_SHADER_CULL_UNUSED_BINDINGS_BOOLEAN = "SDL_shadercross.spirv.cull_unused_bindings"
	PROP_SPIRV_PSSL_COMPATIBILITY_BOOLEAN    = "SDL_shadercross.spirv.pssl.compatibility"
	PROP_SPIRV_MSL_VERSION_STRING            = "SDL_shadercross.spirv.msl.version"
)

Variables

This section is empty.

Functions

func CloseLibrary

func CloseLibrary() error

CloseLibrary releases resources associated with the library.

func CompileComputePipelineFromSPIRV

func CompileComputePipelineFromSPIRV(device *sdl.GPUDevice, info *SPIRVInfo, metadata *ComputePipelineMetadata, props sdl.PropertiesID) (*sdl.GPUComputePipeline, error)

func CompileDXBCFromHLSL

func CompileDXBCFromHLSL(info *HLSLInfo) ([]byte, error)

func CompileDXBCFromSPIRV

func CompileDXBCFromSPIRV(info *SPIRVInfo) ([]byte, error)

func CompileDXILFromHLSL

func CompileDXILFromHLSL(info *HLSLInfo) ([]byte, error)

func CompileDXILFromSPIRV

func CompileDXILFromSPIRV(info *SPIRVInfo) ([]byte, error)

func CompileGraphicsShaderFromSPIRV

func CompileGraphicsShaderFromSPIRV(device *sdl.GPUDevice, info *SPIRVInfo, resourceInfo *GraphicsShaderResourceInfo, props sdl.PropertiesID) (*sdl.GPUShader, error)

func CompileSPIRVFromHLSL

func CompileSPIRVFromHLSL(info *HLSLInfo) ([]byte, error)

func GetHLSLShaderFormats

func GetHLSLShaderFormats() (sdl.GPUShaderFormat, error)

func GetSPIRVShaderFormats

func GetSPIRVShaderFormats() (sdl.GPUShaderFormat, error)

func Init

func Init() error

func LoadLibrary

func LoadLibrary(path string) error

LoadLibrary loads SDL_shadercross library and initializes all functions.

func Path

func Path() string

Path returns the library installation path based on the operating system

func Quit

func Quit()

func TranspileHLSLFromSPIRV

func TranspileHLSLFromSPIRV(info *SPIRVInfo) (string, error)

func TranspileMSLFromSPIRV

func TranspileMSLFromSPIRV(info *SPIRVInfo) (string, error)

Types

type ComputePipelineMetadata

type ComputePipelineMetadata struct {
	NumSamplers                 uint32 /**< The number of samplers defined in the shader. */
	NumReadonlyStorageTextures  uint32 /**< The number of readonly storage textures defined in the shader. */
	NumReadonlyStorageBuffers   uint32 /**< The number of readonly storage buffers defined in the shader. */
	NumReadwriteStorageTextures uint32 /**< The number of read-write storage textures defined in the shader. */
	NumReadwriteStorageBuffers  uint32 /**< The number of read-write storage buffers defined in the shader. */
	NumUniformBuffers           uint32 /**< The number of uniform buffers defined in the shader. */
	ThreadcountX                uint32 /**< The number of threads in the X dimension. */
	ThreadcountY                uint32 /**< The number of threads in the Y dimension. */
	ThreadcountZ                uint32 /**< The number of threads in the Z dimension. */
}

func ReflectComputeSPIRV

func ReflectComputeSPIRV(bytecode []byte, props sdl.PropertiesID) (*ComputePipelineMetadata, error)

type GraphicsShaderMetadata

type GraphicsShaderMetadata struct {
	ResourceInfo *GraphicsShaderResourceInfo /**< Sub-struct containing the resource info of the shader. */
	Inputs       []IOVarMetadata             /**< The inputs defined in the shader. */
	Outputs      []IOVarMetadata             /**< The outputs defined in the shader. */
}

func ReflectGraphicsSPIRV

func ReflectGraphicsSPIRV(bytecode []byte, props sdl.PropertiesID) (*GraphicsShaderMetadata, error)

type GraphicsShaderResourceInfo

type GraphicsShaderResourceInfo struct {
	NumSamplers        uint32 /**< The number of samplers defined in the shader. */
	NumStorageTextures uint32 /**< The number of storage textures defined in the shader. */
	NumStorageBuffers  uint32 /**< The number of storage buffers defined in the shader. */
	NumUniformBuffers  uint32 /**< The number of uniform buffers defined in the shader. */
}

type HLSLDefine

type HLSLDefine struct {
	Name  string /**< The define name. */
	Value string /**< An optional value for the define. Can be NULL. */
}

type HLSLInfo

type HLSLInfo struct {
	Source      string       /**< The HLSL source code for the shader. */
	Entrypoint  string       /**< The entry point function name for the shader in UTF-8. */
	IncludeDir  string       /**< The include directory for shader code. Optional, can be NULL. */
	Defines     []HLSLDefine /**< An array of defines. Optional, can be NULL. If not NULL, must be terminated with a fully NULL define struct. */
	ShaderStage ShaderStage  /**< The shader stage to compile the shader with. */

	Props sdl.PropertiesID /**< A properties ID for extensions. Should be 0 if no extensions are needed. */
}

type IOVarMetadata

type IOVarMetadata struct {
	Name       string    /**< The UTF-8 name of the variable. */
	Location   uint32    /**< The location of the variable. */
	VectorType IOVarType /**< The vector type of the variable. */
	VectorSize uint32    /**< The number of components in the vector type of the variable. */
}

type IOVarType

type IOVarType int32
const (
	IOVAR_TYPE_UNKNOWN IOVarType = iota
	IOVAR_TYPE_INT8
	IOVAR_TYPE_UINT8
	IOVAR_TYPE_INT16
	IOVAR_TYPE_UINT16
	IOVAR_TYPE_INT32
	IOVAR_TYPE_UINT32
	IOVAR_TYPE_INT64
	IOVAR_TYPE_UINT64
	IOVAR_TYPE_FLOAT16
	IOVAR_TYPE_FLOAT32
	IOVAR_TYPE_FLOAT64
)

type SPIRVInfo

type SPIRVInfo struct {
	Bytecode    []byte      /**< The SPIRV bytecode. */
	Entrypoint  string      /**< The entry point function name for the shader in UTF-8. */
	ShaderStage ShaderStage /**< The shader stage to transpile the shader with. */

	Props sdl.PropertiesID /**< A properties ID for extensions. Should be 0 if no extensions are needed. */
}

type ShaderStage

type ShaderStage int32
const (
	SHADERSTAGE_VERTEX ShaderStage = iota
	SHADERSTAGE_FRAGMENT
	SHADERSTAGE_COMPUTE
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL