GLSL: Implement texldl instruction
authorKatelyn Gadd <kg@luminance.org>
Wed, 21 Aug 2019 09:30:54 -0400
changeset 1212 124155bb9bed
parent 1211 74c594099cba
child 1213 dc86dc29d124
GLSL: Implement texldl instruction
profiles/mojoshader_profile.h
profiles/mojoshader_profile_glsl.c
--- a/profiles/mojoshader_profile.h	Wed Aug 14 09:33:57 2019 -0400
+++ b/profiles/mojoshader_profile.h	Wed Aug 21 09:30:54 2019 -0400
@@ -158,7 +158,7 @@
 
     // !!! FIXME: move these into SUPPORT_PROFILE sections.
     int glsl_generated_lit_helper;
-    int glsl_generated_texldd_setup;
+    int glsl_generated_texlod_setup;
     int glsl_generated_texm3x3spec_helper;
     int arb1_wrote_position;
     // !!! FIXME: move these into SUPPORT_PROFILE sections.
@@ -362,4 +362,4 @@
                                    const size_t len);
 const char *get_D3D_varname(Context *ctx, RegisterType rt, int regnum);
 
-#endif
\ No newline at end of file
+#endif
--- a/profiles/mojoshader_profile_glsl.c	Wed Aug 14 09:33:57 2019 -0400
+++ b/profiles/mojoshader_profile_glsl.c	Wed Aug 21 09:30:54 2019 -0400
@@ -467,6 +467,45 @@
     return comps[ctx->instruction_controls];
 } // get_GLSL_comparison_string_vector
 
+// special extensions needed for texldd/texldl...
+
+static void prepend_glsl_texlod_extensions(Context *ctx)
+{
+    // !!! FIXME:
+    // GLSL 1.30 introduced textureGrad() for this, but it looks like the
+    //  functions are overloaded instead of texture2DGrad() (etc).
+
+    // !!! FIXME:
+    // The spec says we can't use GLSL's texture*Lod() built-ins from fragment
+    //  shaders for some inexplicable reason.
+    // For now, you'll just have to suffer with the potentially wrong mipmap
+    //  until I can figure something out.
+
+    // ARB_shader_texture_lod and EXT_gpu_shader4 added texture2DLod/Grad*(),
+    //  so we'll use them if available. Failing that, we'll just fallback
+    //  to a regular texture2D call and hope the mipmap it chooses is close
+    //  enough.
+    if (!ctx->glsl_generated_texlod_setup)
+    {
+        ctx->glsl_generated_texlod_setup = 1;
+        push_output(ctx, &ctx->preflight);
+        output_line(ctx, "#if GL_ARB_shader_texture_lod");
+        output_line(ctx, "#extension GL_ARB_shader_texture_lod : enable");
+        output_line(ctx, "#define texture2DGrad texture2DGradARB");
+        output_line(ctx, "#define texture2DProjGrad texture2DProjARB");
+        output_line(ctx, "#define texture2DLod texture2DLodARB");
+        output_line(ctx, "#elif GL_EXT_gpu_shader4");
+        output_line(ctx, "#extension GL_EXT_gpu_shader4 : enable");
+        output_line(ctx, "#else");
+        output_line(ctx, "#define texture2DGrad(a,b,c,d) texture2D(a,b)");
+        output_line(ctx, "#define texture2DProjGrad(a,b,c,d) texture2DProj(a,b)");
+        output_line(ctx, "#define texture2DLod(a,b,c) texture2D(a,b)");
+        output_line(ctx, "#endif");
+        output_blank_line(ctx);
+        pop_output(ctx);
+    } // if
+} // prepend_glsl_texlod_extensions
+
 
 void emit_GLSL_start(Context *ctx, const char *profilestr)
 {
@@ -1654,8 +1693,11 @@
     output_line(ctx, "if (any(lessThan(%s.xyz, vec3(0.0)))) discard;", dst);
 } // emit_GLSL_TEXKILL
 
-static void glsl_texld(Context *ctx, const int texldd)
+static void glsl_texld(Context *ctx, const int texldd, const int texldl)
 {
+    if (texldd || texldl)
+        prepend_glsl_texlod_extensions(ctx);
+
     if (!shader_version_atleast(ctx, 1, 4))
     {
         DestArgInfo *info = &ctx->dest_arg;
@@ -1664,6 +1706,7 @@
         char code[128] = {0};
 
         assert(!texldd);
+        assert(!texldl);
 
         RegisterList *sreg;
         sreg = reglist_find(&ctx->samplers, REG_TYPE_SAMPLER, info->regnum);
@@ -1756,13 +1799,18 @@
                     funcname = "texture2DProj";
                     make_GLSL_srcarg_string_full(ctx, 0, src0, sizeof (src0));
                 } // if
-                else  // texld/texldb
+                else  // texld/texldb/texldl
                 {
                     funcname = "texture2D";
-                    make_GLSL_srcarg_string_vec2(ctx, 0, src0, sizeof (src0));
+                    if (texldl)
+                        make_GLSL_srcarg_string_full(ctx, 0, src0, sizeof (src0));
+                    else
+                        make_GLSL_srcarg_string_vec2(ctx, 0, src0, sizeof (src0));
                 } // else
                 break;
             case TEXTURE_TYPE_CUBE:
+                assert(!texldl);
+
                 if (ctx->instruction_controls == CONTROL_TEXLDP)
                     fail(ctx, "TEXLDP on a cubemap");  // !!! FIXME: is this legal?
                 funcname = "textureCube";
@@ -1774,10 +1822,13 @@
                     funcname = "texture3DProj";
                     make_GLSL_srcarg_string_full(ctx, 0, src0, sizeof (src0));
                 } // if
-                else  // texld/texldb
+                else  // texld/texldb/texldl
                 {
                     funcname = "texture3D";
-                    make_GLSL_srcarg_string_vec3(ctx, 0, src0, sizeof (src0));
+                    if (texldl)
+                        make_GLSL_srcarg_string_full(ctx, 0, src0, sizeof (src0));
+                    else
+                        make_GLSL_srcarg_string_vec3(ctx, 0, src0, sizeof (src0));
                 } // else
                 break;
             default:
@@ -1797,6 +1848,24 @@
                                      "%sGrad(%s, %s, %s, %s)%s", funcname,
                                      src1, src0, src2, src3, swiz_str);
         } // if
+        else if (texldl)
+        {
+            const TextureType texType = (const TextureType) sreg->index;
+            assert(texType != TEXTURE_TYPE_CUBE);
+
+            // HLSL tex2dlod accepts (sampler, uv.xyz, uv.w) where uv.w is the LOD
+            // GLSL seems to want the dimensionality to match the sampler (.xy vs .xyz)
+            //  so we vary the swizzle accordingly
+            const char * pattern = 0;
+            if (texType == TEXTURE_TYPE_VOLUME)
+                pattern = "%sLod(%s, %s.xyz, %s.w)%s";
+            else
+                pattern = "%sLod(%s, %s.xy, %s.w)%s";
+
+            make_GLSL_destarg_assign(ctx, code, sizeof(code),
+                pattern, funcname,
+                src1, src0, src0, swiz_str);
+        } // else if
         else
         {
             make_GLSL_destarg_assign(ctx, code, sizeof (code),
@@ -1810,7 +1879,7 @@
 
 void emit_GLSL_TEXLD(Context *ctx)
 {
-    glsl_texld(ctx, 0);
+    glsl_texld(ctx, 0, 0);
 } // emit_GLSL_TEXLD
     
 
@@ -2240,33 +2309,7 @@
 
 void emit_GLSL_TEXLDD(Context *ctx)
 {
-    // !!! FIXME:
-    // GLSL 1.30 introduced textureGrad() for this, but it looks like the
-    //  functions are overloaded instead of texture2DGrad() (etc).
-
-    // GL_shader_texture_lod and GL_EXT_gpu_shader4 added texture2DGrad*(),
-    //  so we'll use them if available. Failing that, we'll just fallback
-    //  to a regular texture2D call and hope the mipmap it chooses is close
-    //  enough.
-    if (!ctx->glsl_generated_texldd_setup)
-    {
-        ctx->glsl_generated_texldd_setup = 1;
-        push_output(ctx, &ctx->preflight);
-        output_line(ctx, "#if GL_ARB_shader_texture_lod");
-        output_line(ctx, "#extension GL_ARB_shader_texture_lod : enable");
-        output_line(ctx, "#define texture2DGrad texture2DGradARB");
-        output_line(ctx, "#define texture2DProjGrad texture2DProjARB");
-        output_line(ctx, "#elif GL_EXT_gpu_shader4");
-        output_line(ctx, "#extension GL_EXT_gpu_shader4 : enable");
-        output_line(ctx, "#else");
-        output_line(ctx, "#define texture2DGrad(a,b,c,d) texture2D(a,b)");
-        output_line(ctx, "#define texture2DProjGrad(a,b,c,d) texture2DProj(a,b)");
-        output_line(ctx, "#endif");
-        output_blank_line(ctx);
-        pop_output(ctx);
-    } // if
-
-    glsl_texld(ctx, 1);
+    glsl_texld(ctx, 1, 0);
 } // emit_GLSL_TEXLDD
 
 void emit_GLSL_SETP(Context *ctx)
@@ -2295,11 +2338,7 @@
 
 void emit_GLSL_TEXLDL(Context *ctx)
 {
-    // !!! FIXME: The spec says we can't use GLSL's texture*Lod() built-ins
-    // !!! FIXME:  from fragment shaders for some inexplicable reason.
-    // !!! FIXME:  For now, you'll just have to suffer with the potentially
-    // !!! FIXME:  wrong mipmap until I can figure something out.
-    emit_GLSL_TEXLD(ctx);
+    glsl_texld(ctx, 0, 1);
 } // emit_GLSL_TEXLDL
 
 void emit_GLSL_BREAKP(Context *ctx)