When working with runtime shader compilation in the new SDL3 GPU API using SDL_shadercross, you might encounter a DirectX 12 pipeline failure such as:

ERROR: Could not create graphics pipeline state! Error Code: The parameter is incorrect. (0x80070057)

This error is frustrating, especially when pre-compiling via the SDL_shadercross CLI works as expected. In this guide, we will break down why this error occurs during runtime compilation and how to configure your shader pipeline properly in SDL3.

Understanding the Root Causes

DirectX 12 throws 0x80070057 (E_INVALIDARG) during CreateGraphicsPipelineState when there is a mismatch in the shader bytecode, root signature layout, or invalid buffer alignments. Common culprits in this SDL3 workflow include:

  • Unnecessary Round-Trip Transpilation: Compiling HLSL → SPIR-V → DXIL at runtime using SDL_ShaderCross_CompileSPIRVFromHLSL followed by SDL_ShaderCross_CompileGraphicsShaderFromSPIRV can mangle resource bindings and register space assignments.
  • Direct HLSL Compilation Available: SDL_shadercross supports direct HLSL-to-native shader creation through SDL_ShaderCross_CompileGraphicsShaderFromHLSL(), which handles DXIL/SPIRV/MSL targets cleanly based on the active backend.
  • Uniform Size Miscalculation: Passing sizeof *shade (which evaluates to sizeof(float) = 4 bytes) instead of sizeof(shade) (16 bytes) violates constant buffer alignment rules (D3D12 expects 16-byte alignment increments).
  • Missing DirectX Compiler DLLs: Runtime DXIL generation requires dxcompiler.dll and dxil.dll to be alongside the application executable.

Solution 1: Direct HLSL Runtime Compilation

Instead of manually compiling to intermediate SPIR-V bytecode first, pass your HLSL source directly to SDL_ShaderCross_CompileGraphicsShaderFromHLSL. This allows SDL_shadercross to choose the most efficient compilation path for the current backend.

SDL_ShaderCross_HLSL_Info hlsl_info;
SDL_zero(hlsl_info);
hlsl_info.source = HLSL_src;
hlsl_info.entrypoint = "main";
hlsl_info.shader_stage = SDL_SHADERCROSS_SHADERSTAGE_FRAGMENT;

SDL_ShaderCross_GraphicsShaderResourceInfo resource_info;
SDL_zero(resource_info);
resource_info.num_samplers = 1;
resource_info.num_uniform_buffers = 2;
resource_info.num_storage_textures = 0;
resource_info.num_storage_buffers = 0;

SDL_GPUShader* runtime_shader = SDL_ShaderCross_CompileGraphicsShaderFromHLSL(
    device,
    &hlsl_info,
    &resource_info,
    0
);

if (!runtime_shader) {
    SDL_Log("Failed to create shader: %s", SDL_GetError());
}

Solution 2: Fix Uniform Size and Buffer Uploads

In the render loop, ensure you are passing the complete size of your uniform structs or arrays, not just the size of the first element:

// float shade[4] has 16 bytes total
float shade[4] = {0.3f, 0.0f, 0.0f, 0.0f};

// Correct: sizeof(shade) = 16 bytes (float4 in HLSL)
// Incorrect: sizeof *shade = 4 bytes (causes layout mismatch)
SDL_SetGPURenderStateFragmentUniforms(state, 0, shade, sizeof(shade));

// For scalars, pass 16-byte padded vectors if using standard cbuffer rules
struct {
    float frame;
    float padding[3];
} time_uniform = { frames, {0.0f, 0.0f, 0.0f} };

SDL_SetGPURenderStateFragmentUniforms(state, 1, &time_uniform, sizeof(time_uniform));

Solution 3: If Using SPIR-V, Use Metadata Reflection

If your build system relies on precompiled SPIR-V binaries loaded at runtime, avoid manually populating SDL_ShaderCross_GraphicsShaderResourceInfo. Instead, let SDL_shadercross reflect the metadata automatically:

SDL_ShaderCross_GraphicsShaderMetadata metadata;
SDL_zero(metadata);

// Reflect accurate bindings directly from SPIR-V bytecode
if (SDL_ShaderCross_ReflectGraphicsSPIRV(SPIRV_src, SPIRV_len, &metadata)) {
    SDL_GPUShader* shader = SDL_ShaderCross_CompileGraphicsShaderFromSPIRV(
        device,
        &SPIRV_info,
        &metadata.resource_info,
        0
    );
}

Summary Checklist

  • Ensure your HLSL fragment shader bindings use space2 for textures/samplers and space3 for constant buffers (per SDL3 GPU conventions).
  • Use SDL_ShaderCross_CompileGraphicsShaderFromHLSL for runtime HLSL compiling.
  • Verify that dxcompiler.dll and dxil.dll are located in your executable's working directory on Windows.
  • Ensure all constant buffer payload sizes match the 16-byte alignment expected by Direct3D 12.