From 242845308bb7d9b511a472ffa5bfb271746e52cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Henrique?= Date: Sat, 11 Nov 2023 17:27:00 -0300 Subject: [PATCH] glsl: Initial GLSL ES 3.x support (#65) --- CMakeLists.txt | 3 ++ mojoshader.c | 1 + mojoshader.h | 5 ++ mojoshader_internal.h | 9 ++++ mojoshader_opengl.c | 26 ++++++++- profiles/mojoshader_profile.h | 11 +++- profiles/mojoshader_profile_glsl.c | 84 +++++++++++++++++++++++++----- 7 files changed, 124 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 79198233..8c17d9df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,9 @@ ENDIF(NOT PROFILE_GLSL120) IF(NOT PROFILE_GLSLES) ADD_DEFINITIONS(-DSUPPORT_PROFILE_GLSLES=0) ENDIF(NOT PROFILE_GLSLES) +IF(NOT PROFILE_GLSLES3) + ADD_DEFINITIONS(-DSUPPORT_PROFILE_GLSLES3=0) +ENDIF(NOT PROFILE_GLSLES3) IF(NOT PROFILE_GLSL) ADD_DEFINITIONS(-DSUPPORT_PROFILE_GLSL=0) ENDIF(NOT PROFILE_GLSL) diff --git a/mojoshader.c b/mojoshader.c index ee37f164..e1628e24 100644 --- a/mojoshader.c +++ b/mojoshader.c @@ -333,6 +333,7 @@ static const struct { const char *from; const char *to; } profileMap[] = { { MOJOSHADER_PROFILE_GLSPIRV, MOJOSHADER_PROFILE_SPIRV }, { MOJOSHADER_PROFILE_GLSLES, MOJOSHADER_PROFILE_GLSL }, + { MOJOSHADER_PROFILE_GLSLES3, MOJOSHADER_PROFILE_GLSL }, { MOJOSHADER_PROFILE_GLSL120, MOJOSHADER_PROFILE_GLSL }, { MOJOSHADER_PROFILE_NV2, MOJOSHADER_PROFILE_ARB1 }, { MOJOSHADER_PROFILE_NV3, MOJOSHADER_PROFILE_ARB1 }, diff --git a/mojoshader.h b/mojoshader.h index 043ef4d6..13f945f1 100644 --- a/mojoshader.h +++ b/mojoshader.h @@ -709,6 +709,11 @@ typedef struct MOJOSHADER_parseData */ #define MOJOSHADER_PROFILE_GLSLES "glsles" +/* + * Profile string for GLSL ES: changes to GLSL output for ES 3.x compliance. + */ +#define MOJOSHADER_PROFILE_GLSLES3 "glsles3" + /* * Profile string for OpenGL ARB 1.0 shaders: GL_ARB_(vertex|fragment)_program. */ diff --git a/mojoshader_internal.h b/mojoshader_internal.h index 2a173e6d..d4dfe6da 100644 --- a/mojoshader_internal.h +++ b/mojoshader_internal.h @@ -159,6 +159,10 @@ typedef Uint64 uint64; #define SUPPORT_PROFILE_GLSLES 1 #endif +#ifndef SUPPORT_PROFILE_GLSLES3 +#define SUPPORT_PROFILE_GLSLES3 1 +#endif + #ifndef SUPPORT_PROFILE_ARB1 #define SUPPORT_PROFILE_ARB1 1 #endif @@ -191,6 +195,11 @@ typedef Uint64 uint64; #error glsles profile requires glsl profile. Fix your build. #endif +#if SUPPORT_PROFILE_GLSLES3 && !SUPPORT_PROFILE_GLSLES +#error glsles3 profile requires glsles profile. Fix your build. +#endif + + #if SUPPORT_PROFILE_GLSPIRV && !SUPPORT_PROFILE_SPIRV #error glspirv profile requires spirv profile. Fix your build. #endif diff --git a/mojoshader_opengl.c b/mojoshader_opengl.c index 2552a06a..9e7638b8 100644 --- a/mojoshader_opengl.c +++ b/mojoshader_opengl.c @@ -209,6 +209,7 @@ struct MOJOSHADER_glContext int have_opengl_2; // different entry points than ARB extensions. int have_opengl_3; // different extension query. int have_opengl_es; // different extension requirements + int have_opengl_es3; // different shader synxtax and attributes int have_GL_ARB_vertex_program; int have_GL_ARB_fragment_program; int have_GL_NV_vertex_program2_option; @@ -1413,6 +1414,11 @@ static void load_extensions(MOJOSHADER_glGetProcAddress lookup, void *d) } parse_opengl_version_str(str, &ctx->opengl_major, &ctx->opengl_minor); + if (opengl_version_atleast(3, 0) && ctx->have_opengl_es) + { + ctx->have_opengl_es3 = 1; + } + if ((ctx->have_opengl_3) && (opengl_version_atleast(3, 0))) { GLint i; @@ -1566,6 +1572,13 @@ static int valid_profile(const char *profile) } // else if #endif + #if SUPPORT_PROFILE_GLSLES + else if (strcmp(profile, MOJOSHADER_PROFILE_GLSLES3) == 0) + { + MUST_HAVE_GLSL(MOJOSHADER_PROFILE_GLSLES3, 3, 00); + } // else if + #endif + #if SUPPORT_PROFILE_GLSLES else if (strcmp(profile, MOJOSHADER_PROFILE_GLSLES) == 0) { @@ -1640,6 +1653,14 @@ int MOJOSHADER_glAvailableProfiles(MOJOSHADER_glGetProcAddress lookup, load_extensions(lookup, lookup_d); +#if SUPPORT_PROFILE_GLSLES3 + if (ctx->have_opengl_es3) + { + profs[0] = MOJOSHADER_PROFILE_GLSLES3; + return 1; + } // if +#endif + #if SUPPORT_PROFILE_GLSLES if (ctx->have_opengl_es) { @@ -1763,7 +1784,8 @@ MOJOSHADER_glContext *MOJOSHADER_glCreateContext(const char *profile, #if SUPPORT_PROFILE_GLSL else if ( (strcmp(profile, MOJOSHADER_PROFILE_GLSL) == 0) || (strcmp(profile, MOJOSHADER_PROFILE_GLSL120) == 0) || - (strcmp(profile, MOJOSHADER_PROFILE_GLSLES) == 0) ) + (strcmp(profile, MOJOSHADER_PROFILE_GLSLES) == 0) || + (strcmp(profile, MOJOSHADER_PROFILE_GLSLES3) == 0) ) { ctx->profileMaxUniforms = impl_GLSL_MaxUniforms; ctx->profileCompileShader = impl_GLSL_CompileShader; @@ -1780,7 +1802,7 @@ MOJOSHADER_glContext *MOJOSHADER_glCreateContext(const char *profile, ctx->profilePushSampler = impl_GLSL_PushSampler; ctx->profileMustPushConstantArrays = impl_GLSL_MustPushConstantArrays; ctx->profileMustPushSamplers = impl_GLSL_MustPushSamplers; - if (strcmp(profile, MOJOSHADER_PROFILE_GLSLES) == 0) + if (strcmp(profile, MOJOSHADER_PROFILE_GLSLES) == 0 || strcmp(profile, MOJOSHADER_PROFILE_GLSLES3) == 0) ctx->profileToggleProgramPointSize = impl_NOOP_ToggleProgramPointSize; else ctx->profileToggleProgramPointSize = impl_REAL_ToggleProgramPointSize; diff --git a/profiles/mojoshader_profile.h b/profiles/mojoshader_profile.h index 1b2c6ad6..acf6c88e 100644 --- a/profiles/mojoshader_profile.h +++ b/profiles/mojoshader_profile.h @@ -196,6 +196,9 @@ typedef struct Context #if SUPPORT_PROFILE_GLSLES int profile_supports_glsles; #endif +#if SUPPORT_PROFILE_GLSLES3 + int profile_supports_glsles3; +#endif #if SUPPORT_PROFILE_METAL int metal_need_header_common; @@ -236,8 +239,14 @@ typedef struct Context #define support_glsl120(ctx) (0) #endif +#if SUPPORT_PROFILE_GLSLES3 +#define support_glsles3(ctx) ((ctx)->profile_supports_glsles3) +#else +#define support_glsles3(ctx) (0) +#endif + #if SUPPORT_PROFILE_GLSLES -#define support_glsles(ctx) ((ctx)->profile_supports_glsles) +#define support_glsles(ctx) ((ctx)->profile_supports_glsles || support_glsles3(ctx)) #else #define support_glsles(ctx) (0) #endif diff --git a/profiles/mojoshader_profile_glsl.c b/profiles/mojoshader_profile_glsl.c index d46ec79f..319e3cbd 100644 --- a/profiles/mojoshader_profile_glsl.c +++ b/profiles/mojoshader_profile_glsl.c @@ -485,7 +485,7 @@ static void prepend_glsl_texlod_extensions(Context *ctx) // 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) + if (!ctx->glsl_generated_texlod_setup && !support_glsles3(ctx)) { ctx->glsl_generated_texlod_setup = 1; push_output(ctx, &ctx->preflight); @@ -534,6 +534,33 @@ void emit_GLSL_start(Context *ctx, const char *profilestr) } // else if #endif + #if SUPPORT_PROFILE_GLSLES3 + else if (strcmp(profilestr, MOJOSHADER_PROFILE_GLSLES3) == 0) + { + ctx->profile_supports_glsles3 = 1; + push_output(ctx, &ctx->preflight); + output_line(ctx, "#version 300 es"); + output_line(ctx, "#define texture2D texture"); + output_line(ctx, "#define texture2DLod textureLod"); + output_line(ctx, "#define texture2DProj textureProj"); + output_line(ctx, "#define texture2DGrad textureGrad"); + output_line(ctx, "#define texture2DProjGrad textureProjGrad"); + output_line(ctx, "#define texture3D texture"); + output_line(ctx, "#define texture3DLod textureLod"); + output_line(ctx, "#define textureCube texture"); + output_line(ctx, "#define textureCubeLod textureLod"); + output_line(ctx, "#define texture2DRect texture"); + output_line(ctx, "#define texture2DRectProj textureProj"); + output_line(ctx, "#define texture2DRectLod textureLod"); + if (shader_is_vertex(ctx)) + output_line(ctx, "precision highp float;"); + else + output_line(ctx, "precision mediump float;"); + output_line(ctx, "precision mediump int;"); + pop_output(ctx); + } // else if + #endif + #if SUPPORT_PROFILE_GLSLES else if (strcmp(profilestr, MOJOSHADER_PROFILE_GLSLES) == 0) { @@ -855,6 +882,8 @@ void emit_GLSL_attribute(Context *ctx, RegisterType regtype, int regnum, int flags) { // !!! FIXME: this function doesn't deal with write masks at all yet! + const char *qualifier_in; + const char *qualifier_out; const char *usage_str = NULL; const char *arrayleft = ""; const char *arrayright = ""; @@ -870,6 +899,17 @@ void emit_GLSL_attribute(Context *ctx, RegisterType regtype, int regnum, if (shader_is_vertex(ctx)) { + if (support_glsles3(ctx)) + { + qualifier_in = "in"; + qualifier_out = "out"; + } + else + { + qualifier_in = "attribute"; + qualifier_out = "varying"; + } + // pre-vs3 output registers. // these don't ever happen in DCL opcodes, I think. Map to vs_3_* // output registers. @@ -920,7 +960,7 @@ void emit_GLSL_attribute(Context *ctx, RegisterType regtype, int regnum, if (regtype == REG_TYPE_INPUT) { push_output(ctx, &ctx->globals); - output_line(ctx, "attribute vec4 %s;", var); + output_line(ctx, "%s vec4 %s;", qualifier_in, var); pop_output(ctx); } // if @@ -944,7 +984,7 @@ void emit_GLSL_attribute(Context *ctx, RegisterType regtype, int regnum, push_output(ctx, &ctx->globals); #if SUPPORT_PROFILE_GLSLES if (support_glsles(ctx)) - output_line(ctx, "varying highp float io_%i_%i;", usage, index); + output_line(ctx, "%s highp float io_%i_%i;", qualifier_out, usage, index); else #endif output_line(ctx, "varying float io_%i_%i;", usage, index); @@ -982,7 +1022,7 @@ void emit_GLSL_attribute(Context *ctx, RegisterType regtype, int regnum, push_output(ctx, &ctx->globals); #if SUPPORT_PROFILE_GLSLES if (support_glsles(ctx)) - output_line(ctx, "varying highp float io_%i_%i;", usage, index); + output_line(ctx, "%s highp float io_%i_%i;", qualifier_out, usage, index); else #endif output_line(ctx, "varying float io_%i_%i;", usage, index); @@ -1016,7 +1056,7 @@ void emit_GLSL_attribute(Context *ctx, RegisterType regtype, int regnum, { #if SUPPORT_PROFILE_GLSLES if (support_glsles(ctx)) - output_line(ctx, "varying highp vec4 io_%i_%i;", usage, index); + output_line(ctx, "%s highp vec4 io_%i_%i;", qualifier_out, usage, index); else #endif output_line(ctx, "varying vec4 io_%i_%i;", usage, index); @@ -1038,6 +1078,11 @@ void emit_GLSL_attribute(Context *ctx, RegisterType regtype, int regnum, else if (shader_is_pixel(ctx)) { + if (support_glsles3(ctx)) + qualifier_in = "in"; + else + qualifier_in = "varying"; + // samplers DCLs get handled in emit_GLSL_sampler(). if (flags & MOD_CENTROID) // !!! FIXME @@ -1048,14 +1093,29 @@ void emit_GLSL_attribute(Context *ctx, RegisterType regtype, int regnum, if (regtype == REG_TYPE_COLOROUT) { - if (!ctx->have_multi_color_outputs) - usage_str = "gl_FragColor"; // maybe faster? + // gl_FragColor/FragData were deprecated in favor of manually + // defining your own output variables, GLSL ES 3.x enforces the new + // syntax, so let's use it. + if (support_glsles3(ctx)) + { + usage_str = "_gl_FragData"; + snprintf(index_str, sizeof (index_str), "_%u", (uint) regnum ); + + push_output(ctx, &ctx->globals); + output_line(ctx, "layout(location = %u) out highp vec4 %s%s;", regnum, usage_str, index_str); + pop_output(ctx); + } else { - snprintf(index_str, sizeof (index_str), "%u", (uint) regnum); - usage_str = "gl_FragData"; - arrayleft = "["; - arrayright = "]"; + if (!ctx->have_multi_color_outputs) + usage_str = "gl_FragColor"; // maybe faster? + else + { + snprintf(index_str, sizeof (index_str), "%u", (uint) regnum); + usage_str = "gl_FragData"; + arrayleft = "["; + arrayright = "]"; + } // else } // else } // if @@ -1145,7 +1205,7 @@ void emit_GLSL_attribute(Context *ctx, RegisterType regtype, int regnum, { #if SUPPORT_PROFILE_GLSLES if (support_glsles(ctx)) - output_line(ctx, "varying highp vec4 io_%i_%i;", usage, index); + output_line(ctx, "%s highp vec4 io_%i_%i;", qualifier_in, usage, index); else #endif output_line(ctx, "varying vec4 io_%i_%i;", usage, index);