From 15ba98fb682deea8c144ef1e2e91f2d284f53034 Mon Sep 17 00:00:00 2001 From: Ivan Ushakov Date: Thu, 6 Aug 2026 09:39:20 +0300 Subject: [PATCH] Name every vertex input TEXCOORD, as SDL's D3D12 backend does No pipeline could be created on Windows. Every SDL_CreateGPUGraphicsPipeline call failed with a bare E_INVALIDARG (0x80070057); the D3D12 debug layer had the real reason: CreateInputLayout: The provided input signature expects to read an element with SemanticName/Index: 'POSITION'/0, but the declaration doesn't provide a matching name. [CREATEINPUTLAYOUT_MISSINGELEMENT] SDL_GPUVertexAttribute has no semantic field -- SPIR-V and MSL bind vertex inputs by location, so there is nothing for it to carry. D3D12 does need one, and its backend invents it: every D3D12_INPUT_ELEMENT_DESC gets SemanticName "TEXCOORD" and SemanticIndex = the attribute's location. A shader declaring POSITION, COLOR0, NORMAL or BLENDINDICES names elements the layout will never provide, and CreateInputLayout refuses it. Windows is the only platform this reaches, because it is the only one that compiles our HLSL as HLSL -- dxc straight to DXIL, semantics intact. Linux and macOS launder them through SPIR-V, where the names are dropped and the locations are all that survive. So the semantics now spell out the location instead of the D3D9 usage. Where an #if drops an attribute from the middle of a layout (object3dx, rigid lods carry no blend weights) the ones after it renumber with it, matching how SDLObject3dxRenderer::pipelineFor numbers the attributes it actually binds. Locations are untouched: compiling all 27 vertex entry points before and after gives identical attribute types and bindings on the SPIR-V/MSL route, so Vulkan and Metal see no change. Verified rendering unchanged on macOS. Also stop four renderers reporting "pipeline ready" from their constructor. They only create shaders there and build pipelines lazily, so the Windows log read as if grass, cloud shadows, environment earth and the post-effects were fine while every other renderer failed -- when in fact they had not yet tried. Co-Authored-By: Claude Opus 5 --- Documents/Build-PORTING.md | 33 ++++++++++++++++++++ Render/SDLCloudShadowRenderer.cpp | 3 +- Render/SDLEnvironmentEarthRenderer.cpp | 3 +- Render/SDLGrassRenderer.cpp | 5 ++- Render/SDLPostEffectRenderer.cpp | 3 +- Render/SDLShaders/ShaderBlob.h | 26 +++++++++++++++ Render/SDLShaders/cloudshadow.vert.hlsl | 10 +++--- Render/SDLShaders/environmentearth.vert.hlsl | 8 +++-- Render/SDLShaders/grass.vert.hlsl | 14 +++++---- Render/SDLShaders/minimap.vert.hlsl | 10 +++--- Render/SDLShaders/object3dx.vert.hlsl | 29 ++++++++++++----- Render/SDLShaders/object3dx_shadow.vert.hlsl | 21 ++++++++++--- Render/SDLShaders/tilemap.vert.hlsl | 6 ++-- Render/SDLShaders/tilemap_ice.vert.hlsl | 6 ++-- Render/SDLShaders/tilemap_lava.vert.hlsl | 6 ++-- Render/SDLShaders/tilemap_shadow.vert.hlsl | 4 ++- Render/SDLShaders/ui.vert.hlsl | 8 +++-- Render/SDLShaders/water.vert.hlsl | 6 ++-- Render/SDLShaders/water_ice.vert.hlsl | 6 ++-- Render/SDLShaders/worldquad.vert.hlsl | 8 +++-- Render/SDLShaders/worldtri.vert.hlsl | 10 +++--- 21 files changed, 171 insertions(+), 54 deletions(-) diff --git a/Documents/Build-PORTING.md b/Documents/Build-PORTING.md index 57e6e000..5d7c3c86 100644 --- a/Documents/Build-PORTING.md +++ b/Documents/Build-PORTING.md @@ -29,6 +29,39 @@ not bring `__super` with it, and the engine uses that keyword in ~180 files. Don't pin the Visual Studio generator. `windows-latest` moved to VS 2026 mid-2026; naming a version only moves the breakage to the next image bump. CMake picks the newest it finds. +### Every vertex input's semantic is `TEXCOORD` + +Windows is the one platform that compiles our HLSL *as HLSL* — dxc straight to DXIL, with +the semantics we wrote. Linux and macOS launder them through SPIR-V, where semantics do not +survive. Only D3D12 ever sees the names, and it is the one backend that checks them. + +SDL_GPU has no semantic to bind by: `SDL_GPUVertexAttribute` carries a *location*, because +that is all SPIR-V and MSL need. Its D3D12 backend therefore invents one, stamping every +`D3D12_INPUT_ELEMENT_DESC` with `SemanticName = "TEXCOORD"` and `SemanticIndex = location` +(`D3D12_INTERNAL_ConvertVertexInputState`). `CreateInputLayout` then rejects a layout that +does not name every element the shader reads — so `float3 pos : POSITION` cannot be bound: + +``` +D3D12 ERROR: ID3D12Device::CreateInputLayout: The provided input signature expects to read +an element with SemanticName/Index: 'POSITION'/0, but the declaration doesn't provide a +matching name. [ STATE_CREATION ERROR #65: CREATEINPUTLAYOUT_MISSINGELEMENT] +``` + +`SDL_CreateGPUGraphicsPipeline` reports that as a bare `E_INVALIDARG` (0x80070057) with no +mention of semantics, so **turn on the D3D12 debug layer before believing any pipeline +error** — the useful message only exists there. + +So: a vertex shader input takes `TEXCOORD`, never the semantic the data +means. `#if`-conditional layouts renumber with the `#if` (see `object3dx.vert.hlsl`, where +a rigid lod carries no blend weights and everything after them shifts down one). Nothing +else is constrained — interpolants between our own vertex and fragment stages are matched +by name within the pair, and keep whatever reads best. + +Resource registers have a matching convention, and this tree already follows it: vertex +uniforms at `b0, space1`, fragment textures/samplers at `t#/s#, space2`, fragment uniforms +at `b0, space3`. Getting one wrong fails pipeline creation the same opaque way, because the +root signature SDL builds will not cover the shader's bindings. + ## One source list per module Every module's `CMakeLists.txt` used to have a `WIN32` branch feeding it a different set of diff --git a/Render/SDLCloudShadowRenderer.cpp b/Render/SDLCloudShadowRenderer.cpp index 590c1a00..b7309271 100644 --- a/Render/SDLCloudShadowRenderer.cpp +++ b/Render/SDLCloudShadowRenderer.cpp @@ -22,7 +22,8 @@ SDLCloudShadowRenderer::SDLCloudShadowRenderer(cSDLRenderDevice* owner, SDL_GPUD createSampler(); whiteTexture_ = createSolidGPUTexture(device_, 0xffffffffu); if(createShaders()) - fprintf(stderr, "SDLCloudShadowRenderer: cloud shadow pipeline ready\n"); + // Shaders only; pipelineFor() builds the pipelines on demand. See SDLGrassRenderer. + fprintf(stderr, "SDLCloudShadowRenderer: cloud shadow shaders ready\n"); } SDLCloudShadowRenderer::~SDLCloudShadowRenderer() diff --git a/Render/SDLEnvironmentEarthRenderer.cpp b/Render/SDLEnvironmentEarthRenderer.cpp index e3b9c0c9..ca083957 100644 --- a/Render/SDLEnvironmentEarthRenderer.cpp +++ b/Render/SDLEnvironmentEarthRenderer.cpp @@ -22,7 +22,8 @@ SDLEnvironmentEarthRenderer::SDLEnvironmentEarthRenderer(cSDLRenderDevice* owner createSampler(); whiteTexture_ = createSolidGPUTexture(device_, 0xffffffffu); if(createShaders()) - fprintf(stderr, "SDLEnvironmentEarthRenderer: environment earth pipeline ready\n"); + // Shaders only; pipelineFor() builds the pipelines on demand. See SDLGrassRenderer. + fprintf(stderr, "SDLEnvironmentEarthRenderer: environment earth shaders ready\n"); } SDLEnvironmentEarthRenderer::~SDLEnvironmentEarthRenderer() diff --git a/Render/SDLGrassRenderer.cpp b/Render/SDLGrassRenderer.cpp index 76e84d40..38fe5a50 100644 --- a/Render/SDLGrassRenderer.cpp +++ b/Render/SDLGrassRenderer.cpp @@ -44,7 +44,10 @@ SDLGrassRenderer::SDLGrassRenderer(cSDLRenderDevice* owner, SDL_GPUDevice* devic createSamplers(); whiteTexture_ = createSolidGPUTexture(device_, 0xffffffffu); if(createShaders()) - fprintf(stderr, "SDLGrassRenderer: grass pipeline ready\n"); + // Shaders only: the pipelines themselves are built on demand, per vertex stride, + // in pipelineFor(). Do not report them as ready here -- a pipeline that fails to + // create does so long after this line, and saying "pipeline" reads as if it had not. + fprintf(stderr, "SDLGrassRenderer: grass shaders ready\n"); } SDLGrassRenderer::~SDLGrassRenderer() diff --git a/Render/SDLPostEffectRenderer.cpp b/Render/SDLPostEffectRenderer.cpp index d67cff6a..37a0001b 100644 --- a/Render/SDLPostEffectRenderer.cpp +++ b/Render/SDLPostEffectRenderer.cpp @@ -17,7 +17,8 @@ SDLPostEffectRenderer::SDLPostEffectRenderer(SDL_GPUDevice* device, SDL_Window* { createSamplers(); if(createShaders()) - fprintf(stderr, "SDLPostEffectRenderer: post-effect pipelines ready\n"); + // Shaders only; the pipelines are built on demand. See SDLGrassRenderer. + fprintf(stderr, "SDLPostEffectRenderer: post-effect shaders ready\n"); } SDLPostEffectRenderer::~SDLPostEffectRenderer() diff --git a/Render/SDLShaders/ShaderBlob.h b/Render/SDLShaders/ShaderBlob.h index bdeb60b7..ea524873 100644 --- a/Render/SDLShaders/ShaderBlob.h +++ b/Render/SDLShaders/ShaderBlob.h @@ -39,6 +39,32 @@ inline constexpr SDL_GPUShaderFormat kShaderFormat = SDL_GPU_SHADERFORMAT_SP inline constexpr const char* kShaderEntryPoint = "main"; #endif +// --------------------------------------------------------------------------------------- +// Why every vertex input in SDLShaders/*.vert.hlsl is a TEXCOORD +// --------------------------------------------------------------------------------------- +// SDL_GPU describes a vertex attribute by *location* alone -- SDL_GPUVertexAttribute has no +// semantic field, because SPIR-V and MSL have no semantics to fill it with. D3D12 does, so +// its backend has to invent one: D3D12_INTERNAL_ConvertVertexInputState stamps every +// D3D12_INPUT_ELEMENT_DESC with SemanticName = "TEXCOORD" and SemanticIndex = location. +// +// ID3D12Device::CreateInputLayout then rejects any layout that does not name every element +// the vertex shader's input signature reads. So a shader declaring `float3 pos : POSITION` +// fails pipeline creation outright: +// +// CREATEINPUTLAYOUT_MISSINGELEMENT: The provided input signature expects to read an +// element with SemanticName/Index: 'POSITION'/0, but the declaration doesn't provide a +// matching name. +// +// which surfaces from SDL_CreateGPUGraphicsPipeline as a bare E_INVALIDARG (0x80070057). +// The rule is therefore: a vertex shader input's semantic is TEXCOORD, never +// what the data means. The `#if`-conditional layouts (object3dx) renumber accordingly. +// +// Only the DXIL path cares. Locations in SPIR-V and MSL come from declaration order, which +// the naming does not affect, so the same source keeps its bindings on Vulkan and Metal. +// +// This constrains *inputs* only. Interpolants between the vertex and fragment stages are +// matched by name within our own shader pairs, and keep the semantic that reads best. + // Fill in the fields of an SDL_GPUShaderCreateInfo that are the same for every shader we // build: the bytecode, its format, and its entry point. The caller still sets the stage // and the resource counts, which differ per shader. diff --git a/Render/SDLShaders/cloudshadow.vert.hlsl b/Render/SDLShaders/cloudshadow.vert.hlsl index b36f39af..e3bd1d4d 100644 --- a/Render/SDLShaders/cloudshadow.vert.hlsl +++ b/Render/SDLShaders/cloudshadow.vert.hlsl @@ -31,10 +31,12 @@ cbuffer Constants : register(b0, space1) struct VSInput { // sVertexXYZDT2, stride 32. - float3 Position : POSITION; // offset 0, world space - float4 Color : COLOR0; // offset 12, D3DCOLOR -> UBYTE4_NORM (b,g,r,a) - float2 UV0 : TEXCOORD0; // offset 16, the first scroll - float2 UV1 : TEXCOORD1; // offset 24, the second + // The semantics are TEXCOORD, not what the data means -- SDL_GPU's D3D12 + // backend names every input element TEXCOORD; see SDLShaders/ShaderBlob.h. + float3 Position : TEXCOORD0; // offset 0, world space + float4 Color : TEXCOORD1; // offset 12, D3DCOLOR -> UBYTE4_NORM (b,g,r,a) + float2 UV0 : TEXCOORD2; // offset 16, the first scroll + float2 UV1 : TEXCOORD3; // offset 24, the second }; struct VSOutput diff --git a/Render/SDLShaders/environmentearth.vert.hlsl b/Render/SDLShaders/environmentearth.vert.hlsl index aa772c6e..a9c724db 100644 --- a/Render/SDLShaders/environmentearth.vert.hlsl +++ b/Render/SDLShaders/environmentearth.vert.hlsl @@ -26,9 +26,11 @@ struct VSInput { // sVertexXYZDT1, stride 24. The diffuse is carried to match the vertex declaration but not // used -- EnvironmentEarth.psl shades from the texture and the tfactor uniform alone. - float3 Position : POSITION; // offset 0, world space - float4 Color : COLOR0; // offset 12, D3DCOLOR -> UBYTE4_NORM - float2 UV0 : TEXCOORD0; // offset 16 + // The semantics are TEXCOORD, not what the data means -- SDL_GPU's D3D12 + // backend names every input element TEXCOORD; see SDLShaders/ShaderBlob.h. + float3 Position : TEXCOORD0; // offset 0, world space + float4 Color : TEXCOORD1; // offset 12, D3DCOLOR -> UBYTE4_NORM + float2 UV0 : TEXCOORD2; // offset 16 }; struct VSOutput diff --git a/Render/SDLShaders/grass.vert.hlsl b/Render/SDLShaders/grass.vert.hlsl index deb1da41..48cf4e75 100644 --- a/Render/SDLShaders/grass.vert.hlsl +++ b/Render/SDLShaders/grass.vert.hlsl @@ -85,26 +85,28 @@ cbuffer Constants : register(b0, space1) struct VSInput { - // shortVertexGrass, stride 28. Attribute locations follow this declaration order. + // shortVertexGrass, stride 28. Attribute locations follow this declaration order, and + // the semantics spell that location out rather than what the data means -- SDL_GPU's + // D3D12 backend names every input element TEXCOORD; see SDLShaders/ShaderBlob.h. // // SHORT4, NOT normalized: these are world coordinates in whole units (Bush::pos), which // is why the position is only 8 bytes. D3D9's D3DDECLTYPE_SHORT4 hands them to the shader // as floats; SPIR-V hands them over as sint, so we take int4 and convert. - int4 Position : POSITION; // offset 0 + int4 Position : TEXCOORD0; // offset 0 // Color4c is stored b,g,r,a in memory, so UBYTE4_NORM gives (b,g,r,a): swizzle to read it. // rgb is the terrain colour under the bush (vMap.getColor32), a is Bush::shift -- the // blade's own wind phase, and 0 on the two vertices that stay rooted in the ground. - float4 Color : COLOR0; // offset 8, D3DCOLOR + float4 Color : TEXCOORD1; // offset 8, D3DCOLOR // The bush's surface normal, biased into 0..1 (hence the *2-1 below). Its ALPHA is not a // normal component at all: it is a per-blade brightness added to the vertex colour. - float4 Normal : NORMAL; // offset 12, D3DCOLOR + float4 Normal : TEXCOORD2; // offset 12, D3DCOLOR // xy: the blade's texture coordinate in the grass atlas, pre-multiplied by 10000 so it // survives as a short (undone by *0.0001 below). // z: ±half-width of the blade, in world units. // w: the blade's height, in world units. - int4 TexCoord : TEXCOORD0; // offset 16, SHORT4 + int4 TexCoord : TEXCOORD3; // offset 16, SHORT4 // Bush::windPower: the time at which this blade was planted. See `sc` below. - float PlantTime : TEXCOORD1; // offset 24, FLOAT1 (stride 28) + float PlantTime : TEXCOORD4; // offset 24, FLOAT1 (stride 28) }; struct VSOutput diff --git a/Render/SDLShaders/minimap.vert.hlsl b/Render/SDLShaders/minimap.vert.hlsl index 71a30e48..d829ab71 100644 --- a/Render/SDLShaders/minimap.vert.hlsl +++ b/Render/SDLShaders/minimap.vert.hlsl @@ -24,10 +24,12 @@ cbuffer Constants : register(b0, space1) struct VSInput { - float2 Position : POSITION; // screen pixels - float4 Color : COLOR0; // BGRA (Color4c byte order) - float2 MaskUV : TEXCOORD0; - float2 UV : TEXCOORD1; + // The semantics are TEXCOORD, not what the data means -- SDL_GPU's D3D12 + // backend names every input element TEXCOORD; see SDLShaders/ShaderBlob.h. + float2 Position : TEXCOORD0; // screen pixels + float4 Color : TEXCOORD1; // BGRA (Color4c byte order) + float2 MaskUV : TEXCOORD2; + float2 UV : TEXCOORD3; }; struct VSOutput diff --git a/Render/SDLShaders/object3dx.vert.hlsl b/Render/SDLShaders/object3dx.vert.hlsl index 811a71c8..d6833b08 100644 --- a/Render/SDLShaders/object3dx.vert.hlsl +++ b/Render/SDLShaders/object3dx.vert.hlsl @@ -102,20 +102,35 @@ cbuffer Constants : register(b0, space1) float4 World[MAX_BONES * 3]; }; +// SDL_GPU's D3D12 backend names every vertex input element TEXCOORD, whatever +// the data means, so the semantics below spell out the attribute location rather than the +// D3D9 usage (see SDLShaders/ShaderBlob.h). SKINNED drops one attribute in the middle, so +// everything after it shifts down a location -- exactly as SDLObject3dxRenderer's +// pipelineFor() numbers them, which skips the weight slot for a rigid lod. +#if SKINNED +#define SEM_UV TEXCOORD4 +#define SEM_BINORMAL TEXCOORD5 +#define SEM_TANGENT TEXCOORD6 +#else +#define SEM_UV TEXCOORD3 +#define SEM_BINORMAL TEXCOORD4 +#define SEM_TANGENT TEXCOORD5 +#endif + struct VSInput { - float3 Position : POSITION; // offset 0 - uint4 BlendIndices : BLENDINDICES; // offset 12, D3DCOLOR -> UBYTE4 (memory order) - float3 Normal : NORMAL; // offset 16 + float3 Position : TEXCOORD0; // offset 0 + uint4 BlendIndices : TEXCOORD1; // offset 12, D3DCOLOR -> UBYTE4 (memory order) + float3 Normal : TEXCOORD2; // offset 16 #if SKINNED - float4 BlendWeight : COLOR0; // offset 28, D3DCOLOR -> UBYTE4_NORM (b,g,r,a) + float4 BlendWeight : TEXCOORD3; // offset 28, D3DCOLOR -> UBYTE4_NORM (b,g,r,a) #endif - float2 UV : TEXCOORD0; // offset 28 (rigid) / 32 (skinned) + float2 UV : SEM_UV; // offset 28 (rigid) / 32 (skinned) #if BUMP // cSkinVertex's tangent frame, right after the uv: BINORMAL is GetBumpS, TANGENT is // GetBumpT, and cStatic3dx::CalcBumpSTNorm makes the normal their cross product. - float3 Binormal : BINORMAL; // uv + 8 - float3 Tangent : TANGENT; // uv + 20 + float3 Binormal : SEM_BINORMAL; // uv + 8 + float3 Tangent : SEM_TANGENT; // uv + 20 #endif }; diff --git a/Render/SDLShaders/object3dx_shadow.vert.hlsl b/Render/SDLShaders/object3dx_shadow.vert.hlsl index 8904839c..05d73e3d 100644 --- a/Render/SDLShaders/object3dx_shadow.vert.hlsl +++ b/Render/SDLShaders/object3dx_shadow.vert.hlsl @@ -47,15 +47,26 @@ cbuffer Constants : register(b0, space1) float4 World[MAX_BONES * 3]; }; +// SDL_GPU's D3D12 backend names every vertex input element TEXCOORD, whatever +// the data means, so the semantics below spell out the attribute location rather than the +// D3D9 usage (see SDLShaders/ShaderBlob.h). SKINNED drops one attribute in the middle, so +// the uv that follows it shifts down a location -- exactly as SDLObject3dxRenderer's +// pipelineFor() numbers them, which skips the weight slot for a rigid lod. +#if SKINNED +#define SEM_UV TEXCOORD4 +#else +#define SEM_UV TEXCOORD3 +#endif + struct VSInput { - float3 Position : POSITION; - uint4 BlendIndices : BLENDINDICES; - float3 Normal : NORMAL; + float3 Position : TEXCOORD0; + uint4 BlendIndices : TEXCOORD1; + float3 Normal : TEXCOORD2; #if SKINNED - float4 BlendWeight : COLOR0; + float4 BlendWeight : TEXCOORD3; #endif - float2 UV : TEXCOORD0; + float2 UV : SEM_UV; }; struct VSOutput diff --git a/Render/SDLShaders/tilemap.vert.hlsl b/Render/SDLShaders/tilemap.vert.hlsl index cb1ba18d..2ce16905 100644 --- a/Render/SDLShaders/tilemap.vert.hlsl +++ b/Render/SDLShaders/tilemap.vert.hlsl @@ -53,8 +53,10 @@ cbuffer Constants : register(b0, space1) struct VSInput { - float3 Position : POSITION; // world space, offset 0 - float3 Normal : NORMAL; // world space, offset 12 + // The semantics are TEXCOORD, not what the data means -- SDL_GPU's D3D12 + // backend names every input element TEXCOORD; see SDLShaders/ShaderBlob.h. + float3 Position : TEXCOORD0; // world space, offset 0 + float3 Normal : TEXCOORD1; // world space, offset 12 }; struct VSOutput diff --git a/Render/SDLShaders/tilemap_ice.vert.hlsl b/Render/SDLShaders/tilemap_ice.vert.hlsl index c048ecb0..a7f95982 100644 --- a/Render/SDLShaders/tilemap_ice.vert.hlsl +++ b/Render/SDLShaders/tilemap_ice.vert.hlsl @@ -35,8 +35,10 @@ cbuffer Constants : register(b0, space1) struct VSInput { - float3 Position : POSITION; // world space, offset 0 - float3 Normal : NORMAL; // offset 12 (unused here; kept for the shared mesh layout) + // The semantics are TEXCOORD, not what the data means -- SDL_GPU's D3D12 + // backend names every input element TEXCOORD; see SDLShaders/ShaderBlob.h. + float3 Position : TEXCOORD0; // world space, offset 0 + float3 Normal : TEXCOORD1; // offset 12 (unused here; kept for the shared mesh layout) }; struct VSOutput diff --git a/Render/SDLShaders/tilemap_lava.vert.hlsl b/Render/SDLShaders/tilemap_lava.vert.hlsl index 76b88fab..758f6251 100644 --- a/Render/SDLShaders/tilemap_lava.vert.hlsl +++ b/Render/SDLShaders/tilemap_lava.vert.hlsl @@ -33,8 +33,10 @@ cbuffer Constants : register(b0, space1) struct VSInput { - float3 Position : POSITION; // world space, offset 0 - float3 Normal : NORMAL; // world space, offset 12 (unused here; kept for the shared layout) + // The semantics are TEXCOORD, not what the data means -- SDL_GPU's D3D12 + // backend names every input element TEXCOORD; see SDLShaders/ShaderBlob.h. + float3 Position : TEXCOORD0; // world space, offset 0 + float3 Normal : TEXCOORD1; // world space, offset 12 (unused here; kept for the shared layout) }; struct VSOutput diff --git a/Render/SDLShaders/tilemap_shadow.vert.hlsl b/Render/SDLShaders/tilemap_shadow.vert.hlsl index 59c985c4..3901454e 100644 --- a/Render/SDLShaders/tilemap_shadow.vert.hlsl +++ b/Render/SDLShaders/tilemap_shadow.vert.hlsl @@ -16,7 +16,9 @@ cbuffer Constants : register(b0, space1) row_major float4x4 MVP; // the light camera's matViewProj }; -float4 main(float3 position : POSITION) : SV_Position +// TEXCOORD0, not POSITION: SDL_GPU's D3D12 backend names every vertex input element +// TEXCOORD, whatever the data means. See SDLShaders/ShaderBlob.h. +float4 main(float3 position : TEXCOORD0) : SV_Position { return mul(float4(position, 1.0f), MVP); } diff --git a/Render/SDLShaders/ui.vert.hlsl b/Render/SDLShaders/ui.vert.hlsl index 3a61bd5b..e1119e1b 100644 --- a/Render/SDLShaders/ui.vert.hlsl +++ b/Render/SDLShaders/ui.vert.hlsl @@ -12,11 +12,13 @@ cbuffer Constants : register(b0, space1) float2 _pad; }; +// Vertex inputs are TEXCOORD, not the semantic the data means -- SDL_GPU's +// D3D12 backend names every input element TEXCOORD; see SDLShaders/ShaderBlob.h. struct VSInput { - float4 Position : POSITION; // x,y in pixels - float4 Color : COLOR0; // BGRA (Color4c byte order) - float2 UV : TEXCOORD0; + float4 Position : TEXCOORD0; // x,y in pixels + float4 Color : TEXCOORD1; // BGRA (Color4c byte order) + float2 UV : TEXCOORD2; }; struct VSOutput diff --git a/Render/SDLShaders/water.vert.hlsl b/Render/SDLShaders/water.vert.hlsl index 30d71af3..74cb5a50 100644 --- a/Render/SDLShaders/water.vert.hlsl +++ b/Render/SDLShaders/water.vert.hlsl @@ -57,11 +57,13 @@ cbuffer Constants : register(b0, space1) struct VSInput { - float3 Position : POSITION; // world space, offset 0 + // The semantics are TEXCOORD, not what the data means -- SDL_GPU's D3D12 + // backend names every input element TEXCOORD; see SDLShaders/ShaderBlob.h. + float3 Position : TEXCOORD0; // world space, offset 0 // sVertexXYZD's D3DCOLOR diffuse, offset 12. Only the alpha is read (the fragment // shader's per-vertex water opacity, baked by cWater::CalcColor from the depth // gradient); .w is the alpha byte whichever way the other three are ordered. - float4 Diffuse : COLOR0; + float4 Diffuse : TEXCOORD1; }; struct VSOutput diff --git a/Render/SDLShaders/water_ice.vert.hlsl b/Render/SDLShaders/water_ice.vert.hlsl index a57309ae..e7f218f4 100644 --- a/Render/SDLShaders/water_ice.vert.hlsl +++ b/Render/SDLShaders/water_ice.vert.hlsl @@ -35,8 +35,10 @@ cbuffer Constants : register(b0, space1) struct VSInput { - float3 Position : POSITION; // world space, offset 0 - float4 Diffuse : COLOR0; // UBYTE4_NORM @12; .r is the coverage weight aa + // The semantics are TEXCOORD, not what the data means -- SDL_GPU's D3D12 + // backend names every input element TEXCOORD; see SDLShaders/ShaderBlob.h. + float3 Position : TEXCOORD0; // world space, offset 0 + float4 Diffuse : TEXCOORD1; // UBYTE4_NORM @12; .r is the coverage weight aa }; struct VSOutput diff --git a/Render/SDLShaders/worldquad.vert.hlsl b/Render/SDLShaders/worldquad.vert.hlsl index d7754d83..36357add 100644 --- a/Render/SDLShaders/worldquad.vert.hlsl +++ b/Render/SDLShaders/worldquad.vert.hlsl @@ -33,9 +33,11 @@ cbuffer Constants : register(b0, space1) struct VSInput { - float3 Position : POSITION; // sVertexXYZDT1: world-space position, offset 0 - float4 Color : COLOR0; // D3DCOLOR diffuse, offset 12 -> UBYTE4_NORM (b,g,r,a) - float2 UV : TEXCOORD0; // offset 16 (stride 24) + // The semantics are TEXCOORD, not what the data means -- SDL_GPU's D3D12 + // backend names every input element TEXCOORD; see SDLShaders/ShaderBlob.h. + float3 Position : TEXCOORD0; // sVertexXYZDT1: world-space position, offset 0 + float4 Color : TEXCOORD1; // D3DCOLOR diffuse, offset 12 -> UBYTE4_NORM (b,g,r,a) + float2 UV : TEXCOORD2; // offset 16 (stride 24) }; struct VSOutput diff --git a/Render/SDLShaders/worldtri.vert.hlsl b/Render/SDLShaders/worldtri.vert.hlsl index 046d3272..fbfeb4f3 100644 --- a/Render/SDLShaders/worldtri.vert.hlsl +++ b/Render/SDLShaders/worldtri.vert.hlsl @@ -41,10 +41,12 @@ cbuffer Constants : register(b0, space1) struct VSInput { - float3 Position : POSITION; // sVertexXYZDT2: position, offset 0 - float4 Color : COLOR0; // D3DCOLOR diffuse, offset 12 -> UBYTE4_NORM (b,g,r,a) - float2 UV0 : TEXCOORD0; // offset 16 - float2 UV1 : TEXCOORD1; // offset 24 (stride 32) + // The semantics are TEXCOORD, not what the data means -- SDL_GPU's D3D12 + // backend names every input element TEXCOORD; see SDLShaders/ShaderBlob.h. + float3 Position : TEXCOORD0; // sVertexXYZDT2: position, offset 0 + float4 Color : TEXCOORD1; // D3DCOLOR diffuse, offset 12 -> UBYTE4_NORM (b,g,r,a) + float2 UV0 : TEXCOORD2; // offset 16 + float2 UV1 : TEXCOORD3; // offset 24 (stride 32) }; struct VSOutput