diff --git a/projects/msvc12/GLideN64.vcxproj b/projects/msvc12/GLideN64.vcxproj index 122861a6..7ac3520e 100644 --- a/projects/msvc12/GLideN64.vcxproj +++ b/projects/msvc12/GLideN64.vcxproj @@ -304,9 +304,12 @@ + + + @@ -438,10 +441,12 @@ + + - + diff --git a/projects/msvc12/GLideN64.vcxproj.filters b/projects/msvc12/GLideN64.vcxproj.filters index 9c33318b..0b885174 100644 --- a/projects/msvc12/GLideN64.vcxproj.filters +++ b/projects/msvc12/GLideN64.vcxproj.filters @@ -311,6 +311,15 @@ Source Files\Graphics\OpenGL\GLSL + + Source Files\Graphics\OpenGL\GLSL + + + Source Files\Graphics\OpenGL + + + Source Files\Graphics\OpenGL + @@ -544,9 +553,6 @@ Header Files\Graphics\OpenGL - - Header Files\Graphics\OpenGL - Header Files\Graphics\OpenGL @@ -568,5 +574,14 @@ Header Files\Graphics\OpenGL\GLSL + + Header Files\Graphics\OpenGL\GLSL + + + Header Files\Graphics\OpenGL + + + Header Files\Graphics\OpenGL + \ No newline at end of file diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp index d975153b..c2aec594 100644 --- a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp @@ -1,11 +1,1918 @@ +#include +#include +#include +#include "glsl_Utils.h" +#include "glsl_CombinerProgramImpl.h" #include "glsl_CombinerProgramBuilder.h" -using namespace opengl::glsl; +using namespace glsl; -CombinerProgramBuilder::CombinerProgramBuilder() +/*---------------_compileCombiner-------------*/ + +static +const char *ColorInput[] = { + "combined_color.rgb", + "readtex0.rgb", + "readtex1.rgb", + "uPrimColor.rgb", + "vec_color.rgb", + "uEnvColor.rgb", + "uCenterColor.rgb", + "uScaleColor.rgb", + "combined_color.a", + "vec3(readtex0.a)", + "vec3(readtex1.a)", + "vec3(uPrimColor.a)", + "vec3(vec_color.a)", + "vec3(uEnvColor.a)", + "vec3(lod_frac)", + "vec3(uPrimLod)", + "vec3(0.5 + 0.5*snoise())", + "vec3(uK4)", + "vec3(uK5)", + "vec3(1.0)", + "vec3(0.0)" +}; + +static +const char *AlphaInput[] = { + "combined_color.a", + "readtex0.a", + "readtex1.a", + "uPrimColor.a", + "vec_color.a", + "uEnvColor.a", + "uCenterColor.a", + "uScaleColor.a", + "combined_color.a", + "readtex0.a", + "readtex1.a", + "uPrimColor.a", + "vec_color.a", + "uEnvColor.a", + "lod_frac", + "uPrimLod", + "0.5 + 0.5*snoise()", + "uK4", + "uK5", + "1.0", + "0.0" +}; + +inline +int correctFirstStageParam(int _param) { + switch (_param) { + case TEXEL1: + return TEXEL0; + case TEXEL1_ALPHA: + return TEXEL0_ALPHA; + } + return _param; } +static +void _correctFirstStageParams(CombinerStage & _stage) +{ + for (int i = 0; i < _stage.numOps; ++i) { + _stage.op[i].param1 = correctFirstStageParam(_stage.op[i].param1); + _stage.op[i].param2 = correctFirstStageParam(_stage.op[i].param2); + _stage.op[i].param3 = correctFirstStageParam(_stage.op[i].param3); + } +} + +inline +int correctSecondStageParam(int _param) +{ + switch (_param) { + case TEXEL0: + return TEXEL1; + case TEXEL1: + return TEXEL0; + case TEXEL0_ALPHA: + return TEXEL1_ALPHA; + case TEXEL1_ALPHA: + return TEXEL0_ALPHA; + } + return _param; +} + +static +void _correctSecondStageParams(CombinerStage & _stage) { + for (int i = 0; i < _stage.numOps; ++i) { + _stage.op[i].param1 = correctSecondStageParam(_stage.op[i].param1); + _stage.op[i].param2 = correctSecondStageParam(_stage.op[i].param2); + _stage.op[i].param3 = correctSecondStageParam(_stage.op[i].param3); + } +} + +static +int _compileCombiner(const CombinerStage & _stage, const char** _Input, std::stringstream & _strShader) { + bool bBracketOpen = false; + int nRes = 0; + for (int i = 0; i < _stage.numOps; ++i) { + switch (_stage.op[i].op) { + case LOAD: + // sprintf(buf, "(%s ", _Input[_stage.op[i].param1]); + _strShader << "(" << _Input[_stage.op[i].param1] << " "; + bBracketOpen = true; + nRes |= 1 << _stage.op[i].param1; + break; + case SUB: + if (bBracketOpen) { + // sprintf(buf, "- %s)", _Input[_stage.op[i].param1]); + _strShader << "- " << _Input[_stage.op[i].param1] << ")"; + bBracketOpen = false; + } + else + // sprintf(buf, "- %s", _Input[_stage.op[i].param1]); + _strShader << "- " << _Input[_stage.op[i].param1]; + // _strShader += buf; + nRes |= 1 << _stage.op[i].param1; + break; + case ADD: + if (bBracketOpen) { + // sprintf(buf, "+ %s)", _Input[_stage.op[i].param1]); + _strShader << "+ " << _Input[_stage.op[i].param1] << ")"; + bBracketOpen = false; + } + else + // sprintf(buf, "+ %s", _Input[_stage.op[i].param1]); + _strShader << "+ " << _Input[_stage.op[i].param1]; + nRes |= 1 << _stage.op[i].param1; + break; + case MUL: + if (bBracketOpen) { + // sprintf(buf, ")*%s", _Input[_stage.op[i].param1]); + _strShader << ")*" << _Input[_stage.op[i].param1]; + bBracketOpen = false; + } + else + // sprintf(buf, "*%s", _Input[_stage.op[i].param1]); + _strShader << "*" << _Input[_stage.op[i].param1]; + nRes |= 1 << _stage.op[i].param1; + break; + case INTER: + // sprintf(buf, "mix(%s, %s, %s)", _Input[_stage.op[0].param2], _Input[_stage.op[0].param1], _Input[_stage.op[0].param3]); + _strShader << "mix(" << + _Input[_stage.op[0].param2] << "," << + _Input[_stage.op[0].param1] << "," << + _Input[_stage.op[0].param3] << ")"; + nRes |= 1 << _stage.op[i].param1; + nRes |= 1 << _stage.op[i].param2; + nRes |= 1 << _stage.op[i].param3; + break; + + // default: + // assert(false); + } + } + if (bBracketOpen) + _strShader << ")"; + _strShader << ";" << std::endl; + return nRes; +} + +/*---------------ShaderParts-------------*/ + +class VertexShaderHeader : public ShaderPart +{ +public: + VertexShaderHeader(const opengl::GLInfo & _version) + { + if (_version.isGLES2) { + m_part = "#version 100 \n"; + m_part += + "#if (__VERSION__ > 120) \n" + "# define IN in \n" + "# define OUT out \n" + "#else \n" + "# define IN attribute \n" + "# define OUT varying \n" + "#endif // __VERSION \n" + ; + } + else if (_version.isGLESX) { + std::stringstream ss; + ss << "#version " << _version.majorVersion << _version.minorVersion << "0 es " << std::endl; + ss << "# define IN in" << std::endl << "# define OUT out" << std::endl; + m_part = ss.str(); + } + else { + std::stringstream ss; + ss << "#version " << _version.majorVersion << _version.minorVersion << "0 core " << std::endl; + ss << "# define IN in" << std::endl << "# define OUT out" << std::endl; + m_part = ss.str(); + } + } +}; + +class VertexShaderTexturedTriangle : public ShaderPart +{ +public: + VertexShaderTexturedTriangle(const opengl::GLInfo & _version) + { + m_part = + "IN highp vec4 aPosition; \n" + "IN lowp vec4 aColor; \n" + "IN highp vec2 aTexCoord; \n" + "IN lowp float aNumLights; \n" + "IN highp vec4 aModify; \n" + " \n" + "uniform int uTexturePersp; \n" + " \n" + "uniform lowp int uFogUsage; \n" + "uniform mediump vec2 uFogScale; \n" + "uniform mediump vec2 uScreenCoordsScale; \n" + " \n" + "uniform mediump vec2 uTexScale; \n" + "uniform mediump vec2 uTexOffset[2]; \n" + "uniform mediump vec2 uCacheScale[2]; \n" + "uniform mediump vec2 uCacheOffset[2]; \n" + "uniform mediump vec2 uCacheShiftScale[2]; \n" + "uniform lowp ivec2 uCacheFrameBuffer; \n" + "OUT lowp vec4 vShadeColor; \n" + "OUT mediump vec2 vTexCoord0; \n" + "OUT mediump vec2 vTexCoord1; \n" + "OUT mediump vec2 vLodTexCoord; \n" + "OUT lowp float vNumLights; \n" + + "mediump vec2 calcTexCoord(in vec2 texCoord, in int idx) \n" + "{ \n" + " vec2 texCoordOut = texCoord*uCacheShiftScale[idx]; \n" + " texCoordOut -= uTexOffset[idx]; \n" + " if (uCacheFrameBuffer[idx] != 0) \n" + " texCoordOut.t = -texCoordOut.t; \n" + " return (uCacheOffset[idx] + texCoordOut)* uCacheScale[idx];\n" + "} \n" + " \n" + "void main() \n" + "{ \n" + " gl_Position = aPosition; \n" + " vShadeColor = aColor; \n" + " vec2 texCoord = aTexCoord; \n" + " texCoord *= uTexScale; \n" + " if (uTexturePersp == 0 && aModify[2] == 0.0) texCoord *= 0.5;\n" + " vTexCoord0 = calcTexCoord(texCoord, 0); \n" + " vTexCoord1 = calcTexCoord(texCoord, 1); \n" + " vLodTexCoord = texCoord; \n" + " vNumLights = aNumLights; \n" + " if (aModify != vec4(0.0)) { \n" + " if ((aModify[0]) != 0.0) { \n" + " gl_Position.xy = gl_Position.xy * uScreenCoordsScale + vec2(-1.0, 1.0); \n" + " gl_Position.xy *= gl_Position.w; \n" + " } \n" + " if ((aModify[1]) != 0.0) \n" + " gl_Position.z *= gl_Position.w; \n" + " if ((aModify[3]) != 0.0) \n" + " vNumLights = 0.0; \n" + " } \n" + " if (uFogUsage == 1) { \n" + " lowp float fp; \n" + " if (aPosition.z < -aPosition.w && aModify[1] == 0.0) \n" + " fp = -uFogScale.s + uFogScale.t; \n" + " else \n" + " fp = aPosition.z/aPosition.w*uFogScale.s + uFogScale.t; \n" + " vShadeColor.a = clamp(fp, 0.0, 1.0); \n" + " } \n" + ; + if (!_version.isGLESX) { + m_part += + " gl_ClipDistance[0] = gl_Position.w - gl_Position.z; \n" + ; + } + m_part += + "} \n" + ; + } +}; + +class VertexShaderTriangle : public ShaderPart +{ +public: + VertexShaderTriangle(const opengl::GLInfo & _version) + { + m_part = + "IN highp vec4 aPosition; \n" + "IN lowp vec4 aColor; \n" + "IN lowp float aNumLights; \n" + "IN highp vec4 aModify; \n" + " \n" + "uniform lowp int uFogUsage; \n" + "uniform mediump vec2 uFogScale; \n" + "uniform mediump vec2 uScreenCoordsScale;\n" + " \n" + "OUT lowp vec4 vShadeColor; \n" + "OUT lowp float vNumLights; \n" + " \n" + "void main() \n" + "{ \n" + " gl_Position = aPosition; \n" + " vShadeColor = aColor; \n" + " vNumLights = aNumLights; \n" + " if (aModify != vec4(0.0)) { \n" + " if ((aModify[0]) != 0.0) { \n" + " gl_Position.xy = gl_Position.xy * uScreenCoordsScale + vec2(-1.0, 1.0); \n" + " gl_Position.xy *= gl_Position.w; \n" + " } \n" + " if ((aModify[1]) != 0.0) \n" + " gl_Position.z *= gl_Position.w; \n" + " if ((aModify[3]) != 0.0) \n" + " vNumLights = 0.0; \n" + " } \n" + " if (uFogUsage == 1) { \n" + " lowp float fp; \n" + " if (aPosition.z < -aPosition.w && aModify[1] == 0.0) \n" + " fp = -uFogScale.s + uFogScale.t; \n" + " else \n" + " fp = aPosition.z/aPosition.w*uFogScale.s + uFogScale.t; \n" + " vShadeColor.a = clamp(fp, 0.0, 1.0); \n" + " } \n" + ; + if (!_version.isGLESX) { + m_part += + " gl_ClipDistance[0] = gl_Position.w - gl_Position.z; \n" + ; + } + m_part += + "} \n" + ; + } +}; + +class VertexShaderTexturedRect : public ShaderPart +{ +public: + VertexShaderTexturedRect(const opengl::GLInfo & _version) + { + m_part = + "IN highp vec4 aRectPosition; \n" + "IN lowp vec4 aRectColor; \n" + "IN highp vec2 aTexCoord0; \n" + "IN highp vec2 aTexCoord1; \n" + " \n" + "OUT lowp vec4 vShadeColor; \n" + "OUT mediump vec2 vTexCoord0; \n" + "OUT mediump vec2 vTexCoord1; \n" + "void main() \n" + "{ \n" + " gl_Position = aRectPosition; \n" + " vShadeColor = aRectColor; \n" + " vTexCoord0 = aTexCoord0; \n" + " vTexCoord1 = aTexCoord1; \n" + ; + if (!_version.isGLESX) { + m_part += + " gl_ClipDistance[0] = gl_Position.w - gl_Position.z; \n" + ; + } + m_part += + "} \n" + ; + } +}; + +class VertexShaderRect : public ShaderPart +{ +public: + VertexShaderRect(const opengl::GLInfo & _version) + { + m_part = + "IN highp vec4 aRectPosition; \n" + "IN lowp vec4 aRectColor; \n" + " \n" + "OUT lowp vec4 vShadeColor; \n" + "void main() \n" + "{ \n" + " gl_Position = aRectPosition; \n" + " vShadeColor = aRectColor; \n" + ; + if (!_version.isGLESX) { + m_part += + " gl_ClipDistance[0] = gl_Position.w - gl_Position.z; \n" + ; + } + m_part += + "} \n" + ; + } +}; + +class FragmentShaderHeader : public ShaderPart +{ +public: + FragmentShaderHeader(const opengl::GLInfo & _version) + { + if (_version.isGLES2) { + m_part = "#version 100 \n"; + m_part += "#extension GL_EXT_shader_texture_lod : enable \n"; + m_part += "#extension GL_OES_standard_derivatives : enable \n"; + m_part += + "#if (__VERSION__ > 120) \n" + "# define IN in \n" + "# define OUT out \n" + "#else \n" + "# define IN varying \n" + "# define OUT \n" + "#endif // __VERSION __ \n" + ; + } + else if (_version.isGLESX) { + std::stringstream ss; + ss << "#version " << _version.majorVersion << _version.minorVersion << "0 es " << std::endl; + ss << "# define IN in" << std::endl << "# define OUT out" << std::endl; + m_part = ss.str(); + } else { + std::stringstream ss; + ss << "#version " << _version.majorVersion << _version.minorVersion << "0 core " << std::endl; + ss << "# define IN in" << std::endl << "# define OUT out" << std::endl; + m_part = ss.str(); + } + } +}; + +class ShaderBlender1 : public ShaderPart +{ +public: + ShaderBlender1(const opengl::GLInfo & _version) + { + if (_version.isGLES2) { + m_part = + " if (uForceBlendCycle1 != 0) { \n" + " muxPM[0] = clampedColor; \n" + " muxA[0] = clampedColor.a; \n" + " lowp float muxa; \n" + " if (uBlendMux1[1] == 0) \n" + " muxa = muxA[0]; \n" + " else if (uBlendMux1[1] == 1) \n" + " muxa = muxA[1]; \n" + " else if (uBlendMux1[1] == 2) \n" + " muxa = muxA[2]; \n" + " else if (uBlendMux1[1] == 3) \n" + " muxa = muxA[3]; \n" + " muxB[0] = 1.0 - muxa; \n" + " lowp vec4 muxpm0; \n" + " if (uBlendMux1[0] == 0) \n" + " muxpm0 = muxPM[0]; \n" + " else if (uBlendMux1[0] == 1) \n" + " muxpm0 = muxPM[1]; \n" + " else if (uBlendMux1[0] == 2) \n" + " muxpm0 = muxPM[2]; \n" + " else if (uBlendMux1[0] == 3) \n" + " muxpm0 = muxPM[3]; \n" + " lowp vec4 muxpm2; \n" + " if (uBlendMux1[2] == 0) \n" + " muxpm2 = muxPM[0]; \n" + " else if (uBlendMux1[2] == 1) \n" + " muxpm2 = muxPM[1]; \n" + " else if (uBlendMux1[2] == 2) \n" + " muxpm2 = muxPM[2]; \n" + " else if (uBlendMux1[2] == 3) \n" + " muxpm2 = muxPM[3]; \n" + " lowp float muxb; \n" + " if (uBlendMux1[3] == 0) \n" + " muxb = muxB[0]; \n" + " else if (uBlendMux1[3] == 1) \n" + " muxb = muxB[1]; \n" + " else if (uBlendMux1[3] == 2) \n" + " muxb = muxB[2]; \n" + " else if (uBlendMux1[3] == 3) \n" + " muxb = muxB[3]; \n" + " lowp vec4 blend1 = (muxpm0 * muxa) + (muxpm2 * muxb); \n" + " clampedColor.rgb = clamp(blend1.rgb, 0.0, 1.0); \n" + " } \n" + ; + } else { + m_part = + " if (uForceBlendCycle1 != 0) { \n" + " muxPM[0] = clampedColor; \n" + " muxA[0] = clampedColor.a; \n" + " muxB[0] = 1.0 - muxA[uBlendMux1[1]]; \n" + " lowp vec4 blend1 = (muxPM[uBlendMux1[0]] * muxA[uBlendMux1[1]]) + (muxPM[uBlendMux1[2]] * muxB[uBlendMux1[3]]); \n" + " clampedColor.rgb = clamp(blend1.rgb, 0.0, 1.0); \n" + " } \n" + ; + + } + } +}; + +class ShaderBlender2 : public ShaderPart +{ +public: + ShaderBlender2(const opengl::GLInfo & _version) + { + if (_version.isGLES2) { + m_part = + " if (uForceBlendCycle2 != 0) { \n" + " muxPM[0] = clampedColor; \n" + " muxA[0] = clampedColor.a; \n" + " lowp float muxa; \n" + " if (uBlendMux2[1] == 0) \n" + " muxa = muxA[0]; \n" + " else if (uBlendMux2[1] == 1) \n" + " muxa = muxA[1]; \n" + " else if (uBlendMux2[1] == 2) \n" + " muxa = muxA[2]; \n" + " else if (uBlendMux2[1] == 3) \n" + " muxa = muxA[3]; \n" + " muxB[0] = 1.0 - muxa; \n" + " lowp vec4 muxpm0; \n" + " if (uBlendMux2[0] == 0) \n" + " muxpm0 = muxPM[0]; \n" + " else if (uBlendMux2[0] == 1) \n" + " muxpm0 = muxPM[1]; \n" + " else if (uBlendMux2[0] == 2) \n" + " muxpm0 = muxPM[2]; \n" + " else if (uBlendMux2[0] == 3) \n" + " muxpm0 = muxPM[3]; \n" + " lowp vec4 muxpm2; \n" + " if (uBlendMux2[2] == 0) \n" + " muxpm2 = muxPM[0]; \n" + " else if (uBlendMux2[2] == 1) \n" + " muxpm2 = muxPM[1]; \n" + " else if (uBlendMux2[2] == 2) \n" + " muxpm2 = muxPM[2]; \n" + " else if (uBlendMux2[2] == 3) \n" + " muxpm2 = muxPM[3]; \n" + " lowp float muxb; \n" + " if (uBlendMux2[3] == 0) \n" + " muxb = muxB[0]; \n" + " else if (uBlendMux2[3] == 1) \n" + " muxb = muxB[1]; \n" + " else if (uBlendMux2[3] == 2) \n" + " muxb = muxB[2]; \n" + " else if (uBlendMux2[3] == 3) \n" + " muxb = muxB[3]; \n" + " lowp vec4 blend2 = muxpm0 * muxa + muxpm2 * muxb; \n" + " clampedColor.rgb = clamp(blend2.rgb, 0.0, 1.0); \n" + " } \n" + ; + } + else { + m_part = + " if (uForceBlendCycle2 != 0) { \n" + " muxPM[0] = clampedColor; \n" + " muxA[0] = clampedColor.a; \n" + " muxB[0] = 1.0 - muxA[uBlendMux2[1]]; \n" + " lowp vec4 blend2 = muxPM[uBlendMux2[0]] * muxA[uBlendMux2[1]] + muxPM[uBlendMux2[2]] * muxB[uBlendMux2[3]]; \n" + " clampedColor.rgb = clamp(blend2.rgb, 0.0, 1.0); \n" + " } \n" + ; + } + } +}; + +class ShaderLegacyBlender : public ShaderPart +{ +public: + ShaderLegacyBlender() + { + m_part = + " if (uFogUsage == 1) \n" + " fragColor.rgb = mix(fragColor.rgb, uFogColor.rgb, vShadeColor.a); \n" + ; + } +}; + + +/* +// N64 color wrap and clamp on floats +// See https://github.com/gonetz/GLideN64/issues/661 for reference +if (c < -1.0) return c + 2.0; + +if (c < -0.5) return 1; + +if (c < 0.0) return 0; + +if (c > 2.0) return c - 2.0; + +if (c > 1.5) return 0; + +if (c > 1.0) return 1; + +return c; +*/ +class ShaderClamp : public ShaderPart +{ +public: + ShaderClamp() + { + m_part = + " lowp vec4 wrappedColor = cmbRes + 2.0 * step(cmbRes, vec4(-0.51)) - 2.0*step(vec4(1.51), cmbRes); \n" + " lowp vec4 clampedColor = clamp(wrappedColor, 0.0, 1.0); \n" + ; + } +}; + +/* +N64 sign-extension for C component of combiner +if (c > 1.0) +return c - 2.0; + +return c; +*/ +class ShaderSignExtendColorC : public ShaderPart +{ +public: + ShaderSignExtendColorC() + { + m_part = + " color1 = color1 - 2.0*(vec3(1.0) - step(color1, vec3(1.0))); \n" + ; + } +}; + +class ShaderSignExtendAlphaC : public ShaderPart +{ +public: + ShaderSignExtendAlphaC() + { + m_part = + " alpha1 = alpha1 - 2.0*(1.0 - step(alpha1, 1.0)); \n" + ; + } +}; + +/* +N64 sign-extension for ABD components of combiner +if (c > 1.5) +return c - 2.0; + +if (c < -0.5) +return c + 2.0; + +return c; +*/ +class ShaderSignExtendColorABD : public ShaderPart +{ +public: + ShaderSignExtendColorABD() + { + m_part = + " color1 = color1 + 2.0*step(color1, vec3(-0.51)) - 2.0*step(vec3(1.51), color1); \n" + ; + } +}; + +class ShaderSignExtendAlphaABD : public ShaderPart +{ +public: + ShaderSignExtendAlphaABD() + { + m_part = + " alpha1 = alpha1 + 2.0*step(alpha1, -0.51) - 2.0*step(1.51, alpha1); \n" + ; + } +}; + +class ShaderAlphaTest : public ShaderPart +{ +public: + ShaderAlphaTest() + { + m_part = + " if (uEnableAlphaTest != 0) { \n" + " lowp float alphaTestValue = (uAlphaCompareMode == 3) ? snoise() : uAlphaTestValue; \n" + " lowp float alphaValue; \n" + " if ((uAlphaCvgSel != 0) && (uCvgXAlpha == 0)) { \n" + " alphaValue = 0.125; \n" + " } else { \n" + " alphaValue = clamp(alpha1, 0.0, 1.0); \n" + " } \n" + " if (alphaValue < alphaTestValue) discard; \n" + " } \n" + ; + } +}; + +class ShaderCallDither : public ShaderPart +{ +public: + ShaderCallDither(const opengl::GLInfo & _version) + { + if (!_version.isGLES2 && config.generalEmulation.enableNoise != 0) { + m_part = + " if (uColorDitherMode == 2) colorNoiseDither(snoise(), clampedColor.rgb); \n" + " if (uAlphaDitherMode == 2) alphaNoiseDither(snoise(), clampedColor.a); \n" + ; + } + } +}; + +class ShaderFragmentGlobalVariablesTex : public ShaderPart +{ +public: + ShaderFragmentGlobalVariablesTex(const opengl::GLInfo & _version) + { + m_part = + "uniform sampler2D uTex0; \n" + "uniform sampler2D uTex1; \n" + "uniform lowp vec4 uFogColor; \n" + "uniform lowp vec4 uCenterColor;\n" + "uniform lowp vec4 uScaleColor; \n" + "uniform lowp vec4 uBlendColor; \n" + "uniform lowp vec4 uEnvColor; \n" + "uniform lowp vec4 uPrimColor; \n" + "uniform lowp float uPrimLod; \n" + "uniform lowp float uK4; \n" + "uniform lowp float uK5; \n" + "uniform lowp int uAlphaCompareMode; \n" + "uniform lowp ivec2 uFbMonochrome; \n" + "uniform lowp ivec2 uFbFixedAlpha; \n" + "uniform lowp int uEnableAlphaTest; \n" + "uniform lowp int uCvgXAlpha; \n" + "uniform lowp int uAlphaCvgSel; \n" + "uniform lowp float uAlphaTestValue; \n" + "uniform mediump vec2 uScreenScale; \n" + ; + + if (config.generalEmulation.enableLegacyBlending != 0) { + m_part += + "uniform lowp int uFogUsage; \n" + ; + } else { + m_part += + "uniform lowp ivec4 uBlendMux1; \n" + "uniform lowp int uForceBlendCycle1;\n" + ; + } + + if (!_version.isGLES2) { + m_part += + "uniform sampler2D uDepthTex; \n" + "uniform lowp int uAlphaDitherMode; \n" + "uniform lowp int uColorDitherMode; \n" + "uniform lowp int uRenderTarget; \n" + "uniform mediump vec2 uDepthScale; \n" + ; + if (_version.imageTextures && config.frameBufferEmulation.N64DepthCompare != 0) { + m_part += + "uniform lowp int uEnableDepthCompare; \n" + ; + } + } else { + m_part += + "lowp int nCurrentTile; \n" + ; + } + + if (config.video.multisampling > 0) { + m_part += + "uniform lowp ivec2 uMSTexEnabled; \n"; + "uniform lowp sampler2DMS uMSTex0; \n"; + "uniform lowp sampler2DMS uMSTex1; \n"; + ; + } + + m_part += + "IN lowp vec4 vShadeColor; \n" + "IN mediump vec2 vTexCoord0;\n" + "IN mediump vec2 vTexCoord1;\n" + "IN mediump vec2 vLodTexCoord;\n" + "IN lowp float vNumLights; \n" + "OUT lowp vec4 fragColor; \n" + ; + } +}; + +class ShaderFragmentGlobalVariablesNotex : public ShaderPart +{ +public: + ShaderFragmentGlobalVariablesNotex(const opengl::GLInfo & _version) + { + m_part = + "uniform lowp vec4 uFogColor; \n" + "uniform lowp vec4 uCenterColor;\n" + "uniform lowp vec4 uScaleColor; \n" + "uniform lowp vec4 uBlendColor; \n" + "uniform lowp vec4 uEnvColor; \n" + "uniform lowp vec4 uPrimColor; \n" + "uniform lowp float uPrimLod; \n" + "uniform lowp float uK4; \n" + "uniform lowp float uK5; \n" + "uniform lowp int uAlphaCompareMode; \n" + "uniform lowp ivec2 uFbMonochrome; \n" + "uniform lowp ivec2 uFbFixedAlpha; \n" + "uniform lowp int uEnableAlphaTest; \n" + "uniform lowp int uCvgXAlpha; \n" + "uniform lowp int uAlphaCvgSel; \n" + "uniform lowp float uAlphaTestValue; \n" + "uniform mediump vec2 uScreenScale; \n" + ; + + if (config.generalEmulation.enableLegacyBlending != 0) { + m_part += + "uniform lowp int uFogUsage; \n" + ; + } else { + m_part += + "uniform lowp ivec4 uBlendMux1; \n" + "uniform lowp int uForceBlendCycle1;\n" + ; + } + + if (!_version.isGLES2) { + m_part += + "uniform sampler2D uDepthTex; \n" + "uniform lowp int uAlphaDitherMode; \n" + "uniform lowp int uColorDitherMode; \n" + "uniform lowp int uRenderTarget; \n" + "uniform mediump vec2 uDepthScale; \n" + ; + if (_version.imageTextures && config.frameBufferEmulation.N64DepthCompare != 0) { + m_part += + "uniform lowp int uEnableDepthCompare; \n" + ; + } + } else { + m_part += + "lowp int nCurrentTile; \n" + ; + } + + m_part += + "IN lowp vec4 vShadeColor; \n" + "IN lowp float vNumLights; \n" + "OUT lowp vec4 fragColor; \n"; + } +}; + +class ShaderFragmentHeaderNoise : public ShaderPart +{ +public: + ShaderFragmentHeaderNoise(const opengl::GLInfo & _version) + { + m_part = + "lowp float snoise();\n"; + ; + } +}; + +class ShaderFragmentHeaderWriteDepth : public ShaderPart +{ +public: + ShaderFragmentHeaderWriteDepth(const opengl::GLInfo & _version) + { + if (!_version.isGLES2) { + m_part = + "void writeDepth();\n"; + ; + } + } +}; + +class ShaderFragmentHeaderCalcLight : public ShaderPart +{ +public: + ShaderFragmentHeaderCalcLight(const opengl::GLInfo & _version) + { + m_part = + "void calc_light(in lowp float fLights, in lowp vec3 input_color, out lowp vec3 output_color);\n"; + ; + } +}; + +class ShaderFragmentHeaderMipMap : public ShaderPart +{ +public: + ShaderFragmentHeaderMipMap(const opengl::GLInfo & _version) + { + m_part = + "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1);\n"; + ; + } +}; + +class ShaderFragmentHeaderReadMSTex : public ShaderPart +{ +public: + ShaderFragmentHeaderReadMSTex(const opengl::GLInfo & _version) + { + if (!_version.isGLES2 && config.video.multisampling > 0) { + m_part = + "lowp vec4 readTexMS(in lowp sampler2DMS mstex, in mediump vec2 texCoord, in lowp int fbMonochrome, in lowp int fbFixedAlpha);\n"; + ; + } + } +}; + +class ShaderFragmentHeaderDither : public ShaderPart +{ +public: + ShaderFragmentHeaderDither(const opengl::GLInfo & _version) + { + if (!_version.isGLES2 && config.generalEmulation.enableNoise != 0) { + m_part = + "void colorNoiseDither(in lowp float _noise, inout lowp vec3 _color);\n" + "void alphaNoiseDither(in lowp float _noise, inout lowp float _alpha);\n"; + ; + } + } +}; + +class ShaderFragmentHeaderDepthCompare : public ShaderPart +{ +public: + ShaderFragmentHeaderDepthCompare(const opengl::GLInfo & _version) + { + if (_version.imageTextures && config.frameBufferEmulation.N64DepthCompare != 0) { + m_part = + "bool depth_compare();\n" + "bool depth_render(highp float Z);\n"; + ; + } + } +}; + +class ShaderFragmentHeaderReadTex : public ShaderPart +{ +public: + ShaderFragmentHeaderReadTex (const opengl::GLInfo & _version) + { + if (!_version.isGLES2) { + if (config.texture.bilinearMode == BILINEAR_3POINT) { + m_part = + "uniform lowp int uTextureFilterMode; \n" + // 3 point texture filtering. + // Original author: ArthurCarvalho + // GLSL implementation: twinaphex, mupen64plus-libretro project. + "#define TEX_OFFSET(tex, texCoord, off) texture(tex, texCoord - (off)/texSize) \n" + "#define FILTER_3POINT(tex, texCoord) \\\n" + " mediump vec2 texSize = vec2(textureSize(tex,0)); \\\n" + " mediump vec2 offset = fract(texCoord*texSize - vec2(0.5)); \\\n" + " offset -= step(1.0, offset.x + offset.y); \\\n" + " lowp vec4 c0 = TEX_OFFSET(tex, texCoord, offset); \\\n" + " lowp vec4 c1 = TEX_OFFSET(tex, texCoord, vec2(offset.x - sign(offset.x), offset.y)); \\\n" + " lowp vec4 c2 = TEX_OFFSET(tex, texCoord, vec2(offset.x, offset.y - sign(offset.y))); \\\n" + " lowp vec4 tex3Point = c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0); \n" + "#define READ_TEX(name, tex, texCoord, fbMonochrome, fbFixedAlpha) \\\n" + " { \\\n" + " lowp vec4 texStandard = texture(tex, texCoord); \\\n" + " FILTER_3POINT(tex, texCoord); \\\n" + " name = uTextureFilterMode == 0 ? texStandard : tex3Point; \\\n" + " if (fbMonochrome == 1) name = vec4(name.r); \\\n" + " else if (fbMonochrome == 2) \\\n" + " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" + " if (fbFixedAlpha == 1) name.a = 0.825; \\\n" + " } \n" + ; + } else { + m_part = + "#define READ_TEX(name, tex, texCoord, fbMonochrome, fbFixedAlpha) \\\n" + " { \\\n" + " name = texture(tex, texCoord); \\\n" + " if (fbMonochrome == 1) name = vec4(name.r); \\\n" + " else if (fbMonochrome == 2) \\\n" + " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" + " if (fbFixedAlpha == 1) name.a = 0.825; \\\n" + " } \n" + ; + } + } + } +}; + + +class ShaderFragmentMain : public ShaderPart +{ +public: + ShaderFragmentMain(const opengl::GLInfo & _version) + { + m_part = + "void main() \n" + "{ \n" + ; + if (!_version.isGLES2) { + m_part += + " writeDepth(); \n" + ; + } + m_part += + " lowp vec4 vec_color; \n" + " lowp float alpha1; \n" + " lowp vec3 color1, input_color; \n" + ; + } +}; + +class ShaderFragmentMain2Cycle : public ShaderPart +{ +public: + ShaderFragmentMain2Cycle(const opengl::GLInfo & _version) + { + m_part = + "void main() \n" + "{ \n" + ; + if (!_version.isGLES2) { + m_part += + " writeDepth(); \n" + ; + } + m_part += + " lowp vec4 vec_color, combined_color; \n" + " lowp float alpha1, alpha2; \n" + " lowp vec3 color1, color2, input_color; \n" + ; + } +}; + +class ShaderFragmentBlendMux : public ShaderPart +{ +public: + ShaderFragmentBlendMux(const opengl::GLInfo & _version) + { + if (config.generalEmulation.enableLegacyBlending == 0) { + m_part = + " lowp mat4 muxPM = mat4(vec4(0.0), vec4(0.0), uBlendColor, uFogColor); \n" + " lowp vec4 muxA = vec4(0.0, uFogColor.a, vShadeColor.a, 0.0); \n" + " lowp vec4 muxB = vec4(0.0, 1.0, 1.0, 0.0); \n" + ; + } + } +}; + +class ShaderFragmentReadTexMipmap : public ShaderPart +{ +public: + ShaderFragmentReadTexMipmap(const opengl::GLInfo & _version) + { + m_part = + " lowp vec4 readtex0, readtex1; \n" + " lowp float lod_frac = mipmap(readtex0, readtex1); \n" + ; + } +}; + +class ShaderFragmentReadTex0 : public ShaderPart +{ +public: + ShaderFragmentReadTex0(const opengl::GLInfo & _version) + { + if (_version.isGLES2) { + if (config.video.multisampling > 0) { + m_part = + " lowp vec4 readtex0; \n" + " if (uMSTexEnabled[0] == 0) READ_TEX(readtex0, uTex0, vTexCoord0, uFbMonochrome[0], uFbFixedAlpha[0]) \n" + " else readtex0 = readTexMS(uMSTex0, vTexCoord0, uFbMonochrome[0], uFbFixedAlpha[0]); \n" + ; + } else { + m_part = + " lowp vec4 readtex0; \n" + " READ_TEX(readtex0, uTex0, vTexCoord0, uFbMonochrome[0], uFbFixedAlpha[0]); \n" + ; + } + } else { + m_part = + " nCurrentTile = 0; \n" + " lowp vec4 readtex0 = readTex(uTex0, vTexCoord0, uFbMonochrome[0], uFbFixedAlpha[0]); \n" + ; + } + } +}; + +class ShaderFragmentReadTex1 : public ShaderPart +{ +public: + ShaderFragmentReadTex1(const opengl::GLInfo & _version) + { + if (_version.isGLES2) { + if (config.video.multisampling > 0) { + m_part = + " lowp vec4 readtex1; \n" + " if (uMSTexEnabled[1] == 0) READ_TEX(readtex1, uTex1, vTexCoord1, uFbMonochrome[1], uFbFixedAlpha[1]) \n" + " else readtex1 = readTexMS(uMSTex1, vTexCoord1, uFbMonochrome[1], uFbFixedAlpha[1]); \n" + ; + } + else { + m_part = + " lowp vec4 readtex1; \n" + " READ_TEX(readtex1, uTex1, vTexCoord1, uFbMonochrome[1], uFbFixedAlpha[1]); \n" + ; + } + } + else { + m_part = + " nCurrentTile = 1; \n" + " lowp vec4 readtex1 = readTex(uTex1, vTexCoord1, uFbMonochrome[1], uFbFixedAlpha[1]); \n" + ; + } + } +}; + +class ShaderFragmentCallN64Depth : public ShaderPart +{ +public: + ShaderFragmentCallN64Depth(const opengl::GLInfo & _version) + { + if (!_version.isGLES2 && _version.imageTextures && config.frameBufferEmulation.N64DepthCompare != 0) { + m_part = + " if (uRenderTarget != 0) { if (!depth_render(fragColor.r)) discard; } \n" + " else if (!depth_compare()) discard; \n" + ; + } + } +}; + +class ShaderFragmentRenderTarget : public ShaderPart +{ +public: + ShaderFragmentRenderTarget(const opengl::GLInfo & _version) + { + if (!_version.isGLES2 && config.generalEmulation.enableFragmentDepthWrite != 0) { + m_part = + " if (uRenderTarget != 0) { \n" + " if (uRenderTarget > 1) { \n" + " ivec2 coord = ivec2(gl_FragCoord.xy); \n" + " if (gl_FragDepth >= texelFetch(uDepthTex, coord, 0).r) discard; \n" + " } \n" + " gl_FragDepth = fragColor.r; \n" + " } \n" + ; + } + } +}; + +class ShaderNoise : public ShaderPart +{ +public: + ShaderNoise(const opengl::GLInfo & _version) + { + if (config.generalEmulation.enableNoise == 0) { + // Dummy noise + m_part = + "lowp float snoise() \n" + "{ \n" + " return 1.0; \n" + "} \n" + ; + } else { + if (_version.isGLES2) { + m_part = + "uniform sampler2D uTexNoise; \n" + "lowp float snoise() \n" + "{ \n" + " mediump vec2 texSize = vec2(640.0, 580.0); \n" + " mediump vec2 coord = gl_FragCoord.xy/uScreenScale/texSize; \n" + " return texture2D(uTexNoise, coord).r; \n" + "} \n" + ; + } else { + m_part = + "uniform sampler2D uTexNoise; \n" + "lowp float snoise() \n" + "{ \n" + " ivec2 coord = ivec2(gl_FragCoord.xy/uScreenScale); \n" + " return texelFetch(uTexNoise, coord, 0).r; \n" + "} \n" + ; + } + } + } +}; + +class ShaderDither : public ShaderPart +{ +public: + ShaderDither(const opengl::GLInfo & _version) + { + if (!_version.isGLES2 && config.generalEmulation.enableNoise != 0) { + m_part = + "void colorNoiseDither(in lowp float _noise, inout lowp vec3 _color) \n" + "{ \n" + " mediump vec3 tmpColor = _color*255.0; \n" + " mediump ivec3 iColor = ivec3(tmpColor); \n" + //" iColor &= 248; \n" // does not work with HW lighting enabled (why?!) + " iColor |= ivec3(tmpColor*_noise)&7; \n" + " _color = vec3(iColor)/255.0; \n" + "} \n" + "void alphaNoiseDither(in lowp float _noise, inout lowp float _alpha) \n" + "{ \n" + " mediump float tmpAlpha = _alpha*255.0; \n" + " mediump int iAlpha = int(tmpAlpha); \n" + //" iAlpha &= 248; \n" // causes issue #518. need further investigation + " iAlpha |= int(tmpAlpha*_noise)&7; \n" + " _alpha = float(iAlpha)/255.0; \n" + "} \n" + ; + } + } +}; + +class ShaderWriteDepth : public ShaderPart +{ +public: + ShaderWriteDepth(const opengl::GLInfo & _version) + { + if (!_version.isGLES2) { + if (config.generalEmulation.enableFragmentDepthWrite == 0) { + // Dummy write depth + m_part = + "void writeDepth() \n" + "{ \n" + "} \n" + ; + } else { + m_part = + "void writeDepth() \n" + "{ \n" + " gl_FragDepth = clamp((gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" + "} \n" + ; + } + } + } +}; + +class ShaderMipmap : public ShaderPart +{ +public: + ShaderMipmap(const opengl::GLInfo & _version) + { + if (_version.isGLES2) { + if (config.generalEmulation.enableLOD == 0) { + // Fake mipmap + m_part = + "uniform lowp int uMaxTile; \n" + "uniform mediump float uMinLod; \n" + " \n" + "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n" + " readtex0 = texture2D(uTex0, vTexCoord0); \n" + " readtex1 = texture2D(uTex1, vTexCoord1); \n" + " if (uMaxTile == 0) return 1.0; \n" + " return uMinLod; \n" + "} \n" + ; + } else { + m_part = + "uniform lowp int uEnableLod; \n" + "uniform mediump float uMinLod; \n" + "uniform lowp int uMaxTile; \n" + "uniform lowp int uTextureDetail; \n" + " \n" + "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n" + " readtex0 = texture2D(uTex0, vTexCoord0); \n" + " readtex1 = texture2DLodEXT(uTex1, vTexCoord1, 0.0); \n" + " \n" + " mediump float fMaxTile = float(uMaxTile); \n" + " mediump vec2 dx = abs(dFdx(vLodTexCoord)); \n" + " dx *= uScreenScale; \n" + " mediump float lod = max(dx.x, dx.y); \n" + " bool magnify = lod < 1.0; \n" + " mediump float lod_tile = magnify ? 0.0 : floor(log2(floor(lod))); \n" + " bool distant = lod > 128.0 || lod_tile >= fMaxTile; \n" + " mediump float lod_frac = fract(lod/pow(2.0, lod_tile)); \n" + " if (magnify) lod_frac = max(lod_frac, uMinLod); \n" + " if (uTextureDetail == 0) { \n" + " if (distant) lod_frac = 1.0; \n" + " else if (magnify) lod_frac = 0.0; \n" + " } \n" + " if (magnify && (uTextureDetail == 1 || uTextureDetail == 3)) \n" + " lod_frac = 1.0 - lod_frac; \n" + " if (uMaxTile == 0) { \n" + " if (uEnableLod != 0 && uTextureDetail < 2) \n" + " readtex1 = readtex0; \n" + " return lod_frac; \n" + " } \n" + " if (uEnableLod == 0) return lod_frac; \n" + " \n" + " lod_tile = min(lod_tile, fMaxTile); \n" + " lowp float lod_tile_m1 = max(0.0, lod_tile - 1.0); \n" + " lowp vec4 lodT = texture2DLodEXT(uTex1, vTexCoord1, lod_tile); \n" + " lowp vec4 lodT_m1 = texture2DLodEXT(uTex1, vTexCoord1, lod_tile_m1); \n" + " lowp vec4 lodT_p1 = texture2DLodEXT(uTex1, vTexCoord1, lod_tile + 1.0); \n" + " if (lod_tile < 1.0) { \n" + " if (magnify) { \n" + // !sharpen && !detail + " if (uTextureDetail == 0) readtex1 = readtex0; \n" + " } else { \n" + // detail + " if (uTextureDetail > 1) { \n" + " readtex0 = lodT; \n" + " readtex1 = lodT_p1; \n" + " } \n" + " } \n" + " } else { \n" + " if (uTextureDetail > 1) { \n" + " readtex0 = lodT; \n" + " readtex1 = lodT_p1; \n" + " } else { \n" + " readtex0 = lodT_m1; \n" + " readtex1 = lodT; \n" + " } \n" + " } \n" + " return lod_frac; \n" + "} \n" + ; + } + } + else { + if (config.generalEmulation.enableLOD == 0) { + // Fake mipmap + m_part = + "uniform lowp int uMaxTile; \n" + "uniform mediump float uMinLod; \n" + " \n" + "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n" + " readtex0 = texture(uTex0, vTexCoord0); \n" + " readtex1 = texture(uTex1, vTexCoord1); \n" + " if (uMaxTile == 0) return 1.0; \n" + " return uMinLod; \n" + "} \n" + ; + } else { + m_part = + "uniform lowp int uEnableLod; \n" + "uniform mediump float uMinLod; \n" + "uniform lowp int uMaxTile; \n" + "uniform lowp int uTextureDetail; \n" + " \n" + "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n" + " readtex0 = texture(uTex0, vTexCoord0); \n" + " readtex1 = textureLod(uTex1, vTexCoord1, 0.0); \n" + " \n" + " mediump float fMaxTile = float(uMaxTile); \n" + " mediump vec2 dx = abs(dFdx(vLodTexCoord)); \n" + " dx *= uScreenScale; \n" + " mediump float lod = max(dx.x, dx.y); \n" + " bool magnify = lod < 1.0; \n" + " mediump float lod_tile = magnify ? 0.0 : floor(log2(floor(lod))); \n" + " bool distant = lod > 128.0 || lod_tile >= fMaxTile; \n" + " mediump float lod_frac = fract(lod/pow(2.0, lod_tile)); \n" + " if (magnify) lod_frac = max(lod_frac, uMinLod); \n" + " if (uTextureDetail == 0) { \n" + " if (distant) lod_frac = 1.0; \n" + " else if (magnify) lod_frac = 0.0; \n" + " } \n" + " if (magnify && ((uTextureDetail & 1) != 0)) \n" + " lod_frac = 1.0 - lod_frac; \n" + " if (uMaxTile == 0) { \n" + " if (uEnableLod != 0 && (uTextureDetail & 2) == 0) \n" + " readtex1 = readtex0; \n" + " return lod_frac; \n" + " } \n" + " if (uEnableLod == 0) return lod_frac; \n" + " \n" + " lod_tile = min(lod_tile, fMaxTile); \n" + " lowp float lod_tile_m1 = max(0.0, lod_tile - 1.0); \n" + " lowp vec4 lodT = textureLod(uTex1, vTexCoord1, lod_tile); \n" + " lowp vec4 lodT_m1 = textureLod(uTex1, vTexCoord1, lod_tile_m1); \n" + " lowp vec4 lodT_p1 = textureLod(uTex1, vTexCoord1, lod_tile + 1.0); \n" + " if (lod_tile < 1.0) { \n" + " if (magnify) { \n" + // !sharpen && !detail + " if (uTextureDetail == 0) readtex1 = readtex0; \n" + " } else { \n" + // detail + " if ((uTextureDetail & 2) != 0 ) { \n" + " readtex0 = lodT; \n" + " readtex1 = lodT_p1; \n" + " } \n" + " } \n" + " } else { \n" + " if ((uTextureDetail & 2) != 0 ) { \n" + " readtex0 = lodT; \n" + " readtex1 = lodT_p1; \n" + " } else { \n" + " readtex0 = lodT_m1; \n" + " readtex1 = lodT; \n" + " } \n" + " } \n" + " return lod_frac; \n" + "} \n" + ; + } + } + } +}; + +class ShaderCalcLight : public ShaderPart +{ +public: + ShaderCalcLight(const opengl::GLInfo & _version) + { + m_part = + "uniform mediump vec3 uLightDirection[8]; \n" + "uniform lowp vec3 uLightColor[8]; \n" + "void calc_light(in lowp float fLights, in lowp vec3 input_color, out lowp vec3 output_color) {\n" + " output_color = input_color; \n" + " lowp int nLights = int(floor(fLights + 0.5)); \n" + " if (nLights == 0) \n" + " return; \n" + " output_color = uLightColor[nLights]; \n" + " mediump float intensity; \n" + " for (int i = 0; i < nLights; i++) { \n" + " intensity = max(dot(input_color, uLightDirection[i]), 0.0);\n" + " output_color += intensity*uLightColor[i]; \n" + " }; \n" + " output_color = clamp(output_color, 0.0, 1.0); \n" + "} \n" + ; + } +}; + +class ShaderReadtex : public ShaderPart +{ +public: + ShaderReadtex(const opengl::GLInfo & _version) + { + if (_version.isGLES2) { + if (config.texture.bilinearMode == BILINEAR_3POINT) { + m_part = + "uniform mediump vec2 uTextureSize[2]; \n" + "uniform lowp int uTextureFilterMode; \n" + // 3 point texture filtering. + // Original author: ArthurCarvalho + // GLSL implementation: twinaphex, mupen64plus-libretro project. + "#define TEX_OFFSET(off) texture2D(tex, texCoord - (off)/texSize) \n" + "lowp vec4 filter3point(in sampler2D tex, in mediump vec2 texCoord) \n" + "{ \n" +#ifndef VC + " mediump vec2 texSize = uTextureSize[nCurrentTile]; \n" +#else + " mediump vec2 texSize; \n" + " if (nCurrentTile == 0) \n" + " texSize = uTextureSize[0]; \n" + " else \n" + " texSize = uTextureSize[1]; \n" +#endif + " mediump vec2 offset = fract(texCoord*texSize - vec2(0.5)); \n" + " offset -= step(1.0, offset.x + offset.y); \n" + " lowp vec4 c0 = TEX_OFFSET(offset); \n" + " lowp vec4 c1 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y)); \n" + " lowp vec4 c2 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y))); \n" + " return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0); \n" + "} \n" + "lowp vec4 readTex(in sampler2D tex, in mediump vec2 texCoord, in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" + "{ \n" + " lowp vec4 texStandard = texture2D(tex, texCoord); \n" + " lowp vec4 tex3Point = filter3point(tex, texCoord); \n" + " lowp vec4 texColor = uTextureFilterMode == 0 ? texStandard : tex3Point; \n" + " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" + " else if (fbMonochrome == 2) \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" + " return texColor; \n" + "} \n" + ; + } else { + m_part = + "lowp vec4 readTex(in sampler2D tex, in mediump vec2 texCoord, in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" + "{ \n" + " lowp vec4 texColor = texture2D(tex, texCoord); \n" + " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" + " else if (fbMonochrome == 2) \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" + " return texColor; \n" + "} \n" + ; + } + } else { + if (config.video.multisampling > 0) { + m_part = + "uniform lowp int uMSAASamples; \n" + "uniform lowp float uMSAAScale; \n" + "lowp vec4 sampleMS(in lowp sampler2DMS mstex, in mediump ivec2 ipos) \n" + "{ \n" + " lowp vec4 texel = vec4(0.0); \n" + " for (int i = 0; i < uMSAASamples; ++i) \n" + " texel += texelFetch(mstex, ipos, i); \n" + " return texel * uMSAAScale; \n" + "} \n" + " \n" + "lowp vec4 readTexMS(in lowp sampler2DMS mstex, in mediump vec2 texCoord, in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" + "{ \n" + " mediump vec2 msTexSize = vec2(textureSize(mstex)); \n" + " mediump ivec2 itexCoord = ivec2(msTexSize * texCoord); \n" + " lowp vec4 texColor = sampleMS(mstex, itexCoord); \n" + " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" + " else if (fbMonochrome == 2) \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" + " return texColor; \n" + "} \n" + ; + } + } + } +}; + +class ShaderN64DepthCompare : public ShaderPart +{ +public: + ShaderN64DepthCompare(const opengl::GLInfo & _version) + { + if (_version.imageTextures && config.frameBufferEmulation.N64DepthCompare != 0) { + m_part = _version.isGLESX + ? "layout(binding = 2, rgba32f) highp uniform coherent image2D uDepthImage;\n" + : "layout(binding = 2, rg32f) highp uniform coherent image2D uDepthImage;\n" + ; + m_part += + "uniform lowp int uDepthMode; \n" + "uniform lowp int uDepthSource; \n" + "uniform lowp int uEnableDepthUpdate; \n" + "uniform mediump float uDeltaZ; \n" + "bool depth_compare() \n" + "{ \n" + " ivec2 coord = ivec2(gl_FragCoord.xy); \n" + " highp vec4 depth = imageLoad(uDepthImage,coord); \n" + " highp float bufZ = depth.r; \n" + " highp float curZ = gl_FragDepth; \n" + " highp float dz, dzMin; \n" + " if (uDepthSource == 1) { \n" + " dzMin = dz = uDeltaZ; \n" + " } else { \n" + " dz = 4.0*fwidth(gl_FragDepth); \n" + " dzMin = min(dz, depth.g); \n" + " } \n" + " bool bInfront = curZ < bufZ; \n" + " bool bFarther = (curZ + dzMin) >= bufZ; \n" + " bool bNearer = (curZ - dzMin) <= bufZ; \n" + " bool bMax = bufZ == 1.0; \n" + " bool bRes; \n" + " switch (uDepthMode) { \n" + " case 1: \n" + " bRes = bMax || bNearer; \n" + " break; \n" + " case 0: \n" + " case 2: \n" + " bRes = bMax || bInfront; \n" + " break; \n" + " case 3: \n" + " bRes = bFarther && bNearer && !bMax; \n" + " break; \n" + " default: \n" + " bRes = bInfront; \n" + " break; \n" + " } \n" + " if (uEnableDepthUpdate != 0 && bRes) { \n" + " highp vec4 depth_out = vec4(gl_FragDepth, dz, 1.0, 1.0); \n" + " imageStore(uDepthImage,coord, depth_out); \n" + " } \n" + " memoryBarrierImage(); \n" + " if (uEnableDepthCompare != 0) \n" + " return bRes; \n" + " return true; \n" + "} \n" + ; + } + } +}; + +class ShaderN64DepthRender : public ShaderPart +{ +public: + ShaderN64DepthRender(const opengl::GLInfo & _version) + { + if (_version.imageTextures && config.frameBufferEmulation.N64DepthCompare != 0) { + m_part = _version.isGLESX + ? "layout(binding = 2, rgba32f) highp uniform coherent image2D uDepthImage;\n" + : "layout(binding = 2, rg32f) highp uniform coherent image2D uDepthImage;\n" + ; + m_part += + "bool depth_render(highp float Z) \n" + "{ \n" + " ivec2 coord = ivec2(gl_FragCoord.xy); \n" + " if (uEnableDepthCompare != 0) { \n" + " highp vec4 depth = imageLoad(uDepthImage,coord); \n" + " highp float bufZ = depth.r; \n" + " highp float curZ = gl_FragDepth; \n" + " if (curZ >= bufZ) return false; \n" + " } \n" + " highp vec4 depth_out = vec4(Z, 0.0, 1.0, 1.0); \n" + " imageStore(uDepthImage,coord, depth_out); \n" + " memoryBarrierImage(); \n" + " return true; \n" + "} \n" + ; + } + } +}; + +/*---------------ShaderPartsEnd-------------*/ + +static +bool needClampColor() { + return gDP.otherMode.cycleType <= G_CYC_2CYCLE; +} + +static +bool combinedColorC(const gDPCombine & _combine) { + if (gDP.otherMode.cycleType != G_CYC_2CYCLE) + return false; + return _combine.mRGB1 == G_CCMUX_COMBINED; +} + +static +bool combinedAlphaC(const gDPCombine & _combine) { + if (gDP.otherMode.cycleType != G_CYC_2CYCLE) + return false; + return _combine.mA1 == G_ACMUX_COMBINED; +} + +static +bool combinedColorABD(const gDPCombine & _combine) { + if (gDP.otherMode.cycleType != G_CYC_2CYCLE) + return false; + if (_combine.aRGB1 == G_CCMUX_COMBINED) + return true; + if (_combine.saRGB1 == G_CCMUX_COMBINED || _combine.sbRGB1 == G_CCMUX_COMBINED) + return _combine.mRGB1 != G_CCMUX_0; + return false; +} + +static +bool combinedAlphaABD(const gDPCombine & _combine) { + if (gDP.otherMode.cycleType != G_CYC_2CYCLE) + return false; + if (_combine.aA1 == G_ACMUX_COMBINED) + return true; + if (_combine.saA1 == G_ACMUX_COMBINED || _combine.sbA1 == G_ACMUX_COMBINED) + return _combine.mA1 != G_ACMUX_0; + return false; +} + +int CombinerProgramBuilder::compileCombiner(const CombinerKey & _key, Combiner & _color, Combiner & _alpha, std::string & _strShader) +{ + gDPCombine combine; + combine.mux = _key.getMux(); + + std::stringstream ssShader; + + if (gDP.otherMode.cycleType != G_CYC_2CYCLE) { + _correctFirstStageParams(_alpha.stage[0]); + _correctFirstStageParams(_color.stage[0]); + } + _strShader.append(" alpha1 = "); + int nInputs = _compileCombiner(_alpha.stage[0], AlphaInput, ssShader); + // Simulate N64 color sign-extend. + if (combinedAlphaC(combine)) + m_signExtendAlphaC->write(ssShader); + else if (combinedAlphaABD(combine)) + m_signExtendAlphaABD->write(ssShader); + + m_alphaTest->write(ssShader); + + _strShader.append(" color1 = "); + nInputs |= _compileCombiner(_color.stage[0], ColorInput, ssShader); + // Simulate N64 color sign-extend. + if (combinedColorC(combine)) + m_signExtendColorC->write(ssShader); + else if (combinedColorABD(combine)) + m_signExtendColorABD->write(ssShader); + + if (gDP.otherMode.cycleType == G_CYC_2CYCLE) { + + ssShader << " combined_color = vec4(color1, alpha1);" << std::endl; + if (_alpha.numStages == 2) { + ssShader << " alpha2 = "; + _correctSecondStageParams(_alpha.stage[1]); + nInputs |= _compileCombiner(_alpha.stage[1], AlphaInput, ssShader); + } + else + ssShader << " alpha2 = alpha1;" << std::endl; + + ssShader << " if (uCvgXAlpha != 0 && alpha2 < 0.125) discard;" << std::endl; + + if (_color.numStages == 2) { + ssShader << " color2 = "; + _correctSecondStageParams(_color.stage[1]); + nInputs |= _compileCombiner(_color.stage[1], ColorInput, ssShader); + } + else + ssShader << " color2 = color1;" << std::endl; + + ssShader << " lowp vec4 cmbRes = vec4(color2, alpha2);" << std::endl; + } + else { + ssShader << " if (uCvgXAlpha != 0 && alpha1 < 0.125) discard;" << std::endl; + ssShader << " lowp vec4 cmbRes = vec4(color1, alpha1);" << std::endl; + } + + // Simulate N64 color clamp. + if (needClampColor()) + m_clamp->write(ssShader); + else + ssShader << " lowp vec4 clampedColor = clamp(cmbRes, 0.0, 1.0);" << std::endl; + + m_callDither->write(ssShader); + + if (config.generalEmulation.enableLegacyBlending == 0) { + if (gDP.otherMode.cycleType <= G_CYC_2CYCLE) + m_blender1->write(ssShader); + if (gDP.otherMode.cycleType == G_CYC_2CYCLE) + m_blender2->write(ssShader); + + ssShader << " fragColor = clampedColor;" << std::endl; + } + else { + ssShader << " fragColor = clampedColor;" << std::endl; + m_legacyBlender->write(ssShader); + } + + _strShader = ssShader.str(); + return nInputs; +} + +graphics::CombinerProgram * CombinerProgramBuilder::buildCombinerProgram(Combiner & _color, + Combiner & _alpha, + const CombinerKey & _key) +{ + std::string strCombiner; + CombinerInputs combinerInputs(compileCombiner(_key, _color, _alpha, strCombiner)); + + const bool bUseLod = combinerInputs.usesLOD(); + const bool bUseTextures = combinerInputs.usesTexture(); + const bool bUseHWLight = + config.generalEmulation.enableHWLighting != 0 && GBI.isHWLSupported() && combinerInputs.usesShadeColor(); + + if (bUseHWLight) + combinerInputs.addInput(HW_LIGHT); + + std::stringstream ssShader; + + /* Write headers */ + m_fragmentHeader->write(ssShader); + + if (bUseTextures) { + m_fragmentGlobalVariablesTex->write(ssShader); + + if (gDP.otherMode.cycleType == G_CYC_2CYCLE && config.generalEmulation.enableLegacyBlending == 0) + ssShader << "uniform lowp ivec4 uBlendMux2;" << std::endl << "uniform lowp int uForceBlendCycle2;" << std::endl; + + m_fragmentHeaderNoise->write(ssShader); + m_fragmentHeaderDither->write(ssShader); + m_fragmentHeaderWriteDepth->write(ssShader); + m_fragmentHeaderDepthCompare->write(ssShader); + m_fragmentHeaderReadMSTex->write(ssShader); + if (bUseLod) + m_fragmentHeaderMipMap->write(ssShader); + else + m_fragmentHeaderReadTex->write(ssShader); + } else { + m_fragmentGlobalVariablesNotex->write(ssShader); + + if (gDP.otherMode.cycleType == G_CYC_2CYCLE && config.generalEmulation.enableLegacyBlending == 0) + ssShader << "uniform lowp ivec4 uBlendMux2;" << std::endl << "uniform lowp int uForceBlendCycle2;" << std::endl; + + m_fragmentHeaderNoise->write(ssShader); + m_fragmentHeaderDither->write(ssShader); + m_fragmentHeaderWriteDepth->write(ssShader); + m_fragmentHeaderDepthCompare->write(ssShader); + } + + m_fragmentHeaderCalcLight->write(ssShader); + + /* Write body */ + if (gDP.otherMode.cycleType == G_CYC_2CYCLE) + m_fragmentMain2Cycle->write(ssShader); + else + m_fragmentMain->write(ssShader); + + m_fragmentBlendMux->write(ssShader); + + if (bUseLod) { + m_fragmentReadTexMipmap->write(ssShader); + } else { + if (combinerInputs.usesTile(0)) + m_fragmentReadTex0->write(ssShader); + + if (combinerInputs.usesTile(1)) + m_fragmentReadTex1->write(ssShader); + } + + if (bUseHWLight) + ssShader << " calc_light(vNumLights, vShadeColor.rgb, input_color);" << std::endl; + else + ssShader << " input_color = vShadeColor.rgb;" << std::endl; + + ssShader << " vec_color = vec4(input_color, vShadeColor.a);" << std::endl; + ssShader << strCombiner << std::endl; + + if (config.frameBufferEmulation.N64DepthCompare != 0) + m_fragmentCallN64Depth->write(ssShader); + else + m_fragmentRenderTarget->write(ssShader); + + // End of Main() function + ssShader << "}" << std::endl << std::endl; + + /* Write other functions */ + if (bUseHWLight) + m_shaderCalcLight->write(ssShader); + + if (bUseLod) + m_shaderMipmap->write(ssShader); + else if (bUseTextures) + m_shaderReadtex->write(ssShader); + + m_shaderNoise->write(ssShader); + + m_shaderDither->write(ssShader); + + m_shaderWriteDepth->write(ssShader); + + m_shaderN64DepthCompare->write(ssShader); + + m_shaderN64DepthRender->write(ssShader); + + const std::string strFragmentShader(std::move(ssShader.str())); + + /* Create shader program */ + + GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + const GLchar * strShaderData = strFragmentShader.data(); + glShaderSource(fragmentShader, 1, &strShaderData, nullptr); + glCompileShader(fragmentShader); + if (!Utils::checkShaderCompileStatus(fragmentShader)) + Utils::logErrorShader(GL_FRAGMENT_SHADER, strFragmentShader); + + GLuint program = glCreateProgram(); + const bool bIsRect = _key.isRectKey(); + Utils::locateAttributes(program, bIsRect, bUseTextures); + if (bIsRect) + glAttachShader(program, bUseTextures ? m_vertexShaderTexturedRect : m_vertexShaderRect); + else + glAttachShader(program, bUseTextures ? m_vertexShaderTexturedTriangle : m_vertexShaderTriangle); + glAttachShader(program, fragmentShader); + if (CombinerInfo::get().isShaderCacheSupported()) + glProgramParameteri(program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); + glLinkProgram(program); + assert(Utils::checkProgramLinkStatus(program)); + glDeleteShader(fragmentShader); +// _locateUniforms(); + + + return nullptr; +} + +static +GLuint _createVertexShader(ShaderPart * _header, ShaderPart * _body) +{ + std::stringstream ssShader; + _header->write(ssShader); + _body->write(ssShader); + const std::string strShader(std::move(ssShader.str())); + const GLchar * strShaderData = strShader.data(); + + GLuint shader_object = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(shader_object, 1, &strShaderData, nullptr); + glCompileShader(shader_object); + assert(Utils::checkShaderCompileStatus(shader_object)); + return shader_object; +} + +CombinerProgramBuilder::CombinerProgramBuilder(const opengl::GLInfo & _version) +: m_blender1(new ShaderBlender1(_version)) +, m_blender2(new ShaderBlender2(_version)) +, m_legacyBlender(new ShaderLegacyBlender) +, m_clamp(new ShaderClamp) +, m_signExtendColorC(new ShaderSignExtendColorC) +, m_signExtendAlphaC(new ShaderSignExtendAlphaC) +, m_signExtendColorABD(new ShaderSignExtendColorABD) +, m_signExtendAlphaABD(new ShaderSignExtendAlphaABD) +, m_alphaTest(new ShaderAlphaTest) +, m_callDither(new ShaderCallDither(_version)) +, m_vertexHeader(new VertexShaderHeader(_version)) +, m_vertexRect(new VertexShaderRect(_version)) +, m_vertexTexturedRect(new VertexShaderTexturedRect(_version)) +, m_vertexTriangle(new VertexShaderTriangle(_version)) +, m_vertexTexturedTriangle(new VertexShaderTexturedTriangle(_version)) +, m_fragmentHeader(new FragmentShaderHeader(_version)) +, m_fragmentGlobalVariablesTex(new ShaderFragmentGlobalVariablesTex(_version)) +, m_fragmentGlobalVariablesNotex(new ShaderFragmentGlobalVariablesNotex(_version)) +, m_fragmentHeaderNoise(new ShaderFragmentHeaderNoise(_version)) +, m_fragmentHeaderWriteDepth(new ShaderFragmentHeaderWriteDepth(_version)) +, m_fragmentHeaderCalcLight(new ShaderFragmentHeaderCalcLight(_version)) +, m_fragmentHeaderMipMap(new ShaderFragmentHeaderMipMap(_version)) +, m_fragmentHeaderReadMSTex(new ShaderFragmentHeaderReadMSTex(_version)) +, m_fragmentHeaderDither(new ShaderFragmentHeaderDither(_version)) +, m_fragmentHeaderDepthCompare(new ShaderFragmentHeaderDepthCompare(_version)) +, m_fragmentHeaderReadTex(new ShaderFragmentHeaderReadTex(_version)) +, m_fragmentMain(new ShaderFragmentMain(_version)) +, m_fragmentMain2Cycle(new ShaderFragmentMain2Cycle(_version)) +, m_fragmentBlendMux(new ShaderFragmentBlendMux(_version)) +, m_fragmentReadTex0(new ShaderFragmentReadTex0(_version)) +, m_fragmentReadTex1(new ShaderFragmentReadTex1(_version)) +, m_fragmentReadTexMipmap(new ShaderFragmentReadTexMipmap(_version)) +, m_fragmentCallN64Depth(new ShaderFragmentCallN64Depth(_version)) +, m_fragmentRenderTarget(new ShaderFragmentRenderTarget(_version)) +, m_shaderNoise(new ShaderNoise(_version)) +, m_shaderDither(new ShaderDither(_version)) +, m_shaderWriteDepth(new ShaderWriteDepth(_version)) +, m_shaderMipmap(new ShaderMipmap(_version)) +, m_shaderCalcLight(new ShaderCalcLight(_version)) +, m_shaderReadtex(new ShaderReadtex(_version)) +, m_shaderN64DepthCompare(new ShaderN64DepthCompare(_version)) +, m_shaderN64DepthRender(new ShaderN64DepthRender(_version)) +{ + m_vertexShaderRect = _createVertexShader(m_vertexHeader.get(), m_vertexRect.get()); + m_vertexShaderTriangle = _createVertexShader(m_vertexHeader.get(), m_vertexTriangle.get()); + m_vertexShaderTexturedRect = _createVertexShader(m_vertexHeader.get(), m_vertexTexturedRect.get()); + m_vertexShaderTexturedTriangle = _createVertexShader(m_vertexHeader.get(), m_vertexTexturedTriangle.get()); +} CombinerProgramBuilder::~CombinerProgramBuilder() { diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.h b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.h index 360f3f0f..1625bc07 100644 --- a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.h +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.h @@ -1,17 +1,86 @@ #pragma once +#include +#include +#include #include +#include #include -namespace opengl { namespace glsl { + class ShaderPart + { + public: + void write(std::stringstream & shader) + { + shader << m_part; + } + + protected: + std::string m_part; + }; + class CombinerProgramBuilder { public: - CombinerProgramBuilder(); + CombinerProgramBuilder(const opengl::GLInfo & _version); ~CombinerProgramBuilder(); graphics::CombinerProgram * buildCombinerProgram(Combiner & _color, Combiner & _alpha, const CombinerKey & _key); + + private: + int compileCombiner(const CombinerKey & _key, Combiner & _color, Combiner & _alpha, std::string & _strShader); + + typedef std::unique_ptr ShaderPartPtr; + ShaderPartPtr m_blender1; + ShaderPartPtr m_blender2; + ShaderPartPtr m_legacyBlender; + ShaderPartPtr m_clamp; + ShaderPartPtr m_signExtendColorC; + ShaderPartPtr m_signExtendAlphaC; + ShaderPartPtr m_signExtendColorABD; + ShaderPartPtr m_signExtendAlphaABD; + ShaderPartPtr m_alphaTest; + ShaderPartPtr m_callDither; + + ShaderPartPtr m_vertexHeader; + ShaderPartPtr m_vertexRect; + ShaderPartPtr m_vertexTexturedRect; + ShaderPartPtr m_vertexTriangle; + ShaderPartPtr m_vertexTexturedTriangle; + + ShaderPartPtr m_fragmentHeader; + ShaderPartPtr m_fragmentGlobalVariablesTex; + ShaderPartPtr m_fragmentGlobalVariablesNotex; + ShaderPartPtr m_fragmentHeaderNoise; + ShaderPartPtr m_fragmentHeaderWriteDepth; + ShaderPartPtr m_fragmentHeaderCalcLight; + ShaderPartPtr m_fragmentHeaderMipMap; + ShaderPartPtr m_fragmentHeaderReadMSTex; + ShaderPartPtr m_fragmentHeaderDither; + ShaderPartPtr m_fragmentHeaderDepthCompare; + ShaderPartPtr m_fragmentHeaderReadTex; + ShaderPartPtr m_fragmentMain; + ShaderPartPtr m_fragmentMain2Cycle; + ShaderPartPtr m_fragmentBlendMux; + ShaderPartPtr m_fragmentReadTex0; + ShaderPartPtr m_fragmentReadTex1; + ShaderPartPtr m_fragmentReadTexMipmap; + ShaderPartPtr m_fragmentCallN64Depth; + ShaderPartPtr m_fragmentRenderTarget; + + ShaderPartPtr m_shaderNoise; + ShaderPartPtr m_shaderDither; + ShaderPartPtr m_shaderWriteDepth; + ShaderPartPtr m_shaderMipmap; + ShaderPartPtr m_shaderCalcLight; + ShaderPartPtr m_shaderReadtex; + ShaderPartPtr m_shaderN64DepthCompare; + ShaderPartPtr m_shaderN64DepthRender; + + GLuint m_vertexShaderRect; + GLuint m_vertexShaderTriangle; + GLuint m_vertexShaderTexturedRect; + GLuint m_vertexShaderTexturedTriangle; }; } -} \ No newline at end of file diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramImpl.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramImpl.cpp index b9585e25..91396d8b 100644 --- a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramImpl.cpp +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramImpl.cpp @@ -1,6 +1,50 @@ +#include #include "glsl_CombinerProgramImpl.h" -using namespace opengl::glsl; +using namespace glsl; + +/*---------------CombinerInputs-------------*/ + +bool CombinerInputs::usesTile(u32 _t) const +{ + if (_t == 0) + return (m_inputs & ((1 << TEXEL0) | (1 << TEXEL0_ALPHA))) != 0; + return (m_inputs & ((1 << TEXEL1) | (1 << TEXEL1_ALPHA))) != 0; +} + +bool CombinerInputs::usesTexture() const +{ + return (m_inputs & ((1 << TEXEL1) | (1 << TEXEL1_ALPHA) | (1 << TEXEL0) | (1 << TEXEL0_ALPHA))) != 0; +} + +bool CombinerInputs::usesLOD() const +{ + return (m_inputs & (1 << LOD_FRACTION)) != 0; +} + +bool CombinerInputs::usesShade() const +{ + return (m_inputs & ((1 << SHADE) | (1 << SHADE_ALPHA))) != 0; +} + +bool CombinerInputs::usesShadeColor() const +{ + return (m_inputs & (1 << SHADE)) != 0; +} + +bool CombinerInputs::usesHwLighting() const +{ + return (m_inputs & (1 << HW_LIGHT)) != 0; +} + +void CombinerInputs::addInput(int _input) +{ + m_inputs |= 1 << _input; +} + + +/*---------------CombinerProgramImpl-------------*/ + CombinerProgramImpl::CombinerProgramImpl() { diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramImpl.h b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramImpl.h index 23b8c974..43f8be86 100644 --- a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramImpl.h +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramImpl.h @@ -1,9 +1,31 @@ #pragma once #include -namespace opengl { namespace glsl { + class CombinerInputs + { + public: + explicit CombinerInputs(int _inputs) : m_inputs(_inputs) {} + + bool usesTile(u32 _t) const; + + bool usesTexture() const; + + bool usesLOD() const; + + bool usesShade() const; + + bool usesShadeColor() const; + + bool usesHwLighting() const; + + void addInput(int _input); + + private: + int m_inputs; + }; + class CombinerProgramImpl : public graphics::CombinerProgram { public: @@ -16,4 +38,3 @@ namespace glsl { }; } -} \ No newline at end of file diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_Utils.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_Utils.cpp new file mode 100644 index 00000000..5e9aa6c6 --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_Utils.cpp @@ -0,0 +1,76 @@ +#include +#include +#include "glsl_Utils.h" + +using namespace glsl; + +void Utils::locateAttributes(GLuint _program, bool _rect, bool _textures) +{ + if (_rect) { + glBindAttribLocation(_program, opengl::rectAttrib::position, "aRectPosition"); + glBindAttribLocation(_program, opengl::rectAttrib::color, "aRectColor"); + if (_textures) { + glBindAttribLocation(_program, opengl::rectAttrib::texcoord0, "aTexCoord0"); + glBindAttribLocation(_program, opengl::rectAttrib::texcoord1, "aTexCoord1"); + } + return; + } + + glBindAttribLocation(_program, opengl::triangleAttrib::position, "aPosition"); + glBindAttribLocation(_program, opengl::triangleAttrib::color, "aColor"); + glBindAttribLocation(_program, opengl::triangleAttrib::numlights, "aNumLights"); + glBindAttribLocation(_program, opengl::triangleAttrib::modify, "aModify"); + if (_textures) + glBindAttribLocation(_program, opengl::triangleAttrib::texcoord, "aTexCoord"); +} + + +static const GLsizei nShaderLogSize = 1024; + +bool Utils::checkShaderCompileStatus(GLuint obj) +{ + GLint status; + glGetShaderiv(obj, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) { + GLchar shader_log[nShaderLogSize]; + GLsizei nLogSize = nShaderLogSize; + glGetShaderInfoLog(obj, nShaderLogSize, &nLogSize, shader_log); + shader_log[nLogSize] = 0; + LOG(LOG_ERROR, "shader_compile error: %s\n", shader_log); + return false; + } + return true; +} + +bool Utils::checkProgramLinkStatus(GLuint obj) +{ + GLint status; + glGetProgramiv(obj, GL_LINK_STATUS, &status); + if (status == GL_FALSE) { + GLsizei nLogSize = nShaderLogSize; + GLchar shader_log[nShaderLogSize]; + glGetProgramInfoLog(obj, nShaderLogSize, &nLogSize, shader_log); + LOG(LOG_ERROR, "shader_link error: %s\n", shader_log); + return false; + } + return true; +} + +void Utils::logErrorShader(GLenum _shaderType, const std::string & _strShader) +{ + LOG(LOG_ERROR, "Error in %s shader", _shaderType == GL_VERTEX_SHADER ? "vertex" : "fragment"); + + const int max = 800; + int pos = 0; + + while (pos < _strShader.length()) { + + if (_strShader.length() - pos < max) { + LOG(LOG_ERROR, "%s", _strShader.substr(pos).data()); + } + else { + LOG(LOG_ERROR, "%s", _strShader.substr(pos, max).data()); + } + pos += max; + } +} diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_Utils.h b/src/Graphics/OpenGLContext/GLSL/glsl_Utils.h new file mode 100644 index 00000000..ff4df8c0 --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_Utils.h @@ -0,0 +1,13 @@ +#pragma once +#include +#include + +namespace glsl { + + struct Utils { + static void locateAttributes(GLuint _program, bool _rect, bool _textures); + static bool checkShaderCompileStatus(GLuint obj); + static bool checkProgramLinkStatus(GLuint obj); + static void logErrorShader(GLenum _shaderType, const std::string & _strShader); + }; +} diff --git a/src/Graphics/OpenGLContext/opengl_Attributes.cpp b/src/Graphics/OpenGLContext/opengl_Attributes.cpp new file mode 100644 index 00000000..b493d854 --- /dev/null +++ b/src/Graphics/OpenGLContext/opengl_Attributes.cpp @@ -0,0 +1,21 @@ +#include "opengl_Attributes.h" + +namespace opengl { + + namespace triangleAttrib { + const GLuint position = 1U; + const GLuint color = 2U; + const GLuint texcoord = 3U; + const GLuint numlights = 4U; + const GLuint modify = 5U; + } + + // Rect attributes + namespace rectAttrib { + const GLuint position = 6U; + const GLuint color = 7U; + const GLuint texcoord0 = 8U; + const GLuint texcoord1 = 9U; + } + +} diff --git a/src/Graphics/OpenGLContext/opengl_Attributes.h b/src/Graphics/OpenGLContext/opengl_Attributes.h new file mode 100644 index 00000000..40111338 --- /dev/null +++ b/src/Graphics/OpenGLContext/opengl_Attributes.h @@ -0,0 +1,23 @@ +#pragma once +#include "GLFunctions.h" + +namespace opengl { + + // Triangle attributes + namespace triangleAttrib { + extern const GLuint position; + extern const GLuint color; + extern const GLuint texcoord; + extern const GLuint numlights; + extern const GLuint modify; + } + + // Rect attributes + namespace rectAttrib { + extern const GLuint position; + extern const GLuint color; + extern const GLuint texcoord0; + extern const GLuint texcoord1; + } + +} diff --git a/src/Graphics/OpenGLContext/opengl_BufferManipulationObjectFactory.cpp b/src/Graphics/OpenGLContext/opengl_BufferManipulationObjectFactory.cpp index ca34dbdf..eb848038 100644 --- a/src/Graphics/OpenGLContext/opengl_BufferManipulationObjectFactory.cpp +++ b/src/Graphics/OpenGLContext/opengl_BufferManipulationObjectFactory.cpp @@ -1,5 +1,5 @@ #include -#include "opengl_GLVersion.h" +#include "opengl_GLInfo.h" #include "opengl_CachedFunctions.h" #include "opengl_BufferManipulationObjectFactory.h" @@ -23,9 +23,9 @@ public: class CreateFramebuffer : public CreateFramebufferObject { public: - static bool Check(const GLVersion & _version) { + static bool Check(const GLInfo & _glinfo) { #ifdef ENABLE_GL_4_5 - return (_version.majorVersion > 4) || (_version.majorVersion == 4 && _version.minorVersion >= 5); + return (_glinfo.majorVersion > 4) || (_glinfo.majorVersion == 4 && _glinfo.minorVersion >= 5); #else return false; #endif @@ -101,9 +101,9 @@ private: class AddNamedFramebufferTexture : public AddFramebufferRenderTarget { public: - static bool Check(const GLVersion & _version) { + static bool Check(const GLInfo & _glinfo) { #ifdef ENABLE_GL_4_5 - return (_version.majorVersion > 4) || (_version.majorVersion == 4 && _version.minorVersion >= 5); + return (_glinfo.majorVersion > 4) || (_glinfo.majorVersion == 4 && _glinfo.minorVersion >= 5); #else return false; #endif @@ -120,9 +120,9 @@ public: /*---------------BufferManipulationObjectFactory-------------*/ -BufferManipulationObjectFactory::BufferManipulationObjectFactory(const GLVersion & _version, +BufferManipulationObjectFactory::BufferManipulationObjectFactory(const GLInfo & _info, CachedFunctions & _cachedFunctions) - : m_version(_version) + : m_glInfo(_info) , m_cachedFunctions(_cachedFunctions) { } @@ -134,7 +134,7 @@ BufferManipulationObjectFactory::~BufferManipulationObjectFactory() CreateFramebufferObject * BufferManipulationObjectFactory::getCreateFramebufferObject() const { - if (CreateFramebuffer::Check(m_version)) + if (CreateFramebuffer::Check(m_glInfo)) return new CreateFramebuffer; return new GenFramebuffer; @@ -152,7 +152,7 @@ InitRenderbuffer * BufferManipulationObjectFactory::getInitRenderbuffer() const AddFramebufferRenderTarget * BufferManipulationObjectFactory::getAddFramebufferRenderTarget() const { - if (AddNamedFramebufferTexture::Check(m_version)) + if (AddNamedFramebufferTexture::Check(m_glInfo)) return new AddNamedFramebufferTexture; return new AddFramebufferTexture2D(m_cachedFunctions.geCachedBindFramebuffer()); diff --git a/src/Graphics/OpenGLContext/opengl_BufferManipulationObjectFactory.h b/src/Graphics/OpenGLContext/opengl_BufferManipulationObjectFactory.h index 48b100cf..47374af3 100644 --- a/src/Graphics/OpenGLContext/opengl_BufferManipulationObjectFactory.h +++ b/src/Graphics/OpenGLContext/opengl_BufferManipulationObjectFactory.h @@ -2,10 +2,11 @@ #include #include #include +#include "opengl_GLInfo.h" namespace opengl { - struct GLVersion; + struct GLInfo; class CachedFunctions; class CreateFramebufferObject @@ -40,7 +41,7 @@ namespace opengl { class BufferManipulationObjectFactory { public: - BufferManipulationObjectFactory(const GLVersion & _version, CachedFunctions & _cachedFunctions); + BufferManipulationObjectFactory(const GLInfo & _info, CachedFunctions & _cachedFunctions); ~BufferManipulationObjectFactory(); CreateFramebufferObject * getCreateFramebufferObject() const; @@ -52,7 +53,7 @@ namespace opengl { AddFramebufferRenderTarget * getAddFramebufferRenderTarget() const; private: - const GLVersion & m_version; + const GLInfo & m_glInfo; CachedFunctions & m_cachedFunctions; }; diff --git a/src/Graphics/OpenGLContext/opengl_ContextImpl.cpp b/src/Graphics/OpenGLContext/opengl_ContextImpl.cpp index 98b34108..eb95b6b6 100644 --- a/src/Graphics/OpenGLContext/opengl_ContextImpl.cpp +++ b/src/Graphics/OpenGLContext/opengl_ContextImpl.cpp @@ -16,24 +16,20 @@ ContextImpl::~ContextImpl() void ContextImpl::init() { - glGetIntegerv(GL_MAJOR_VERSION, &m_version.majorVersion); - LOG(LOG_VERBOSE, "OpenGL major version: %d\n", m_version.majorVersion); - assert(m_version.majorVersion >= 3 && "Plugin requires GL version 3 or higher."); - glGetIntegerv(GL_MINOR_VERSION, &m_version.minorVersion); - LOG(LOG_VERBOSE, "OpenGL minor version: %d\n", m_version.minorVersion); + m_glInfo.init(); if (!m_cachedFunctions) m_cachedFunctions.reset(new CachedFunctions); { - TextureManipulationObjectFactory textureObjectsFactory(m_version, *m_cachedFunctions.get()); + TextureManipulationObjectFactory textureObjectsFactory(m_glInfo, *m_cachedFunctions.get()); m_createTexture.reset(textureObjectsFactory.getCreate2DTexture()); m_init2DTexture.reset(textureObjectsFactory.getInit2DTexture()); m_set2DTextureParameters.reset(textureObjectsFactory.getSet2DTextureParameters()); } { - BufferManipulationObjectFactory bufferObjectFactory(m_version, *m_cachedFunctions.get()); + BufferManipulationObjectFactory bufferObjectFactory(m_glInfo, *m_cachedFunctions.get()); m_createFramebuffer.reset(bufferObjectFactory.getCreateFramebufferObject()); m_createRenderbuffer.reset(bufferObjectFactory.getCreateRenderbuffer()); m_initRenderbuffer.reset(bufferObjectFactory.getInitRenderbuffer()); diff --git a/src/Graphics/OpenGLContext/opengl_ContextImpl.h b/src/Graphics/OpenGLContext/opengl_ContextImpl.h index f59943ed..48e2693e 100644 --- a/src/Graphics/OpenGLContext/opengl_ContextImpl.h +++ b/src/Graphics/OpenGLContext/opengl_ContextImpl.h @@ -3,7 +3,7 @@ #include #include "opengl_TextureManipulationObjectFactory.h" #include "opengl_BufferManipulationObjectFactory.h" -#include "opengl_GLVersion.h" +#include "opengl_GLInfo.h" #include "opengl_CachedFunctions.h" namespace opengl { @@ -49,7 +49,7 @@ namespace opengl { std::unique_ptr m_initRenderbuffer; std::unique_ptr m_addFramebufferRenderTarget; - GLVersion m_version; + GLInfo m_glInfo; }; } diff --git a/src/Graphics/OpenGLContext/opengl_GLInfo.cpp b/src/Graphics/OpenGLContext/opengl_GLInfo.cpp new file mode 100644 index 00000000..b5bc49a0 --- /dev/null +++ b/src/Graphics/OpenGLContext/opengl_GLInfo.cpp @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include "opengl_Utilis.h" +#include "opengl_GLInfo.h" + +using namespace opengl; + +void GLInfo::init() { + const char * strVersion = reinterpret_cast(glGetString(GL_VERSION)); + isGLESX = strstr(strVersion, "OpenGL ES") != nullptr; + isGLES2 = strstr(strVersion, "OpenGL ES 2") != nullptr; + if (isGLES2) { + majorVersion = 2; + minorVersion = 0; + } + else { + glGetIntegerv(GL_MAJOR_VERSION, &majorVersion); + glGetIntegerv(GL_MINOR_VERSION, &minorVersion); + } + LOG(LOG_VERBOSE, "%s major version: %d\n", isGLESX ? "OpenGL ES" : "OpenGL", majorVersion); + LOG(LOG_VERBOSE, "%s minor version: %d\n", isGLESX ? "OpenGL ES" : "OpenGL", minorVersion); + +#ifdef GL_NUM_PROGRAM_BINARY_FORMATS + GLint numBinaryFormats = 0; + glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numBinaryFormats); + const char * strGetProgramBinary = isGLESX + ? "GL_OES_get_program_binary" + : "GL_ARB_get_program_binary"; + shaderStorage = numBinaryFormats > 0 && + config.generalEmulation.enableShadersStorage != 0 && + Utils::isExtensionSupported(strGetProgramBinary); +#else + shaderStorage =false; +#endif +} diff --git a/src/Graphics/OpenGLContext/opengl_GLInfo.h b/src/Graphics/OpenGLContext/opengl_GLInfo.h new file mode 100644 index 00000000..2cf394e4 --- /dev/null +++ b/src/Graphics/OpenGLContext/opengl_GLInfo.h @@ -0,0 +1,16 @@ +#pragma once +#include "GLFunctions.h" + +namespace opengl { + + struct GLInfo { + GLint majorVersion = 0; + GLint minorVersion = 0; + bool isGLES2 = false; + bool isGLESX = false; + bool imageTextures = false; + bool shaderStorage = false; + + void init(); + }; +} diff --git a/src/Graphics/OpenGLContext/opengl_GLVersion.h b/src/Graphics/OpenGLContext/opengl_GLVersion.h deleted file mode 100644 index 3ddb00ce..00000000 --- a/src/Graphics/OpenGLContext/opengl_GLVersion.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "GLFunctions.h" - -namespace opengl { - - struct GLVersion { - GLint majorVersion = 0; - GLint minorVersion = 0; - }; -} diff --git a/src/Graphics/OpenGLContext/opengl_TextureManipulationObjectFactory.cpp b/src/Graphics/OpenGLContext/opengl_TextureManipulationObjectFactory.cpp index a2cb426c..97025ea6 100644 --- a/src/Graphics/OpenGLContext/opengl_TextureManipulationObjectFactory.cpp +++ b/src/Graphics/OpenGLContext/opengl_TextureManipulationObjectFactory.cpp @@ -1,6 +1,6 @@ #include #include -#include "opengl_GLVersion.h" +#include "opengl_GLInfo.h" #include "opengl_CachedFunctions.h" #include "opengl_TextureManipulationObjectFactory.h" @@ -25,9 +25,9 @@ namespace opengl { class CreateTexture : public Create2DTexture { public: - static bool Check(const GLVersion & _version) { + static bool Check(const GLInfo & _glinfo) { #ifdef ENABLE_GL_4_5 - return (_version.majorVersion > 4) || (_version.majorVersion == 4 && _version.minorVersion >= 5); + return (_glinfo.majorVersion > 4) || (_glinfo.majorVersion == 4 && _glinfo.minorVersion >= 5); #else return false; #endif @@ -84,9 +84,9 @@ namespace opengl { class Init2DTexStorage : public Init2DTexture { public: - static bool Check(const GLVersion & _version) { + static bool Check(const GLInfo & _glinfo) { #ifdef ENABLE_GL_4_2 - return (_version.majorVersion > 4) || (_version.majorVersion == 4 && _version.minorVersion >= 2); + return (_glinfo.majorVersion > 4) || (_glinfo.majorVersion == 4 && _glinfo.minorVersion >= 2); #else return false; #endif @@ -142,9 +142,9 @@ namespace opengl { class Init2DTextureStorage : public Init2DTexture { public: - static bool Check(const GLVersion & _version) { + static bool Check(const GLInfo & _glinfo) { #ifdef ENABLE_GL_4_5 - return (_version.majorVersion > 4) || (_version.majorVersion == 4 && _version.minorVersion >= 5); + return (_glinfo.majorVersion > 4) || (_glinfo.majorVersion == 4 && _glinfo.minorVersion >= 5); #else return false; #endif @@ -230,9 +230,9 @@ namespace opengl { class SetTextureParameters : public Set2DTextureParameters { public: - static bool Check(const GLVersion & _version) { + static bool Check(const GLInfo & _glinfo) { #ifdef ENABLE_GL_4_5 - return (_version.majorVersion > 4) || (_version.majorVersion == 4 && _version.minorVersion >= 5); + return (_glinfo.majorVersion > 4) || (_glinfo.majorVersion == 4 && _glinfo.minorVersion >= 5); #else return false; #endif @@ -272,9 +272,9 @@ namespace opengl { /*---------------TextureManipulationObjectFactory-------------*/ - TextureManipulationObjectFactory::TextureManipulationObjectFactory(const GLVersion & _version, + TextureManipulationObjectFactory::TextureManipulationObjectFactory(const GLInfo & _glinfo, CachedFunctions & _cachedFunctions) - : m_version(_version) + : m_glInfo(_glinfo) , m_cachedFunctions(_cachedFunctions) { } @@ -285,7 +285,7 @@ namespace opengl { Create2DTexture * TextureManipulationObjectFactory::getCreate2DTexture() const { - if (CreateTexture::Check(m_version)) + if (CreateTexture::Check(m_glInfo)) return new CreateTexture; return new GenTexture; @@ -293,10 +293,10 @@ namespace opengl { Init2DTexture * TextureManipulationObjectFactory::getInit2DTexture() const { - if (Init2DTextureStorage::Check(m_version)) + if (Init2DTextureStorage::Check(m_glInfo)) return new Init2DTextureStorage; - if (Init2DTexStorage::Check(m_version)) + if (Init2DTexStorage::Check(m_glInfo)) return new Init2DTexStorage(m_cachedFunctions.getCachedBindTexture()); return new Init2DTexImage(m_cachedFunctions.getCachedBindTexture()); @@ -304,7 +304,7 @@ namespace opengl { Set2DTextureParameters * TextureManipulationObjectFactory::getSet2DTextureParameters() const { - if (SetTextureParameters::Check(m_version)) + if (SetTextureParameters::Check(m_glInfo)) return new SetTextureParameters; return new SetTexParameters(m_cachedFunctions.geCachedActiveTexture(), diff --git a/src/Graphics/OpenGLContext/opengl_TextureManipulationObjectFactory.h b/src/Graphics/OpenGLContext/opengl_TextureManipulationObjectFactory.h index d3aaa21c..35078b6e 100644 --- a/src/Graphics/OpenGLContext/opengl_TextureManipulationObjectFactory.h +++ b/src/Graphics/OpenGLContext/opengl_TextureManipulationObjectFactory.h @@ -5,7 +5,7 @@ namespace opengl { - struct GLVersion; + struct GLInfo; class CachedFunctions; class Create2DTexture @@ -33,7 +33,7 @@ namespace opengl { class TextureManipulationObjectFactory { public: - TextureManipulationObjectFactory(const GLVersion & _version, CachedFunctions & _cachedFunctions); + TextureManipulationObjectFactory(const GLInfo & _glinfo, CachedFunctions & _cachedFunctions); ~TextureManipulationObjectFactory(); Create2DTexture * getCreate2DTexture() const; @@ -43,7 +43,7 @@ namespace opengl { Set2DTextureParameters * getSet2DTextureParameters() const; private: - const GLVersion & m_version; + const GLInfo & m_glInfo; CachedFunctions & m_cachedFunctions; }; diff --git a/src/Graphics/OpenGLContext/opengl_Utilis.cpp b/src/Graphics/OpenGLContext/opengl_Utilis.cpp index cf947e81..28cf27b0 100644 --- a/src/Graphics/OpenGLContext/opengl_Utilis.cpp +++ b/src/Graphics/OpenGLContext/opengl_Utilis.cpp @@ -2,7 +2,9 @@ #include "opengl_Utilis.h" #include "GLFunctions.h" -bool opengl::isExtensionSupported(const char *extension) +using namespace opengl; + +bool Utils::isExtensionSupported(const char *extension) { #ifdef GL_NUM_EXTENSIONS GLint count = 0; diff --git a/src/Graphics/OpenGLContext/opengl_Utilis.h b/src/Graphics/OpenGLContext/opengl_Utilis.h index 8998a540..781f3df5 100644 --- a/src/Graphics/OpenGLContext/opengl_Utilis.h +++ b/src/Graphics/OpenGLContext/opengl_Utilis.h @@ -2,6 +2,9 @@ namespace opengl { - bool isExtensionSupported(const char * extension); + struct Utils + { + static bool isExtensionSupported(const char * extension); + }; }