diff --git a/core/rend/gl4/abuffer.cpp b/core/rend/gl4/abuffer.cpp index c925d223d..808c6d1de 100644 --- a/core/rend/gl4/abuffer.cpp +++ b/core/rend/gl4/abuffer.cpp @@ -29,13 +29,11 @@ static GLuint g_quadBuffer; static GLuint g_quadIndexBuffer; static GLuint g_quadVertexArray; -#define MAX_PIXELS_PER_FRAGMENT "32" +constexpr int MAX_PIXELS_PER_FRAGMENT = 32; -static const char *final_shader_source = SHADER_HEADER -"#define MAX_PIXELS_PER_FRAGMENT " MAX_PIXELS_PER_FRAGMENT -R"( +static const char *final_shader_source = R"( layout(binding = 0) uniform sampler2D tex; -uniform highp float shade_scale_factor; +uniform float shade_scale_factor; out vec4 FragColor; @@ -178,8 +176,7 @@ void main(void) } )"; -static const char *clear_shader_source = SHADER_HEADER -R"( +static const char *clear_shader_source = R"( void main(void) { ivec2 coords = ivec2(gl_FragCoord.xy); @@ -192,11 +189,7 @@ void main(void) } )"; -static const char *tr_modvol_shader_source = SHADER_HEADER -"#define MAX_PIXELS_PER_FRAGMENT " MAX_PIXELS_PER_FRAGMENT -R"( -#define MV_MODE %d - +static const char *tr_modvol_shader_source = R"( // Must match ModifierVolumeMode enum values #define MV_XOR 0 #define MV_OR 1 @@ -242,10 +235,8 @@ void main(void) } )"; -static const char* VertexShaderSource = -R"(#version 430 - -in highp vec3 in_pos; +static const char* VertexShaderSource = R"( +in vec3 in_pos; void main() { @@ -301,17 +292,33 @@ void initABuffer() glCheck(); } + OpenGl4Source vertexShader; + vertexShader.addSource(VertexShaderSource); if (g_abuffer_final_shader.program == 0) - gl4CompilePipelineShader(&g_abuffer_final_shader, final_shader_source, VertexShaderSource); + { + OpenGl4Source finalShader; + finalShader.addConstant("MAX_PIXELS_PER_FRAGMENT", MAX_PIXELS_PER_FRAGMENT) + .addSource(ShaderHeader) + .addSource(final_shader_source); + gl4CompilePipelineShader(&g_abuffer_final_shader, finalShader.generate().c_str(), vertexShader.generate().c_str()); + } if (g_abuffer_clear_shader.program == 0) - gl4CompilePipelineShader(&g_abuffer_clear_shader, clear_shader_source, VertexShaderSource); + { + OpenGl4Source clearShader; + clearShader.addSource(ShaderHeader) + .addSource(clear_shader_source); + gl4CompilePipelineShader(&g_abuffer_clear_shader, clearShader.generate().c_str(), vertexShader.generate().c_str()); + } if (g_abuffer_tr_modvol_shaders[0].program == 0) { - char source[16384]; + OpenGl4Source modVolShader; + modVolShader.addConstant("MAX_PIXELS_PER_FRAGMENT", MAX_PIXELS_PER_FRAGMENT) + .addSource(ShaderHeader) + .addSource(tr_modvol_shader_source); for (int mode = 0; mode < ModeCount; mode++) { - sprintf(source, tr_modvol_shader_source, mode); - gl4CompilePipelineShader(&g_abuffer_tr_modvol_shaders[mode], source, VertexShaderSource); + modVolShader.setConstant("MV_MODE", mode); + gl4CompilePipelineShader(&g_abuffer_tr_modvol_shaders[mode], modVolShader.generate().c_str(), vertexShader.generate().c_str()); } } if (g_quadBuffer == 0) diff --git a/core/rend/gl4/gl4.h b/core/rend/gl4/gl4.h index 07f633456..e58b8cdab 100755 --- a/core/rend/gl4/gl4.h +++ b/core/rend/gl4/gl4.h @@ -89,7 +89,7 @@ extern int max_image_width; extern int max_image_height; extern const char *gl4PixelPipelineShader; -bool gl4CompilePipelineShader(gl4PipelineShader* s, const char *pixel_source = gl4PixelPipelineShader, const char *vertex_source = NULL); +bool gl4CompilePipelineShader(gl4PipelineShader* s, const char *pixel_source = nullptr, const char *vertex_source = nullptr); void initABuffer(); void termABuffer(); @@ -106,33 +106,37 @@ extern GLuint geom_fbo; extern GLuint texSamplers[2]; extern GLuint depth_fbo; -#define SHADER_HEADER "#version 430 \n\ -\n\ -layout(r32ui, binding = 4) uniform coherent restrict uimage2D abufferPointerImg; \n\ -\n\ -layout(binding = 0, offset = 0) uniform atomic_uint buffer_index; \n\ -\n" \ -OIT_POLY_PARAM \ -"\ -layout (binding = 0, std430) coherent restrict buffer PixelBuffer { \n\ - Pixel pixels[]; \n\ -}; \n\ -\n\ -uint getNextPixelIndex() \n\ -{ \n\ - uint index = atomicCounterIncrement(buffer_index); \n\ - if (index >= pixels.length()) \n\ - // Buffer overflow \n\ - discard; \n\ - \n\ - return index; \n\ -} \n\ -\n\ -layout (binding = 1, std430) readonly buffer TrPolyParamBuffer { \n\ - PolyParam tr_poly_params[]; \n\ -}; \n\ - \n\ -" +static const char* ShaderHeader = R"( +layout(r32ui, binding = 4) uniform coherent restrict uimage2D abufferPointerImg; + +layout(binding = 0, offset = 0) uniform atomic_uint buffer_index; +)" +OIT_POLY_PARAM +R"( +layout (binding = 0, std430) coherent restrict buffer PixelBuffer { + Pixel pixels[]; +}; + +uint getNextPixelIndex() +{ + uint index = atomicCounterIncrement(buffer_index); + if (index >= pixels.length()) + // Buffer overflow + discard; + + return index; +} + +layout (binding = 1, std430) readonly buffer TrPolyParamBuffer { + PolyParam tr_poly_params[]; +}; +)"; + +class OpenGl4Source : public ShaderSource +{ +public: + OpenGl4Source() : ShaderSource("#version 430") {} +}; void gl4SetupMainVBO(); void gl4SetupModvolVBO(); diff --git a/core/rend/gl4/gles.cpp b/core/rend/gl4/gles.cpp index 1ed65fb32..66bd7db78 100644 --- a/core/rend/gl4/gles.cpp +++ b/core/rend/gl4/gles.cpp @@ -23,9 +23,7 @@ //Fragment and vertex shaders code -static const char* VertexShaderSource = R"(#version 140 -#define pp_Gouraud %d - +static const char* VertexShaderSource = R"( #if pp_Gouraud == 0 #define INTERPOLATION flat #else @@ -67,24 +65,7 @@ void main() } )"; -const char* gl4PixelPipelineShader = SHADER_HEADER -R"( -#define cp_AlphaTest %d -#define pp_ClipInside %d -#define pp_UseAlpha %d -#define pp_Texture %d -#define pp_IgnoreTexA %d -#define pp_ShadInstr %d -#define pp_Offset %d -#define pp_FogCtrl %d -#define pp_TwoVolumes %d -#define pp_Gouraud %d -#define pp_BumpMap %d -#define FogClamping %d -#define pp_Palette %d -#define NOUVEAU %d -#define PASS %d - +const char* gl4PixelPipelineShader = R"( #define PI 3.1415926 #define PASS_DEPTH 0 @@ -166,7 +147,7 @@ vec4 fog_clamp(vec4 col) vec4 palettePixel(sampler2D tex, vec2 coords) { int color_idx = int(floor(texture(tex, coords).r * 255.0 + 0.5)) + palette_index; - ivec2 c = ivec2(color_idx %% 32, color_idx / 32); + ivec2 c = ivec2(color_idx % 32, color_idx / 32); return texelFetch(palette, c, 0); } @@ -393,36 +374,62 @@ void main() } )"; -static const char* ModifierVolumeShader = SHADER_HEADER -R"( +static const char* ModifierVolumeShader = R"( void main() { setFragDepth(); } )"; +class Vertex4Source : public OpenGl4Source +{ +public: + Vertex4Source(bool gouraud) : OpenGl4Source() { + addConstant("pp_Gouraud", gouraud); + + addSource(VertexShaderSource); + } +}; + +class Fragment4ShaderSource : public OpenGl4Source +{ +public: + Fragment4ShaderSource(const gl4PipelineShader* s) : OpenGl4Source() + { + addConstant("cp_AlphaTest", s->cp_AlphaTest); + addConstant("pp_ClipInside", s->pp_InsideClipping); + addConstant("pp_UseAlpha", s->pp_UseAlpha); + addConstant("pp_Texture", s->pp_Texture); + addConstant("pp_IgnoreTexA", s->pp_IgnoreTexA); + addConstant("pp_ShadInstr", s->pp_ShadInstr); + addConstant("pp_Offset", s->pp_Offset); + addConstant("pp_FogCtrl", s->pp_FogCtrl); + addConstant("pp_TwoVolumes", s->pp_TwoVolumes); + addConstant("pp_Gouraud", s->pp_Gouraud); + addConstant("pp_BumpMap", s->pp_BumpMap); + addConstant("FogClamping", s->fog_clamping); + addConstant("pp_Palette", s->palette); + addConstant("NOUVEAU", gl.mesa_nouveau); + addConstant("PASS", (int)s->pass); + + addSource(ShaderHeader); + addSource(gl4PixelPipelineShader); + } +}; + gl4_ctx gl4; struct gl4ShaderUniforms_t gl4ShaderUniforms; int max_image_width; int max_image_height; -bool gl4CompilePipelineShader( gl4PipelineShader* s, const char *pixel_source /* = PixelPipelineShader */, const char *vertex_source /* = NULL */) +bool gl4CompilePipelineShader(gl4PipelineShader* s, const char *fragment_source /* = nullptr */, const char *vertex_source /* = nullptr */) { - char vshader[16384]; + Vertex4Source vertexSource(s->pp_Gouraud); + Fragment4ShaderSource fragmentSource(s); - sprintf(vshader, vertex_source == NULL ? VertexShaderSource : vertex_source, s->pp_Gouraud); - - char pshader[16384]; - - sprintf(pshader, pixel_source, - s->cp_AlphaTest, s->pp_InsideClipping, s->pp_UseAlpha, - s->pp_Texture, s->pp_IgnoreTexA, s->pp_ShadInstr, s->pp_Offset, s->pp_FogCtrl, - s->pp_TwoVolumes, s->pp_Gouraud, s->pp_BumpMap, s->fog_clamping, s->palette, - gl.mesa_nouveau, - (int)s->pass); - - s->program = gl_CompileAndLink(vshader, pshader); + s->program = gl_CompileAndLink(vertex_source != nullptr ? vertex_source : vertexSource.generate().c_str(), + fragment_source != nullptr ? fragment_source : fragmentSource.generate().c_str()); //setup texture 0 as the input for the shader GLint gu = glGetUniformLocation(s->program, "tex0"); @@ -524,11 +531,13 @@ static void create_modvol_shader() { if (gl4.modvol_shader.program != 0) return; - char vshader[16384]; - sprintf(vshader, VertexShaderSource, 1); + Vertex4Source vertexShader(true); + OpenGl4Source fragmentShader; + fragmentShader.addSource(ShaderHeader) + .addSource(ModifierVolumeShader); - gl4.modvol_shader.program=gl_CompileAndLink(vshader, ModifierVolumeShader); - gl4.modvol_shader.normal_matrix = glGetUniformLocation(gl4.modvol_shader.program, "normal_matrix"); + gl4.modvol_shader.program = gl_CompileAndLink(vertexShader.generate().c_str(), fragmentShader.generate().c_str()); + gl4.modvol_shader.normal_matrix = glGetUniformLocation(gl4.modvol_shader.program, "normal_matrix"); } static bool gl_create_resources() diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index 07d1f889d..96810f6f6 100644 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -29,11 +29,7 @@ //Fragment and vertex shaders code -static const char* VertexShaderSource = "%s" -VTX_SHADER_COMPAT -R"( -#define pp_Gouraud %d - +static const char* GouraudSource = R"( #if TARGET_GL == GL3 || TARGET_GL == GLES3 #if pp_Gouraud == 0 #define INTERPOLATION flat @@ -43,7 +39,9 @@ R"( #else #define INTERPOLATION #endif +)"; +static const char* VertexShaderSource = R"( /* Vertex constants*/ uniform highp vec4 depth_scale; uniform highp mat4 normal_matrix; @@ -80,33 +78,7 @@ void main() } )"; -const char* PixelPipelineShader = "%s" -PIX_SHADER_COMPAT -R"( -#define cp_AlphaTest %d -#define pp_ClipInside %d -#define pp_UseAlpha %d -#define pp_Texture %d -#define pp_IgnoreTexA %d -#define pp_ShadInstr %d -#define pp_Offset %d -#define pp_FogCtrl %d -#define pp_Gouraud %d -#define pp_BumpMap %d -#define FogClamping %d -#define pp_TriLinear %d -#define pp_Palette %d - -#if TARGET_GL == GL3 || TARGET_GL == GLES3 -#if pp_Gouraud == 0 -#define INTERPOLATION flat -#else -#define INTERPOLATION smooth -#endif -#else -#define INTERPOLATION -#endif - +const char* PixelPipelineShader = R"( #define PI 3.1415926 /* Shader program params*/ @@ -164,7 +136,7 @@ lowp vec4 palettePixel(highp vec2 coords) highp vec2 c = vec2((mod(float(color_idx), 32.0) * 2.0 + 1.0) / 64.0, (float(color_idx / 32) * 2.0 + 1.0) / 64.0); return texture(palette, c); #else - highp ivec2 c = ivec2(color_idx %% 32, color_idx / 32); + highp ivec2 c = ivec2(color_idx % 32, color_idx / 32); return texelFetch(palette, c, 0); #endif } @@ -267,10 +239,9 @@ void main() } )"; -static const char* ModifierVolumeShader = "%s" -PIX_SHADER_COMPAT -R"( +static const char* ModifierVolumeShader = R"( uniform lowp float sp_ShaderColor; + /* Vertex input*/ void main() { @@ -282,9 +253,7 @@ void main() } )"; -const char* OSD_VertexShader = "%s" -VTX_SHADER_COMPAT -R"( +const char* OSD_VertexShader = R"( uniform highp vec4 scale; in highp vec4 in_pos; @@ -307,9 +276,7 @@ void main() } )"; -const char* OSD_Shader = "%s" -PIX_SHADER_COMPAT -R"( +const char* OSD_Shader = R"( in lowp vec4 vtx_base; in mediump vec2 vtx_uv; @@ -632,23 +599,49 @@ PipelineShader *GetProgram(bool cp_AlphaTest, bool pp_InsideClipping, return shader; } -bool CompilePipelineShader( PipelineShader* s) +class VertexSource : public OpenGlSource { - char vshader[8192]; +public: + VertexSource(bool gouraud) : OpenGlSource() { + addConstant("pp_Gouraud", gouraud); - int rc = sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, s->pp_Gouraud); - verify(rc + 1 <= (int)sizeof(vshader)); + addSource(VertexCompatShader); + addSource(GouraudSource); + addSource(VertexShaderSource); + } +}; - char pshader[8192]; +class FragmentShaderSource : public OpenGlSource +{ +public: + FragmentShaderSource(const PipelineShader* s) : OpenGlSource() + { + addConstant("cp_AlphaTest", s->cp_AlphaTest); + addConstant("pp_ClipInside", s->pp_InsideClipping); + addConstant("pp_UseAlpha", s->pp_UseAlpha); + addConstant("pp_Texture", s->pp_Texture); + addConstant("pp_IgnoreTexA", s->pp_IgnoreTexA); + addConstant("pp_ShadInstr", s->pp_ShadInstr); + addConstant("pp_Offset", s->pp_Offset); + addConstant("pp_FogCtrl", s->pp_FogCtrl); + addConstant("pp_Gouraud", s->pp_Gouraud); + addConstant("pp_BumpMap", s->pp_BumpMap); + addConstant("FogClamping", s->fog_clamping); + addConstant("pp_TriLinear", s->trilinear); + addConstant("pp_Palette", s->palette); - rc = sprintf(pshader,PixelPipelineShader, gl.glsl_version_header, gl.gl_version, - s->cp_AlphaTest,s->pp_InsideClipping,s->pp_UseAlpha, - s->pp_Texture,s->pp_IgnoreTexA,s->pp_ShadInstr,s->pp_Offset,s->pp_FogCtrl, s->pp_Gouraud, s->pp_BumpMap, - s->fog_clamping, s->trilinear, s->palette); - verify(rc + 1 <= (int)sizeof(pshader)); + addSource(PixelCompatShader); + addSource(GouraudSource); + addSource(PixelPipelineShader); + } +}; - s->program=gl_CompileAndLink(vshader, pshader); +bool CompilePipelineShader(PipelineShader* s) +{ + VertexSource vertexSource(s->pp_Gouraud); + FragmentShaderSource fragmentSource(s); + s->program = gl_CompileAndLink(vertexSource.generate().c_str(), fragmentSource.generate().c_str()); //setup texture 0 as the input for the shader GLint gu = glGetUniformLocation(s->program, "tex"); @@ -743,13 +736,14 @@ static void SetupOSDVBO() void gl_load_osd_resources() { - char vshader[8192]; - char fshader[8192]; + OpenGlSource vertexSource; + vertexSource.addSource(VertexCompatShader) + .addSource(OSD_VertexShader); + OpenGlSource fragmentSource; + fragmentSource.addSource(PixelCompatShader) + .addSource(OSD_Shader); - sprintf(vshader, OSD_VertexShader, gl.glsl_version_header, gl.gl_version); - sprintf(fshader, OSD_Shader, gl.glsl_version_header, gl.gl_version); - - gl.OSD_SHADER.program = gl_CompileAndLink(vshader, fshader); + gl.OSD_SHADER.program = gl_CompileAndLink(vertexSource.generate().c_str(), fragmentSource.generate().c_str()); gl.OSD_SHADER.scale = glGetUniformLocation(gl.OSD_SHADER.program, "scale"); glUniform1i(glGetUniformLocation(gl.OSD_SHADER.program, "tex"), 0); //bind osd texture to slot 0 @@ -794,12 +788,13 @@ static void create_modvol_shader() { if (gl.modvol_shader.program != 0) return; - char vshader[8192]; - sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, 1); - char fshader[8192]; - sprintf(fshader, ModifierVolumeShader, gl.glsl_version_header, gl.gl_version); + VertexSource vertexShader(true); - gl.modvol_shader.program = gl_CompileAndLink(vshader, fshader); + OpenGlSource fragmentShader; + fragmentShader.addSource(PixelCompatShader) + .addSource(ModifierVolumeShader); + + gl.modvol_shader.program = gl_CompileAndLink(vertexShader.generate().c_str(), fragmentShader.generate().c_str()); gl.modvol_shader.normal_matrix = glGetUniformLocation(gl.modvol_shader.program, "normal_matrix"); gl.modvol_shader.sp_ShaderColor = glGetUniformLocation(gl.modvol_shader.program, "sp_ShaderColor"); gl.modvol_shader.depth_scale = glGetUniformLocation(gl.modvol_shader.program, "depth_scale"); diff --git a/core/rend/gles/gles.h b/core/rend/gles/gles.h index e4e7fd1d9..1cf0387e4 100755 --- a/core/rend/gles/gles.h +++ b/core/rend/gles/gles.h @@ -5,6 +5,7 @@ #include "wsi/gl_context.h" #include "glcache.h" #include "postprocess.h" +#include "rend/shader_util.h" #include #include @@ -297,46 +298,53 @@ void initQuad(); void termQuad(); void drawQuad(GLuint texId, bool rotate = false, bool swapY = false); -#define SHADER_COMPAT " \n\ -#define TARGET_GL %s \n\ - \n\ -#define GLES2 0 \n\ -#define GLES3 1 \n\ -#define GL2 2 \n\ -#define GL3 3 \n\ - \n\ -#if TARGET_GL == GL2 \n\ -#define highp \n\ -#define lowp \n\ -#define mediump \n\ -#endif \n\ -#if TARGET_GL == GLES3 \n\ -out highp vec4 FragColor; \n\ -#define gl_FragColor FragColor \n\ -#define FOG_CHANNEL a \n\ -#elif TARGET_GL == GL3 \n\ -out highp vec4 FragColor; \n\ -#define gl_FragColor FragColor \n\ -#define FOG_CHANNEL r \n\ -#else \n\ -#define texture texture2D \n\ -#define FOG_CHANNEL a \n\ -#endif \n\ - \n\ -" +static const char* ShaderCompatSource = R"( +#define GLES2 0 +#define GLES3 1 +#define GL2 2 +#define GL3 3 + +#if TARGET_GL == GL2 +#define highp +#define lowp +#define mediump +#endif +#if TARGET_GL == GLES3 +out highp vec4 FragColor; +#define gl_FragColor FragColor +#define FOG_CHANNEL a +#elif TARGET_GL == GL3 +out highp vec4 FragColor; +#define gl_FragColor FragColor +#define FOG_CHANNEL r +#else +#define texture texture2D +#define FOG_CHANNEL a +#endif +)"; -#define VTX_SHADER_COMPAT SHADER_COMPAT \ -"#if TARGET_GL == GLES2 || TARGET_GL == GL2 \n\ -#define in attribute \n\ -#define out varying \n\ -#endif \n\ -" +static const char *VertexCompatShader = R"( +#if TARGET_GL == GLES2 || TARGET_GL == GL2 +#define in attribute +#define out varying +#endif +)"; + +static const char *PixelCompatShader = R"( +#if TARGET_GL == GLES2 || TARGET_GL == GL2 +#define in varying +#endif +)"; + +class OpenGlSource : public ShaderSource +{ +public: + OpenGlSource() : ShaderSource(gl.glsl_version_header) { + addConstant("TARGET_GL", gl.gl_version); + addSource(ShaderCompatSource); + } +}; -#define PIX_SHADER_COMPAT SHADER_COMPAT \ -"#if TARGET_GL == GLES2 || TARGET_GL == GL2 \n\ -#define in varying \n\ -#endif \n\ -" #ifdef LIBRETRO extern "C" struct retro_hw_render_callback hw_render; void termVmuLightgun(); diff --git a/core/rend/gles/postprocess.cpp b/core/rend/gles/postprocess.cpp index 0e18d88b7..8851914f3 100644 --- a/core/rend/gles/postprocess.cpp +++ b/core/rend/gles/postprocess.cpp @@ -23,21 +23,8 @@ PostProcessor postProcessor; -static const char* VertexShaderSource = R"(%s -#define TARGET_GL %s - -#define GLES2 0 -#define GLES3 1 -#define GL2 2 -#define GL3 3 - -#if TARGET_GL == GL3 || TARGET_GL == GLES3 -#define COMPAT_VARYING in -#else -#define COMPAT_VARYING attribute -#endif - -COMPAT_VARYING vec3 in_pos; +static const char* VertexShaderSource = R"( +in vec3 in_pos; void main() { @@ -45,32 +32,11 @@ void main() } )"; -static const char* FragmentShaderSource = R"(%s -#define TARGET_GL %s -#define DITHERING %d -#define INTERLACED %d -#define VGASIGNAL %d +static const char* FragmentShaderSource = R"( #define LUMBOOST 0 -#define GLES2 0 -#define GLES3 1 -#define GL2 2 -#define GL3 3 - #if TARGET_GL == GLES2 || TARGET_GL == GLES3 -#ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; -#else -precision mediump float; -#endif -#endif - -#if TARGET_GL == GL3 || TARGET_GL == GLES3 -#define COMPAT_TEXTURE texture -out vec4 FragColor; -#else -#define FragColor gl_FragColor -#define COMPAT_TEXTURE texture2D #endif uniform int FrameCount; @@ -102,7 +68,7 @@ void main() vec2 texcoord2 = vTexCoord; texcoord2.x *= float(TextureSize.x); texcoord2.y *= float(TextureSize.y); - vec4 color = COMPAT_TEXTURE(Source, texcoord); + vec4 color = texture(Source, texcoord); float fc = mod(float(FrameCount), 2.0); #if INTERLACED == 1 @@ -117,7 +83,7 @@ void main() for (bl=0;bl=3) e=0.35; texcoord4.x -= (tap / 640); - ble.rgb += (COMPAT_TEXTURE(Source, texcoord4).rgb * e) / (taps/(bl+1)); + ble.rgb += (texture(Source, texcoord4).rgb * e) / (taps/(bl+1)); } color.rgb += ble.rgb * 0.015; @@ -217,13 +183,18 @@ public: private: void compile(bool dither, bool interlaced, bool vga) { - char vshader[16384]; - sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version); + OpenGlSource vertexShader; + vertexShader.addSource(VertexCompatShader) + .addSource(VertexShaderSource); - char pshader[16384]; - sprintf(pshader, FragmentShaderSource, gl.glsl_version_header, gl.gl_version, (int)dither, (int)interlaced, (int)vga); + OpenGlSource fragmentShader; + fragmentShader.addConstant("DITHERING", dither) + .addConstant("INTERLACED", interlaced) + .addConstant("VGASIGNAL", vga) + .addSource(PixelCompatShader) + .addSource(FragmentShaderSource); - program = gl_CompileAndLink(vshader, pshader); + program = gl_CompileAndLink(vertexShader.generate().c_str(), fragmentShader.generate().c_str()); //setup texture 0 as the input for the shader GLint gu = glGetUniformLocation(program, "Texture"); diff --git a/core/rend/gles/quad.cpp b/core/rend/gles/quad.cpp index 4ee4ea930..df5412200 100644 --- a/core/rend/gles/quad.cpp +++ b/core/rend/gles/quad.cpp @@ -18,11 +18,7 @@ */ #include "gles.h" -static const char* VertexShader = "%s" -VTX_SHADER_COMPAT -R"( -#define ROTATE %d - +static const char* VertexShader = R"( in highp vec3 in_pos; in mediump vec2 in_uv; out mediump vec2 vtx_uv; @@ -38,9 +34,7 @@ void main() } )"; -static const char* FragmentShader = "%s" -PIX_SHADER_COMPAT -R"( +static const char* FragmentShader = R"( in mediump vec2 vtx_uv; uniform sampler2D tex; @@ -82,24 +76,23 @@ void initQuad() { if (shader == 0) { - size_t shaderLength = strlen(FragmentShader) * 2; - char *frag = new char[shaderLength]; - snprintf(frag, shaderLength, FragmentShader, gl.glsl_version_header, gl.gl_version); + OpenGlSource fragmentShader; + fragmentShader.addSource(PixelCompatShader) + .addSource(FragmentShader); + OpenGlSource vertexShader; + vertexShader.addConstant("ROTATE", 0) + .addSource(VertexCompatShader) + .addSource(VertexShader); - shaderLength = strlen(VertexShader) * 2; - char *vtx = new char[shaderLength]; - snprintf(vtx, shaderLength, VertexShader, gl.glsl_version_header, gl.gl_version, 0); - shader = gl_CompileAndLink(vtx, frag); + const std::string fragmentGlsl = fragmentShader.generate(); + shader = gl_CompileAndLink(vertexShader.generate().c_str(), fragmentGlsl.c_str()); GLint tex = glGetUniformLocation(shader, "tex"); glUniform1i(tex, 0); // texture 0 - snprintf(vtx, shaderLength, VertexShader, gl.glsl_version_header, gl.gl_version, 1); - rot90shader = gl_CompileAndLink(vtx, frag); + vertexShader.setConstant("ROTATE", 1); + rot90shader = gl_CompileAndLink(vertexShader.generate().c_str(), fragmentGlsl.c_str()); tex = glGetUniformLocation(rot90shader, "tex"); glUniform1i(tex, 0); // texture 0 - - delete [] vtx; - delete [] frag; } #ifndef GLES2 if (quadVertexArray == 0 && gl.gl_major >= 3) diff --git a/core/rend/shader_util.h b/core/rend/shader_util.h new file mode 100644 index 000000000..54fb09d07 --- /dev/null +++ b/core/rend/shader_util.h @@ -0,0 +1,82 @@ +/* + Copyright 2021 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#pragma once +#include +#include + +class ShaderSource +{ +public: + ShaderSource(const std::string& header = "") : header(header) {} + + ShaderSource& setHeader(const std::string& source) { + header = source; + return *this; + } + + ShaderSource& addSource(const std::string& source) { + segments.push_back(source); + return *this; + } + + ShaderSource& addConstant(const std::string& name, const std::string& value = "0") { + constants.emplace_back(name, value); + return *this; + } + ShaderSource& addConstant(const std::string& name, int value) { + addConstant(name, std::to_string(value)); + return *this; + } + ShaderSource& setConstant(const std::string& name, const std::string& value) { + for (Constant& c : constants) + if (c.name == name) + { + c.value = value; + return *this; + } + return addConstant(name, value); + } + ShaderSource& setConstant(const std::string& name, int value) { + setConstant(name, std::to_string(value)); + return *this; + } + + std::string generate() + { + std::string result(header + "\n"); + for (const Constant& c : constants) + result += "#define " + c.name + " " + c.value + "\n"; + for (const std::string& s : segments) + result += s + "\n"; + return result; + } + +private: + struct Constant + { + Constant(const std::string& name, const std::string& defaultValue = "0") : name(name), value(defaultValue) {} + + const std::string name; + std::string value; + }; + + std::string header; + std::vector segments; + std::vector constants; +}; diff --git a/core/rend/vulkan/oit/oit_shaders.cpp b/core/rend/vulkan/oit/oit_shaders.cpp index cf8ecaef1..a85eeb2f2 100644 --- a/core/rend/vulkan/oit/oit_shaders.cpp +++ b/core/rend/vulkan/oit/oit_shaders.cpp @@ -22,16 +22,7 @@ #include "../compiler.h" #include "rend/gl4/glsl.h" -static const char OITVertexShaderSource[] = R"(#version 450 - -#define pp_Gouraud %d - -#if pp_Gouraud == 0 -#define INTERPOLATION flat -#else -#define INTERPOLATION smooth -#endif - +static const char OITVertexShaderSource[] = R"( layout (std140, set = 0, binding = 0) uniform VertexShaderUniforms { mat4 normal_matrix; @@ -68,8 +59,7 @@ void main() } )"; -static const char OITShaderHeader[] = R"(#version 450 - +static const char OITShaderHeader[] = R"( layout (std140, set = 0, binding = 1) uniform FragmentShaderUniforms { vec4 colorClampMin; @@ -111,20 +101,6 @@ layout (set = 0, binding = 3, std430) readonly buffer TrPolyParamBuffer { )"; static const char OITFragmentShaderSource[] = R"( -#define cp_AlphaTest %d -#define pp_ClipInside %d -#define pp_UseAlpha %d -#define pp_Texture %d -#define pp_IgnoreTexA %d -#define pp_ShadInstr %d -#define pp_Offset %d -#define pp_FogCtrl %d -#define pp_TwoVolumes %d -#define pp_Gouraud %d -#define pp_BumpMap %d -#define ColorClamping %d -#define pp_Palette %d -#define PASS %d #define PI 3.1415926 #define PASS_DEPTH 0 @@ -142,12 +118,6 @@ layout (location = 0) out vec4 FragColor; #define IF(x) #endif -#if pp_Gouraud == 0 -#define INTERPOLATION flat -#else -#define INTERPOLATION smooth -#endif - layout (push_constant) uniform pushBlock { vec4 clipTest; @@ -444,18 +414,15 @@ void main() )"; static const char OITModifierVolumeShader[] = R"( - void main() { setFragDepth(); } )"; -#define MAX_PIXELS_PER_FRAGMENT "32" +constexpr int MAX_PIXELS_PER_FRAGMENT = 32; -static const char OITFinalShaderSource[] = -"#define MAX_PIXELS_PER_FRAGMENT " MAX_PIXELS_PER_FRAGMENT -R"( +static const char OITFinalShaderSource[] = R"( layout (input_attachment_index = 0, set = 2, binding = 0) uniform subpassInput tex; layout (location = 0) out vec4 FragColor; @@ -609,11 +576,7 @@ void main(void) } )"; -static const char OITTranslucentModvolShaderSource[] = -"#define MAX_PIXELS_PER_FRAGMENT " MAX_PIXELS_PER_FRAGMENT -R"( -#define MV_MODE %d - +static const char OITTranslucentModvolShaderSource[] = R"( // Must match ModifierVolumeMode enum values #define MV_XOR 0 #define MV_OR 1 @@ -657,8 +620,7 @@ void main() } )"; -static const char OITFinalVertexShaderSource[] = R"(#version 430 - +static const char OITFinalVertexShaderSource[] = R"( layout (location = 0) in vec3 in_pos; void main() @@ -671,57 +633,75 @@ extern const char ModVolVertexShaderSource[]; vk::UniqueShaderModule OITShaderManager::compileShader(const VertexShaderParams& params) { - char buf[sizeof(OITVertexShaderSource) * 2]; - - sprintf(buf, OITVertexShaderSource, (int)params.gouraud); - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, buf); + VulkanSource src; + src.addConstant("pp_Gouraud", (int)params.gouraud) + .addSource(GouraudSource) + .addSource(OITVertexShaderSource); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, src.generate()); } vk::UniqueShaderModule OITShaderManager::compileShader(const FragmentShaderParams& params) { - char buf[(sizeof(OITShaderHeader) + sizeof(OITFragmentShaderSource)) * 2]; - - strcpy(buf, OITShaderHeader); - sprintf(buf + strlen(buf), OITFragmentShaderSource, (int)params.alphaTest, (int)params.insideClipTest, (int)params.useAlpha, - (int)params.texture, (int)params.ignoreTexAlpha, params.shaderInstr, (int)params.offset, params.fog, - (int)params.twoVolume, (int)params.gouraud, (int)params.bumpmap, (int)params.clamping, (int)params.palette, - (int)params.pass); - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, buf); + VulkanSource src; + src.addConstant("cp_AlphaTest", (int)params.alphaTest) + .addConstant("pp_ClipInside", (int)params.insideClipTest) + .addConstant("pp_UseAlpha", (int)params.useAlpha) + .addConstant("pp_Texture", (int)params.texture) + .addConstant("pp_IgnoreTexA", (int)params.ignoreTexAlpha) + .addConstant("pp_ShadInstr", params.shaderInstr) + .addConstant("pp_Offset", (int)params.offset) + .addConstant("pp_FogCtrl", params.fog) + .addConstant("pp_TwoVolumes", (int)params.twoVolume) + .addConstant("pp_Gouraud", (int)params.gouraud) + .addConstant("pp_BumpMap", (int)params.bumpmap) + .addConstant("ColorClamping", (int)params.clamping) + .addConstant("pp_Palette", (int)params.palette) + .addConstant("PASS", (int)params.pass) + .addSource(GouraudSource) + .addSource(OITShaderHeader) + .addSource(OITFragmentShaderSource); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, src.generate()); } vk::UniqueShaderModule OITShaderManager::compileFinalShader() { - std::string source = OITShaderHeader; - source += OITFinalShaderSource; - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, source); + VulkanSource src; + src.addConstant("MAX_PIXELS_PER_FRAGMENT", MAX_PIXELS_PER_FRAGMENT) + .addSource(OITShaderHeader) + .addSource(OITFinalShaderSource); + + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, src.generate()); } vk::UniqueShaderModule OITShaderManager::compileFinalVertexShader() { - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, OITFinalVertexShaderSource); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, VulkanSource().addSource(OITFinalVertexShaderSource).generate()); } vk::UniqueShaderModule OITShaderManager::compileClearShader() { - std::string source = OITShaderHeader; - source += OITClearShaderSource; - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, source); + VulkanSource src; + src.addSource(OITShaderHeader) + .addSource(OITClearShaderSource); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, src.generate()); } vk::UniqueShaderModule OITShaderManager::compileModVolVertexShader() { - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, ModVolVertexShaderSource); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, VulkanSource().addSource(ModVolVertexShaderSource).generate()); } vk::UniqueShaderModule OITShaderManager::compileModVolFragmentShader() { - std::string source = OITShaderHeader; - source += OITModifierVolumeShader; - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, source); + VulkanSource src; + src.addSource(OITShaderHeader) + .addSource(OITModifierVolumeShader); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, src.generate()); } void OITShaderManager::compileTrModVolFragmentShader(ModVolMode mode) { if (trModVolShaders.empty()) trModVolShaders.resize((size_t)ModVolMode::Final); - char buf[(sizeof(OITShaderHeader) + sizeof(OITTranslucentModvolShaderSource)) * 2]; - - strcpy(buf, OITShaderHeader); - sprintf(buf + strlen(buf), OITTranslucentModvolShaderSource, (int)mode); - trModVolShaders[(size_t)mode] = ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, buf); + VulkanSource src; + src.addConstant("MAX_PIXELS_PER_FRAGMENT", MAX_PIXELS_PER_FRAGMENT) + .addConstant("MV_MODE", (int)mode) + .addSource(OITShaderHeader) + .addSource(OITTranslucentModvolShaderSource); + trModVolShaders[(size_t)mode] = ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, src.generate()); } diff --git a/core/rend/vulkan/shaders.cpp b/core/rend/vulkan/shaders.cpp index 13d877aba..e6670ab05 100644 --- a/core/rend/vulkan/shaders.cpp +++ b/core/rend/vulkan/shaders.cpp @@ -21,17 +21,9 @@ #include "vulkan.h" #include "shaders.h" #include "compiler.h" +#include "utils.h" -static const char VertexShaderSource[] = R"(#version 450 - -#define pp_Gouraud %d - -#if pp_Gouraud == 0 -#define INTERPOLATION flat -#else -#define INTERPOLATION smooth -#endif - +static const char VertexShaderSource[] = R"( layout (std140, set = 0, binding = 0) uniform VertexShaderUniforms { mat4 normal_matrix; @@ -59,32 +51,12 @@ void main() } )"; -static const char FragmentShaderSource[] = R"(#version 450 - -#define cp_AlphaTest %d -#define pp_ClipInside %d -#define pp_UseAlpha %d -#define pp_Texture %d -#define pp_IgnoreTexA %d -#define pp_ShadInstr %d -#define pp_Offset %d -#define pp_FogCtrl %d -#define pp_Gouraud %d -#define pp_BumpMap %d -#define ColorClamping %d -#define pp_TriLinear %d -#define pp_Palette %d +static const char FragmentShaderSource[] = R"( #define PI 3.1415926 layout (location = 0) out vec4 FragColor; #define gl_FragColor FragColor -#if pp_Gouraud == 0 -#define INTERPOLATION flat -#else -#define INTERPOLATION smooth -#endif - layout (std140, set = 0, binding = 1) uniform FragmentShaderUniforms { vec4 colorClampMin; @@ -243,8 +215,7 @@ void main() } )"; -extern const char ModVolVertexShaderSource[] = R"(#version 450 - +extern const char ModVolVertexShaderSource[] = R"( layout (std140, set = 0, binding = 0) uniform VertexShaderUniforms { mat4 normal_matrix; @@ -269,8 +240,7 @@ void main() } )"; -static const char ModVolFragmentShaderSource[] = R"(#version 450 - +static const char ModVolFragmentShaderSource[] = R"( layout (location = 0) out vec4 FragColor; layout (push_constant) uniform pushBlock @@ -286,10 +256,7 @@ void main() } )"; -static const char QuadVertexShaderSource[] = R"(#version 450 - -#define ROTATE %d - +static const char QuadVertexShaderSource[] = R"( layout (location = 0) in vec3 in_pos; layout (location = 1) in vec2 in_uv; @@ -306,8 +273,7 @@ void main() } )"; -static const char QuadFragmentShaderSource[] = R"(#version 450 - +static const char QuadFragmentShaderSource[] = R"( layout (set = 0, binding = 0) uniform sampler2D tex; layout (push_constant) uniform pushBlock @@ -324,8 +290,7 @@ void main() } )"; -static const char OSDVertexShaderSource[] = R"(#version 450 - +static const char OSDVertexShaderSource[] = R"( layout (location = 0) in vec4 inPos; layout (location = 1) in uvec4 inColor; layout (location = 2) in vec2 inUV; @@ -340,8 +305,7 @@ void main() } )"; -static const char OSDFragmentShaderSource[] = R"(#version 450 - +static const char OSDFragmentShaderSource[] = R"( layout (binding = 0) uniform sampler2D tex; layout (location = 0) in lowp vec4 inColor; layout (location = 1) in mediump vec2 inUV; @@ -355,51 +319,63 @@ void main() vk::UniqueShaderModule ShaderManager::compileShader(const VertexShaderParams& params) { - char buf[sizeof(VertexShaderSource) * 2]; - - sprintf(buf, VertexShaderSource, (int)params.gouraud); - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, buf); + VulkanSource src; + src.addConstant("pp_Gouraud", (int)params.gouraud) + .addSource(GouraudSource) + .addSource(VertexShaderSource); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, src.generate()); } vk::UniqueShaderModule ShaderManager::compileShader(const FragmentShaderParams& params) { - char buf[sizeof(FragmentShaderSource) * 2]; - - sprintf(buf, FragmentShaderSource, (int)params.alphaTest, (int)params.insideClipTest, (int)params.useAlpha, (int)params.texture, - (int)params.ignoreTexAlpha, params.shaderInstr, (int)params.offset, params.fog, (int)params.gouraud, - (int)params.bumpmap, (int)params.clamping, (int)params.trilinear, (int)params.palette); - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, buf); + VulkanSource src; + src.addConstant("cp_AlphaTest", (int)params.alphaTest) + .addConstant("pp_ClipInside", (int)params.insideClipTest) + .addConstant("pp_UseAlpha", (int)params.useAlpha) + .addConstant("pp_Texture", (int)params.texture) + .addConstant("pp_IgnoreTexA", (int)params.ignoreTexAlpha) + .addConstant("pp_ShadInstr", params.shaderInstr) + .addConstant("pp_Offset", (int)params.offset) + .addConstant("pp_FogCtrl", params.fog) + .addConstant("pp_Gouraud", (int)params.gouraud) + .addConstant("pp_BumpMap", (int)params.bumpmap) + .addConstant("ColorClamping", (int)params.clamping) + .addConstant("pp_TriLinear", (int)params.trilinear) + .addConstant("pp_Palette", (int)params.palette) + .addSource(GouraudSource) + .addSource(FragmentShaderSource); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, src.generate()); } vk::UniqueShaderModule ShaderManager::compileModVolVertexShader() { - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, ModVolVertexShaderSource); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, VulkanSource().addSource(ModVolVertexShaderSource).generate()); } vk::UniqueShaderModule ShaderManager::compileModVolFragmentShader() { - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, ModVolFragmentShaderSource); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, VulkanSource().addSource(ModVolFragmentShaderSource).generate()); } vk::UniqueShaderModule ShaderManager::compileQuadVertexShader(bool rotate) { - char buf[sizeof(QuadVertexShaderSource) * 2]; - - sprintf(buf, QuadVertexShaderSource, (int)rotate); - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, buf); + VulkanSource src; + src.addConstant("ROTATE", (int)rotate) + .addSource(QuadVertexShaderSource); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, src.generate()); } vk::UniqueShaderModule ShaderManager::compileQuadFragmentShader() { - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, QuadFragmentShaderSource); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, VulkanSource().addSource(QuadFragmentShaderSource).generate()); } vk::UniqueShaderModule ShaderManager::compileOSDVertexShader() { - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, OSDVertexShaderSource); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eVertex, VulkanSource().addSource(OSDVertexShaderSource).generate()); } vk::UniqueShaderModule ShaderManager::compileOSDFragmentShader() { - return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, OSDFragmentShaderSource); + return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, VulkanSource().addSource(OSDFragmentShaderSource).generate()); } diff --git a/core/rend/vulkan/utils.h b/core/rend/vulkan/utils.h index fe83eb52a..af99ccdf0 100644 --- a/core/rend/vulkan/utils.h +++ b/core/rend/vulkan/utils.h @@ -20,6 +20,7 @@ */ #pragma once #include "vulkan.h" +#include "rend/shader_util.h" enum class ModVolMode { Xor, Or, Inclusion, Exclusion, Final }; @@ -75,3 +76,17 @@ static inline u32 findMemoryType(vk::PhysicalDeviceMemoryProperties const& memor verify(typeIndex != u32(~0)); return typeIndex; } + +static const char GouraudSource[] = R"( +#if pp_Gouraud == 0 +#define INTERPOLATION flat +#else +#define INTERPOLATION smooth +#endif +)"; + +class VulkanSource : public ShaderSource +{ +public: + VulkanSource() : ShaderSource("#version 450") {} +};