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