icculus / mojoshader

Use Direct3D shaders with other 3D rendering APIs.
https://icculus.org/mojoshader/
zlib License
122 stars 36 forks source link

[hlsl] PointCoord Support #48

Open flibitijibibo opened 2 years ago

flibitijibibo commented 2 years ago

I'm pretty sure we noticed this the first time around, but it came up again while we were using Flotilla as an experiment for NativeAOT support. Simply put, GLSL/SPIR-V both have gl_PointCoord or gl_TexCoord[0] working with point sprites, but D3D11 doesn't appear to have a straightforward equivalent (as far as I know, TEXCOORD0 doesn't work like it did with D3D9). Microsoft incorrectly suggests using VPOS, and ANGLE emulates point sprites with geometry shaders, so this doesn't look good.

TheSpydog commented 2 years ago

If anyone's interested in experimenting with possible solutions, I've scribbled out a rough version of what the general structure might look like, minus the key part -- what semantic or convoluted workaround we should use.

diff --git a/mojoshader_d3d11.c b/mojoshader_d3d11.c
index 92902fd..e113a05 100644
--- a/mojoshader_d3d11.c
+++ b/mojoshader_d3d11.c
@@ -415,7 +415,7 @@ static char *rewritePixelShader(MOJOSHADER_d3d11Shader *vshader,
     const char *_Input = "_Input" ENDLINE_STR "{" ENDLINE_STR;
     const char *vsrc = vpd->output;
     const char *psrc = ppd->output;
-    const char *a, *b, *vout, *pstart, *vface, *pend;
+    const char *a, *b, *vout, *pstart, *vface, *pointcoord, *pend;
     size_t substr_len;
     char *pfinal;

@@ -449,6 +449,7 @@ static char *rewritePixelShader(MOJOSHADER_d3d11Shader *vshader,
     // Find matching semantics
     int i, j;
     int vfaceidx = -1;
+    int pointcoordidx = -1;
     const char *pvarname, *vvarname;
     for (i = 0; i < ppd->attribute_count; i++)
     {
@@ -477,7 +478,21 @@ static char *rewritePixelShader(MOJOSHADER_d3d11Shader *vshader,
         } // for

         if (strcmp(ppd->attributes[i].name, "vFace") == 0)
+        {
+            found_matching_vs_output_for_ps_input = 1;
             vfaceidx = i;
+        } // if
+
+        if (!found_matching_vs_output_for_ps_input)
+        {
+            if (ppd->attributes[i].usage == MOJOSHADER_USAGE_TEXCOORD &&
+                ppd->attributes[i].index == 0)
+            {
+                found_matching_vs_output_for_ps_input = 1;
+                pointcoordidx = i;
+                replaceVarname(ppd->attributes[i].name, "pointCoord", &pend);
+            } // if
+        } // if

         // A vertex shader that doesn't properly initialize all its outputs
         //  can produce a situation where vpd->outputs is missing a matching
@@ -491,14 +506,18 @@ static char *rewritePixelShader(MOJOSHADER_d3d11Shader *vshader,
     // Special handling for VFACE
     vface = (vfaceidx != -1) ? "\tbool m_vFace : SV_IsFrontFace;\n" : "";

+    // Special handling for point coord (aka TEXCOORD0)
+    pointcoord = (pointcoordidx != -1) ? "\tfloat2 m_pointCoord : TEXCOORD0;\n" : ""; // FIXME: What semantic...?
+
     // Concatenate the shader pieces together
-    substr_len = strlen(pstart) + strlen(vout) + strlen(vface) + strlen(pend);
+    substr_len = strlen(pstart) + strlen(vout) + strlen(vface) + strlen(pointcoord) + strlen(pend);
     pfinal = (char *) ctx->malloc_fn(substr_len + 1, ctx->malloc_data);
     memset((void *) pfinal, '\0', substr_len + 1);
     memcpy(pfinal, pstart, strlen(pstart));
     memcpy(pfinal + strlen(pstart), vout, strlen(vout));
     memcpy(pfinal + strlen(pstart) + strlen(vout), vface, strlen(vface));
-    memcpy(pfinal + strlen(pstart) + strlen(vout) + strlen(vface), pend, strlen(pend));
+    memcpy(pfinal + strlen(pstart) + strlen(vout) + strlen(vface), pointcoord, strlen(pointcoord));
+    memcpy(pfinal + strlen(pstart) + strlen(vout) + strlen(vface) + strlen(pointcoord), pend, strlen(pend));

     // Free the temporary buffers
     ctx->free_fn((void *) vout, ctx->malloc_data);