diff --git a/plugins/zzogl-pg/opengl/CMakeLists.txt b/plugins/zzogl-pg/opengl/CMakeLists.txt index 860b0d8d85..5f788c77ed 100644 --- a/plugins/zzogl-pg/opengl/CMakeLists.txt +++ b/plugins/zzogl-pg/opengl/CMakeLists.txt @@ -20,7 +20,6 @@ set(CommonFlags -fno-strict-aliasing -Wstrict-aliasing # Allow to track strict aliasing issue. -Wunused-variable - #-DOGL4_LOG # Easier for development ) set(OptimizationFlags @@ -31,7 +30,7 @@ set(OptimizationFlags # Debug - Build if(CMAKE_BUILD_TYPE STREQUAL Debug) # add defines - add_definitions(${CommonFlags} -g -Wall -D_DEBUG) + add_definitions(${CommonFlags} -g -Wall -D_DEBUG) endif(CMAKE_BUILD_TYPE STREQUAL Debug) # Devel - Build @@ -48,7 +47,8 @@ endif(CMAKE_BUILD_TYPE STREQUAL Release) # Select the shader API if(GLSL_API) - add_definitions(-DGLSL_API) + add_definitions(-DGLSL_API -DGLSL4_API -DOGL4_LOG) + #add_definitions(-DGLSL_API) else(GLSL_API) add_definitions(-DNVIDIA_CG_API) endif(GLSL_API) @@ -87,6 +87,7 @@ set(zzoglSources ZZoglSave.cpp ZZoglShaders.cpp ZZoglShadersGLSL.cpp + ZZoglShadersGLSL4.cpp ZZoglShoots.cpp ZZoglVB.cpp ) @@ -190,7 +191,8 @@ endif(NOT USER_CMAKE_LD_FLAGS STREQUAL "") if(PACKAGE_MODE) install(TARGETS ${Output} DESTINATION ${PLUGIN_DIR}) if(GLSL_API) - install(FILES ${PROJECT_SOURCE_DIR}/plugins/zzogl-pg/opengl/ps2hw.glsl DESTINATION ${PLUGIN_DIR}) + install(FILES ${PROJECT_SOURCE_DIR}/plugins/zzogl-pg/opengl/ps2hw.glsl DESTINATION ${GLSL_SHADER_DIR}) + install(FILES ${PROJECT_SOURCE_DIR}/plugins/zzogl-pg/opengl/ps2hw_gl4.glsl DESTINATION ${GLSL_SHADER_DIR}) else(GLSL_API) if(NOT REBUILD_SHADER) install(FILES ${PROJECT_SOURCE_DIR}/plugins/zzogl-pg/opengl/ps2hw.dat DESTINATION ${PLUGIN_DIR}) @@ -200,6 +202,7 @@ else(PACKAGE_MODE) install(TARGETS ${Output} DESTINATION ${CMAKE_SOURCE_DIR}/bin/plugins) if(GLSL_API) install(FILES ${PROJECT_SOURCE_DIR}/plugins/zzogl-pg/opengl/ps2hw.glsl DESTINATION ${CMAKE_SOURCE_DIR}/bin/plugins) + install(FILES ${PROJECT_SOURCE_DIR}/plugins/zzogl-pg/opengl/ps2hw_gl4.glsl DESTINATION ${CMAKE_SOURCE_DIR}/bin/plugins) else(GLSL_API) if(NOT REBUILD_SHADER) install(FILES ${PROJECT_SOURCE_DIR}/plugins/zzogl-pg/opengl/ps2hw.dat DESTINATION ${CMAKE_SOURCE_DIR}/bin/plugins) diff --git a/plugins/zzogl-pg/opengl/GLWinX11.cpp b/plugins/zzogl-pg/opengl/GLWinX11.cpp index 5e0215689f..ed286c196e 100644 --- a/plugins/zzogl-pg/opengl/GLWinX11.cpp +++ b/plugins/zzogl-pg/opengl/GLWinX11.cpp @@ -228,9 +228,9 @@ bool GLWindow::CreateContextGL(int major, int minor) void GLWindow::CreateContextGL() { -#ifdef OGL4_LOG - // We need to define a debug context. So we need at a 3.0 context (if not 3.2) - CreateContextGL(4, 1); +#if defined(OGL4_LOG) || defined(GLSL4_API) + // We need to define a debug context. So we need at a 3.0 context (if not 3.2 actually) + CreateContextGL(4, 2); #else // FIXME there was some issue with previous context creation on Geforce7. Code was rewritten // for GSdx unfortunately it was not tested on Geforce7 so keep the 2.0 context for now. diff --git a/plugins/zzogl-pg/opengl/GS.h b/plugins/zzogl-pg/opengl/GS.h index 04052bda1f..562a9ae392 100644 --- a/plugins/zzogl-pg/opengl/GS.h +++ b/plugins/zzogl-pg/opengl/GS.h @@ -26,6 +26,7 @@ #include "Util.h" #include "GifTransfer.h" #include "HostMemory.h" +#include "ZZoglShoots.h" using namespace std; @@ -422,7 +423,7 @@ union tex_0_info #define TEX_HIGHLIGHT 2 #define TEX_HIGHLIGHT2 3 -bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height); +//bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height, int ext_format = 0); extern void SaveTex(tex0Info* ptex, int usevid); extern char* NamedSaveTex(tex0Info* ptex, int usevid); diff --git a/plugins/zzogl-pg/opengl/ZZDepthTargets.cpp b/plugins/zzogl-pg/opengl/ZZDepthTargets.cpp index 24847dcd19..ea553fe256 100644 --- a/plugins/zzogl-pg/opengl/ZZDepthTargets.cpp +++ b/plugins/zzogl-pg/opengl/ZZDepthTargets.cpp @@ -203,7 +203,11 @@ void CDepthTarget::Update(int context, CRenderTarget* prndr) // write color and zero out stencil buf, always 0 context! SetTexVariablesInt(0, 0, texframe, false, &ppsBitBltDepth, 1); +#ifdef GLSL4_API + ZZshGLSetTextureParameter(ppsBitBltDepth.prog, ppsBitBltDepth.sMemory[context], vb[0].pmemtarg->ptex->tex, "BitBltDepth"); +#else ZZshGLSetTextureParameter(ppsBitBltDepth.prog, ppsBitBltDepth.sMemory, vb[0].pmemtarg->ptex->tex, "BitBltDepth"); +#endif float4 v = DefaultBitBltPos(); diff --git a/plugins/zzogl-pg/opengl/ZZRenderTargets.cpp b/plugins/zzogl-pg/opengl/ZZRenderTargets.cpp index 04aba8b967..912824d105 100644 --- a/plugins/zzogl-pg/opengl/ZZRenderTargets.cpp +++ b/plugins/zzogl-pg/opengl/ZZRenderTargets.cpp @@ -432,7 +432,11 @@ void CRenderTarget::Update(int context, CRenderTarget* pdepth) // Fix in r133 -- FFX movies and Gust backgrounds! //SetTexVariablesInt(0, 0*(AA.x || AA.y) ? 2 : 0, texframe, false, &ppsBitBlt[!!s_AAx], 1); SetTexVariablesInt(0, 0, texframe, false, &ppsBitBlt[bit_idx], 1); +#ifdef GLSL4_API + ZZshGLSetTextureParameter(ppsBitBlt[bit_idx].prog, ppsBitBlt[bit_idx].sMemory[context], vb[0].pmemtarg->ptex->tex, "BitBlt.memory"); +#else ZZshGLSetTextureParameter(ppsBitBlt[bit_idx].prog, ppsBitBlt[bit_idx].sMemory, vb[0].pmemtarg->ptex->tex, "BitBlt.memory"); +#endif v = float4(1, 1, 0.0f, 0.0f); ZZshSetParameter4fv(pvsBitBlt.prog, pvsBitBlt.sBitBltTex, v, "g_fBitBltTex"); diff --git a/plugins/zzogl-pg/opengl/ZZoglCRTC.cpp b/plugins/zzogl-pg/opengl/ZZoglCRTC.cpp index 7acd72a291..51bb16e379 100644 --- a/plugins/zzogl-pg/opengl/ZZoglCRTC.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglCRTC.cpp @@ -656,7 +656,13 @@ inline void RenderCheckForMemory(tex0Info& texframe, list& listT v = RenderSetTargetInvTex(texframe.tw, texframe.th, CRTC_RENDER); float4 valpha = RenderGetForClip(texframe.psm, CRTC_RENDER); +#ifdef GLSL4_API + // FIXME context + int context = 0; + ZZshGLSetTextureParameter(curr_ppsCRTC()->prog, curr_ppsCRTC()->sMemory[context], vb[0].pmemtarg->ptex->tex, "CRTC memory"); +#else ZZshGLSetTextureParameter(curr_ppsCRTC()->prog, curr_ppsCRTC()->sMemory, vb[0].pmemtarg->ptex->tex, "CRTC memory"); +#endif RenderCreateInterlaceTex(texframe.th, CRTC_RENDER_TARG); ZZshSetPixelShader(curr_ppsCRTC()->prog); diff --git a/plugins/zzogl-pg/opengl/ZZoglFlush.cpp b/plugins/zzogl-pg/opengl/ZZoglFlush.cpp index 0b33ff320c..6da1539a6f 100644 --- a/plugins/zzogl-pg/opengl/ZZoglFlush.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglFlush.cpp @@ -688,7 +688,7 @@ inline float4 FlushSetPageOffset(FRAGMENTSHADER* pfragment, int shadertype, CRen // zoe2 if (PSMT_ISZTEX(ptextarg->psm)) vpageoffset.w = -1.0f; - ZZshSetParameter4fv(pfragment->fPageOffset, vpageoffset, "g_fPageOffset"); + ZZshSetParameter4fv(pfragment->prog, pfragment->fPageOffset, vpageoffset, "g_fPageOffset"); return vpageoffset; } @@ -706,7 +706,7 @@ inline float4 FlushSetTexOffset(FRAGMENTSHADER* pfragment, int shadertype, VB& c v.y = 16.0f / (float)curvb.tex0.th; v.z = 0.5f * v.x; v.w = 0.5f * v.y; - ZZshSetParameter4fv(pfragment->fTexOffset, v, "g_fTexOffset"); + ZZshSetParameter4fv(pfragment->prog, pfragment->fTexOffset, v, "g_fTexOffset"); } else if (shadertype == 4) { @@ -715,7 +715,7 @@ inline float4 FlushSetTexOffset(FRAGMENTSHADER* pfragment, int shadertype, VB& c v.y = 16.0f / (float)ptextarg->fbh; v.z = -1; v.w = 8.0f / (float)ptextarg->fbh; - ZZshSetParameter4fv(pfragment->fTexOffset, v, "g_fTexOffset"); + ZZshSetParameter4fv(pfragment->prog, pfragment->fTexOffset, v, "g_fTexOffset"); } return v; @@ -749,7 +749,7 @@ inline float4 FlushTextureDims(FRAGMENTSHADER* pfragment, int shadertype, VB& cu if (shadertype == 4) vTexDims.z += 8.0f; - ZZshSetParameter4fv(pfragment->fTexDims, vTexDims, "g_fTexDims"); + ZZshSetParameter4fv(pfragment->prog, pfragment->fTexDims, vTexDims, "g_fTexDims"); return vTexDims; } @@ -799,7 +799,7 @@ inline FRAGMENTSHADER* FlushUseExistRenderTarget(VB& curvb, CRenderTarget* ptext float4 vTexDims = FlushTextureDims(pfragment, shadertype, curvb, ptextarg); if (pfragment->sCLUT != NULL && ptexclut != 0) - ZZshGLSetTextureParameter(pfragment->sCLUT, ptexclut, "CLUT"); + ZZshGLSetTextureParameter(pfragment->prog, pfragment->sCLUT, ptexclut, "CLUT"); FlushApplyResizeFilter(curvb, dwFilterOpts, ptextarg, context); @@ -846,13 +846,17 @@ inline void FlushSetTexture(VB& curvb, FRAGMENTSHADER* pfragment, CRenderTarget* // have to enable the texture parameters(curtest.atst) if( curvb.ptexClamp[0] != 0 ) - ZZshGLSetTextureParameter(pfragment->sBitwiseANDX, curvb.ptexClamp[0], "Clamp 0"); + ZZshGLSetTextureParameter(pfragment->prog, pfragment->sBitwiseANDX, curvb.ptexClamp[0], "Clamp 0"); if( curvb.ptexClamp[1] != 0 ) - ZZshGLSetTextureParameter(pfragment->sBitwiseANDY, curvb.ptexClamp[1], "Clamp 1"); + ZZshGLSetTextureParameter(pfragment->prog, pfragment->sBitwiseANDY, curvb.ptexClamp[1], "Clamp 1"); if( pfragment->sMemory != NULL && s_ptexCurSet[context] != 0) - ZZshGLSetTextureParameter(pfragment->sMemory, s_ptexCurSet[context], "Clamp memory"); +#ifdef GLSL4_API + ZZshGLSetTextureParameter(pfragment->prog, pfragment->sMemory[context], s_ptexCurSet[context], "Clamp memory"); +#else + ZZshGLSetTextureParameter(pfragment->prog, pfragment->sMemory, s_ptexCurSet[context], "Clamp memory"); +#endif } // Reset program and texture variables; @@ -975,7 +979,7 @@ inline void AlphaRenderFBA(VB& curvb, FRAGMENTSHADER* pfragment) // needs to be before RenderAlphaTest if ((gs.pabe) || (curvb.fba.fba && !ZZOglGet_fbmHighByte(curvb.frame.fbm)) || (s_bDestAlphaTest && bCanRenderStencil)) { - RenderFBA(curvb, pfragment->sOneColor); + RenderFBA(curvb, pfragment); } } @@ -990,7 +994,7 @@ inline u32 AlphaRenderAlpha(VB& curvb, const pixTest curtest, FRAGMENTSHADER* pf if ((bNeedBlendFactorInAlpha || ((curtest.ate && curtest.atst > ATST_ALWAYS) && (curtest.aref > 0x80)))) { // need special stencil processing for the alpha - RenderAlphaTest(curvb, pfragment->sOneColor); + RenderAlphaTest(curvb, pfragment); dwUsingSpecialTesting = 1; } @@ -1003,13 +1007,13 @@ inline u32 AlphaRenderAlpha(VB& curvb, const pixTest curtest, FRAGMENTSHADER* pf v.w *= 255; } - ZZshSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor"); + ZZshSetParameter4fv(pfragment->prog, pfragment->sOneColor, v, "g_fOneColor"); } else { // not using blending so set to defaults float4 v = exactcolor ? float4(1, 510 * 255.0f / 256.0f, 0, 0) : float4(1, 2 * 255.0f / 256.0f, 0, 0); - ZZshSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor"); + ZZshSetParameter4fv(pfragment->prog, pfragment->sOneColor, v, "g_fOneColor"); } @@ -1100,7 +1104,7 @@ inline void AlphaPabe(VB& curvb, FRAGMENTSHADER* pfragment, int exactcolor) if (exactcolor) v.y *= 255; - ZZshSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor"); + ZZshSetParameter4fv(pfragment->prog, pfragment->sOneColor, v, "g_fOneColor"); Draw(curvb); @@ -1169,7 +1173,7 @@ inline void AlphaFailureTestJob(VB& curvb, const pixTest curtest, FRAGMENTSHADE if (exactcolor) { v.y *= 255; v.w *= 255; } - ZZshSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor"); + ZZshSetParameter4fv(pfragment->prog, pfragment->sOneColor, v, "g_fOneColor"); glEnable(GL_BLEND); GL_STENCILFUNC(GL_EQUAL, s_stencilref | STENCIL_FBA, s_stencilmask | STENCIL_FBA); @@ -1193,7 +1197,7 @@ inline void AlphaFailureTestJob(VB& curvb, const pixTest curtest, FRAGMENTSHADE if (exactcolor) v.y *= 255; - ZZshSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor"); + ZZshSetParameter4fv(pfragment->prog, pfragment->sOneColor, v, "g_fOneColor"); Draw(curvb); @@ -1245,7 +1249,7 @@ inline void AlphaSpecialTesting(VB& curvb, FRAGMENTSHADER* pfragment, u32 dwUsin glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); float4 v = float4(0, exactcolor ? 510.0f : 2.0f, 0, 0); - ZZshSetParameter4fv(pfragment->sOneColor, v, "g_fOneColor"); + ZZshSetParameter4fv(pfragment->prog, pfragment->sOneColor, v, "g_fOneColor"); Draw(curvb); // don't need to restore @@ -1260,7 +1264,7 @@ inline void AlphaDestinationTest(VB& curvb, FRAGMENTSHADER* pfragment) { if (curvb.fba.fba) { - ProcessFBA(curvb, pfragment->sOneColor); + ProcessFBA(curvb, pfragment); } else if (s_bDestAlphaTest && bCanRenderStencil) { @@ -1383,7 +1387,7 @@ void FlushIfNecesary(void* ptr) if (vb[1].prndr == ptr || vb[1].pdepth == ptr) Flush(1); } -inline void RenderFBA(const VB& curvb, ZZshParameter sOneColor) +inline void RenderFBA(const VB& curvb, FRAGMENTSHADER* pfragment) { // add fba to all pixels GL_STENCILFUNC(GL_ALWAYS, STENCIL_FBA, 0xff); @@ -1404,7 +1408,7 @@ inline void RenderFBA(const VB& curvb, ZZshParameter sOneColor) float4 v(1,2,0,0); - ZZshSetParameter4fv(sOneColor, v, "g_fOneColor"); + ZZshSetParameter4fv(pfragment->prog, pfragment->sOneColor, v, "g_fOneColor"); Draw(curvb); @@ -1427,7 +1431,7 @@ inline void RenderFBA(const VB& curvb, ZZshParameter sOneColor) GL_ZTEST(curvb.test.zte); } -__forceinline void RenderAlphaTest(const VB& curvb, ZZshParameter sOneColor) +__forceinline void RenderAlphaTest(const VB& curvb, FRAGMENTSHADER* pfragment ) { if (!g_bUpdateStencil) return; @@ -1443,7 +1447,7 @@ __forceinline void RenderAlphaTest(const VB& curvb, ZZshParameter sOneColor) float4 v(1,2,0,0); - ZZshSetParameter4fv(sOneColor, v, "g_fOneColor"); + ZZshSetParameter4fv(pfragment->prog, pfragment->sOneColor, v, "g_fOneColor"); // or a 1 to the stencil buffer wherever alpha passes glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); @@ -1467,7 +1471,7 @@ __forceinline void RenderAlphaTest(const VB& curvb, ZZshParameter sOneColor) if (curvb.test.ate && curvb.test.atst > ATST_ALWAYS && curvb.test.aref > 0x80) { v = float4(1,1,0,0); - ZZshSetParameter4fv(sOneColor, v, "g_fOneColor"); + ZZshSetParameter4fv(pfragment->prog, pfragment->sOneColor, v, "g_fOneColor"); glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], AlphaReferedValue(curvb.test.aref)); } @@ -1565,7 +1569,7 @@ inline void ProcessStencil(const VB& curvb) glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); } -__forceinline void ProcessFBA(const VB& curvb, ZZshParameter sOneColor) +__forceinline void ProcessFBA(const VB& curvb, FRAGMENTSHADER* pfragment ) { if ((curvb.frame.fbm&0x80000000)) return; @@ -1590,8 +1594,12 @@ __forceinline void ProcessFBA(const VB& curvb, ZZshParameter sOneColor) GL_BLEND_ALPHA(GL_ONE, GL_ONE); GL_BLENDEQ_ALPHA(GL_FUNC_ADD); - float f = 1; - ZZshSetParameter4fv(sOneColor, &f, "g_fOneColor"); + // FIXME: Seem dangerous + // float f = 1; + // ZZshSetParameter4fv(pfragment->prog, pfragment->sOneColor, &f, "g_fOneColor"); + float4 v = float4(1,1,0,0); + ZZshSetParameter4fv(pfragment->prog, pfragment->sOneColor, v, "g_fOneColor"); + ZZshSetPixelShader(ppsOne.prog); Draw(curvb); glDisable(GL_ALPHA_TEST); @@ -1840,11 +1848,10 @@ void SetTexClamping(int context, FRAGMENTSHADER* pfragment) } if (pfragment->fTexWrapMode != 0) - ZZshSetParameter4fv(pfragment->fTexWrapMode, v, "g_fTexWrapMode"); + ZZshSetParameter4fv(pfragment->prog, pfragment->fTexWrapMode, v, "g_fTexWrapMode"); if (pfragment->fClampExts != 0) - ZZshSetParameter4fv(pfragment->fClampExts, v2, "g_fClampExts"); - + ZZshSetParameter4fv(pfragment->prog, pfragment->fClampExts, v2, "g_fClampExts"); } @@ -1917,15 +1924,15 @@ void SetTexVariables(int context, FRAGMENTSHADER* pfragment) valpha.z = (tex0.tfx == TFX_HIGHLIGHT2); valpha.w = (tex0.tcc == 0) || (tex0.tcc == 1 && tex0.tfx == TFX_HIGHLIGHT); - ZZshSetParameter4fv(pfragment->fTexAlpha, valpha, "g_fTexAlpha"); - ZZshSetParameter4fv(pfragment->fTexAlpha2, valpha2, "g_fTexAlpha2"); + ZZshSetParameter4fv(pfragment->prog, pfragment->fTexAlpha, valpha, "g_fTexAlpha"); + ZZshSetParameter4fv(pfragment->prog, pfragment->fTexAlpha2, valpha2, "g_fTexAlpha2"); if (IsAlphaTestExpansion(tex0)) { float4 vblack; vblack.x = vblack.y = vblack.z = vblack.w = 10; if (tex0.tcc && gs.texa.aem && psm == PSMCT24) vblack.w = 0; - ZZshSetParameter4fv(pfragment->fTestBlack, vblack, "g_fTestBlack"); + ZZshSetParameter4fv(pfragment->prog, pfragment->fTestBlack, vblack, "g_fTestBlack"); } SetTexClamping(context, pfragment); @@ -2025,11 +2032,11 @@ void SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, bool Ch v.z *= b.bpp * (1 / 32.0f); } - ZZshSetParameter4fv(pfragment->fTexDims, vTexDims, "g_fTexDims"); + ZZshSetParameter4fv(pfragment->prog, pfragment->fTexDims, vTexDims, "g_fTexDims"); // ZZshSetParameter4fv(pfragment->fTexBlock, b.vTexBlock, "g_fTexBlock"); // I change it, and it's working. Seems casting from float4 to float[4] is ok. - ZZshSetParameter4fv(pfragment->fTexBlock, &b.vTexBlock.x, "g_fTexBlock"); - ZZshSetParameter4fv(pfragment->fTexOffset, v, "g_fTexOffset"); + ZZshSetParameter4fv(pfragment->prog, pfragment->fTexBlock, &b.vTexBlock.x, "g_fTexBlock"); + ZZshSetParameter4fv(pfragment->prog, pfragment->fTexOffset, v, "g_fTexOffset"); // get hardware texture dims //int texheight = pmemtarg->texH; @@ -2049,7 +2056,7 @@ void SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, bool Ch v.w = 0.5f;*/ v.w = 0.5f; - ZZshSetParameter4fv(pfragment->fPageOffset, v, "g_fPageOffset"); + ZZshSetParameter4fv(pfragment->prog, pfragment->fPageOffset, v, "g_fPageOffset"); if (force) s_ptexCurSet[context] = pmemtarg->ptex->tex; diff --git a/plugins/zzogl-pg/opengl/ZZoglFlush.h b/plugins/zzogl-pg/opengl/ZZoglFlush.h index be635f5fdc..b17a6d51d8 100644 --- a/plugins/zzogl-pg/opengl/ZZoglFlush.h +++ b/plugins/zzogl-pg/opengl/ZZoglFlush.h @@ -108,11 +108,11 @@ void SetAlphaVariables(const alphaInfo& ainfo); // zzz inline void SetAlphaTestInt(pixTest curtest); -inline void RenderAlphaTest(const VB& curvb, ZZshParameter sOneColor); +inline void RenderAlphaTest(const VB& curvb, FRAGMENTSHADER* pfragment); inline void RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting); inline void ProcessStencil(const VB& curvb); -inline void RenderFBA(const VB& curvb, ZZshParameter sOneColor); -inline void ProcessFBA(const VB& curvb, ZZshParameter sOneColor); // zz +inline void RenderFBA(const VB& curvb, FRAGMENTSHADER* pfragment); +inline void ProcessFBA(const VB& curvb, FRAGMENTSHADER* pfragment); // zz void SetContextTarget(int context); diff --git a/plugins/zzogl-pg/opengl/ZZoglShaders.cpp b/plugins/zzogl-pg/opengl/ZZoglShaders.cpp index 7ced42daee..3f39b61e1b 100644 --- a/plugins/zzogl-pg/opengl/ZZoglShaders.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglShaders.cpp @@ -276,13 +276,13 @@ void ZZshSetParameter4fv(ZZshParameter param, const float* v, const char* name) cgGLSetParameter4fv(param, v); } -void ZZshSetParameter4fv(ZZshProgram prog, ZZshParameter param, const float* v, const char* name) { +void ZZshSetParameter4fv(ZZshProgram& prog, ZZshParameter param, const float* v, const char* name) { ShaderHandleName = name; cgGLSetParameter4fv(param, v); } // The same stuff, but also with retry of param, name should be USED name of param for prog. -void ZZshSetParameter4fvWithRetry(ZZshParameter* param, ZZshProgram prog, const float* v, const char* name) { +void ZZshSetParameter4fvWithRetry(ZZshParameter* param, ZZshProgram& prog, const float* v, const char* name) { if (param != NULL) ZZshSetParameter4fv(prog, param[0], v, name); else @@ -303,7 +303,7 @@ void ZZshGLSetTextureParameter(ZZshProgram prog, ZZshParameter param, GLuint tex } // Used sometimes for color 1. -void ZZshDefaultOneColor( FRAGMENTSHADER ptr ) { +void ZZshDefaultOneColor( FRAGMENTSHADER& ptr ) { ShaderHandleName = "Set Default One color"; float4 v = float4 ( 1, 1, 1, 1 ); ZZshSetParameter4fv( ptr.prog, ptr.sOneColor, v, "DefaultOne"); diff --git a/plugins/zzogl-pg/opengl/ZZoglShaders.h b/plugins/zzogl-pg/opengl/ZZoglShaders.h index 83a951d828..6dd3141aea 100644 --- a/plugins/zzogl-pg/opengl/ZZoglShaders.h +++ b/plugins/zzogl-pg/opengl/ZZoglShaders.h @@ -30,6 +30,7 @@ #define SHADER_REDUCED 1 // equivalent to ps2.0 #define SHADER_ACCURATE 2 // for older cards with less accurate math (ps2.x+) +#include #include "ZZoglMath.h" #include "GS.h" @@ -106,6 +107,159 @@ inline bool ZZshActiveParameter(ZZshParameter param) {return (param > -1); } #endif +extern float4 g_vdepth; +extern float4 vlogz; + + +#ifdef GLSL4_API +enum { + ZZSH_CTX_0 = 0, + ZZSH_CTX_1 = 1, + ZZSH_CTX_ALL = 2 +}; + +class GSUniformBufferOGL { + GLuint buffer; // data object + GLuint index; // GLSL slot + uint size; // size of the data + const GLenum target; + +public: + GSUniformBufferOGL(GLuint index, uint size) : index(index) + , size(size) + ,target(GL_UNIFORM_BUFFER) + { + glGenBuffers(1, &buffer); + bind(); + allocate(); + attach(); + } + + void bind() + { + glBindBuffer(target, buffer); + } + + void allocate() + { + glBufferData(target, size, NULL, GL_STREAM_DRAW); + } + + void attach() + { + glBindBufferBase(target, index, buffer); + } + + void upload(const void* src) + { + u32 flags = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT; + u8* dst = (u8*) glMapBufferRange(target, 0, size, flags); + memcpy(dst, src, size); + glUnmapBuffer(target); + } + + ~GSUniformBufferOGL() { + glDeleteBuffers(1, &buffer); + } +}; + + + +// Note A nice template could be better +// Warning order is important for buffer (see GLSL) +// Note must be keep POD (so you can map it to GLSL) +struct GlobalUniform { + union { + struct { + // VS + float g_fPosXY[4]; // dual context + // PS + float g_fFogColor[4]; + }; + float linear[2*4]; + }; + void SettleFloat(int indice, const float* v) { + assert(indice >= 0); + assert(indice + 3 < sizeof(linear)); + linear[indice+0] = v[0]; + linear[indice+1] = v[1]; + linear[indice+2] = v[2]; + linear[indice+3] = v[3]; + } +}; +struct ConstantUniform { + union { + struct { + // Both VS/PS + float g_fBilinear[4]; + float g_fZbias[4]; + float g_fc0[4]; + float g_fMult[4]; + // VS + float g_fZ[4]; + float g_fZMin[4]; + float g_fZNorm[4]; + // PS + float g_fExactColor[4]; + }; + float linear[8*4]; + }; + void SettleFloat(int indice, const float* v) { + assert(indice >= 0); + assert(indice + 3 < sizeof(linear)); + linear[indice+0] = v[0]; + linear[indice+1] = v[1]; + linear[indice+2] = v[2]; + linear[indice+3] = v[3]; + } +}; +struct FragmentUniform { + union { + struct { + float g_fTexAlpha2[4]; // dual context + float g_fTexOffset[4]; // dual context + float g_fTexDims[4]; // dual context + float g_fTexBlock[4]; // dual context + float g_fClampExts[4]; // dual context + float g_fTexWrapMode[4]; // dual context + float g_fRealTexDims[4]; // dual context + float g_fTestBlack[4]; // dual context + float g_fPageOffset[4]; // dual context + float g_fTexAlpha[4]; // dual context + float g_fInvTexDims[4]; + float g_fBitBltZ[4]; + float g_fOneColor[4]; + }; + float linear[13*4]; + }; + void SettleFloat(int indice, const float* v) { + assert(indice >= 0); + assert(indice + 3 < sizeof(linear)); + linear[indice+0] = v[0]; + linear[indice+1] = v[1]; + linear[indice+2] = v[2]; + linear[indice+3] = v[3]; + } +}; +struct VertexUniform { + union { + struct { + float g_fBitBltPos[4]; + float g_fBitBltTex[4]; + float g_fBitBltTrans[4]; + }; + float linear[3*4]; + }; + void SettleFloat(int indice, const float* v) { + assert(indice >= 0); + assert(indice + 3 < sizeof(linear) / 4); + linear[indice+0] = v[0]; + linear[indice+1] = v[1]; + linear[indice+2] = v[2]; + linear[indice+3] = v[3]; + } +}; +#endif @@ -124,6 +278,7 @@ extern ZZshParameter g_vparamPosXY[2], g_fparamFogColor; #define MAX_ACTIVE_UNIFORMS 600 #define MAX_ACTIVE_SHADERS 400 +#ifndef GLSL4_API struct FRAGMENTSHADER { FRAGMENTSHADER() : prog(sZero), Shader(0), sMemory(pZero), sFinal(pZero), sBitwiseANDX(pZero), sBitwiseANDY(pZero), sInterlace(pZero), sCLUT(pZero), sOneColor(pZero), sBitBltZ(pZero), @@ -217,7 +372,202 @@ struct FRAGMENTSHADER } #endif }; +#else +const GLenum g_texture_target[10] = {GL_TEXTURE_RECTANGLE, GL_TEXTURE_RECTANGLE, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_RECTANGLE, GL_TEXTURE_RECTANGLE, GL_TEXTURE_RECTANGLE, GL_TEXTURE_2D}; +struct SamplerParam { + int unit; + GLuint texid; + GLenum target; + + SamplerParam() : unit(-1), texid(0), target(0) {} + + void set_unit(int new_unit = 0) { + assert(new_unit >= 0); + assert(new_unit < 10); + unit = new_unit; + target = g_texture_target[new_unit]; + } + + void enable_texture() { + assert(unit >= 0); + assert(unit < 10); + if (texid) { + glActiveTexture(GL_TEXTURE0 + unit); + glBindTexture(target, texid); + } + } + + void set_texture(GLuint texid) { + texid = texid; + } +}; + +struct FRAGMENTSHADER +{ + FRAGMENTSHADER() : prog(sZero) , Shader(0) + , sFinal(2) + , sBitwiseANDX(3) + , sBitwiseANDY(4) + , sInterlace(5) + , sCLUT(6) + { + // Uniform + sOneColor = (ZZshParameter)offsetof(struct FragmentUniform, g_fOneColor) /4; + sBitBltZ = (ZZshParameter)offsetof(struct FragmentUniform, g_fBitBltZ) /4; + sInvTexDims = (ZZshParameter)offsetof(struct FragmentUniform, g_fInvTexDims) /4; + fTexAlpha = (ZZshParameter)offsetof(struct FragmentUniform, g_fTexAlpha) /4; + fTexAlpha2 = (ZZshParameter)offsetof(struct FragmentUniform, g_fTexAlpha2) /4; + fTexOffset = (ZZshParameter)offsetof(struct FragmentUniform, g_fTexOffset) /4; + fTexDims = (ZZshParameter)offsetof(struct FragmentUniform, g_fTexDims) /4; + fTexBlock = (ZZshParameter)offsetof(struct FragmentUniform, g_fTexBlock) /4; + fClampExts = (ZZshParameter)offsetof(struct FragmentUniform, g_fClampExts) /4; // FIXME: There is a bug, that lead FFX-1 to incorrect CLAMP if this uniform have context. + fTexWrapMode = (ZZshParameter)offsetof(struct FragmentUniform, g_fTexWrapMode) /4; + fRealTexDims = (ZZshParameter)offsetof(struct FragmentUniform, g_fRealTexDims) /4; + fTestBlack = (ZZshParameter)offsetof(struct FragmentUniform, g_fTestBlack) /4; + fPageOffset = (ZZshParameter)offsetof(struct FragmentUniform, g_fPageOffset) /4; + + sMemory[ZZSH_CTX_0] = 0; + sMemory[ZZSH_CTX_1] = 1; + //sFinal = 2; + //sBitwiseANDX = 3; + //sBitwiseANDY = 4; + //sInterlace = 5; + //sCLUT = 6; + samplers[sMemory[ZZSH_CTX_0]].set_unit(0); + samplers[sMemory[ZZSH_CTX_1]].set_unit(0); // Dual context. Use same unit + samplers[sFinal].set_unit(1); + samplers[sBitwiseANDX].set_unit(6); + samplers[sBitwiseANDY].set_unit(7); + samplers[sInterlace].set_unit(8); + samplers[sCLUT].set_unit(9); + } + + ZZshShaderLink prog; // it link to FRAGMENTSHADER structure, for compability between GLSL and CG + ZZshShader Shader; // useless with separate build + ZZshShaderType ShaderType; // Not every PS and VS are used together, only compatible ones. + + FragmentUniform uniform_buffer[ZZSH_CTX_ALL]; + + // sampler + ZZshParameter sMemory[ZZSH_CTX_ALL]; + const ZZshParameter sFinal, sBitwiseANDX, sBitwiseANDY, sInterlace, sCLUT; + SamplerParam samplers[7]; + + // uniform + ZZshParameter sOneColor, sBitBltZ, sInvTexDims; + ZZshParameter fTexAlpha2, fTexOffset, fTexDims, fTexBlock, fClampExts, fTexWrapMode, fRealTexDims, fTestBlack, fPageOffset, fTexAlpha; + +#ifdef _DEBUG + string filename; +#endif + + void ZZshSetParameter4fv(ZZshParameter param, const float* v, int context = ZZSH_CTX_ALL) { + if (context < ZZSH_CTX_ALL) + uniform_buffer[context].SettleFloat((int) param, v); + else + for ( int i = 0; i < ZZSH_CTX_ALL ; i++) + uniform_buffer[i].SettleFloat((int) param, v); + } + + void enable_texture(int context) { + samplers[0+context].enable_texture(); + for (int i = 2; i < 7; i++) + samplers[i].enable_texture(); + } + + void set_texture(ZZshParameter param, GLuint texid) { + samplers[param].set_texture(texid); + } +}; +#endif + +#ifdef GLSL4_API +struct COMMONSHADER +{ + COMMONSHADER() : sBlocks(0) + , sBilinearBlocks(1) + , sConv16to32(2) + , sConv32to16(3) + { + // sBlocks = 0; + // sBilinearBlocks = 1; + // sConv16to32 = 2; + // sConv32to16 = 3; + samplers[sBlocks].set_unit(2); + samplers[sBilinearBlocks].set_unit(3); + samplers[sConv16to32].set_unit(4); + samplers[sConv32to16].set_unit(5); + + + g_fparamFogColor = (ZZshParameter)offsetof(struct GlobalUniform, g_fFogColor) /4; + g_vparamPosXY = (ZZshParameter)offsetof(struct GlobalUniform, g_fPosXY) /4; + + g_fBilinear = (ZZshParameter)offsetof(struct ConstantUniform, g_fBilinear) /4; + g_fZBias = (ZZshParameter)offsetof(struct ConstantUniform, g_fZbias) /4; + g_fc0 = (ZZshParameter)offsetof(struct ConstantUniform, g_fc0) /4; + g_fMult = (ZZshParameter)offsetof(struct ConstantUniform, g_fMult) /4; + g_fZ = (ZZshParameter)offsetof(struct ConstantUniform, g_fZ) /4; + g_fZMin = (ZZshParameter)offsetof(struct ConstantUniform, g_fZMin) /4; + g_fZNorm = (ZZshParameter)offsetof(struct ConstantUniform, g_fZNorm) /4; + g_fExactColor = (ZZshParameter)offsetof(struct ConstantUniform, g_fExactColor) /4; + + // Setup the constant buffer + + // Set Z-test, log or no log; + if (conf.settings().no_logz) { + g_vdepth = float4( 255.0 /256.0f, 255.0/65536.0f, 255.0f/(65535.0f*256.0f), 1.0f/(65536.0f*65536.0f)); + vlogz = float4( 1.0f, 0.0f, 0.0f, 0.0f); + } + else { + g_vdepth = float4( 256.0f*65536.0f, 65536.0f, 256.0f, 65536.0f*65536.0f); + vlogz = float4( 0.0f, 1.0f, 0.0f, 0.0f); + } + uniform_buffer_constant.SettleFloat(g_fZ, g_vdepth ); + uniform_buffer_constant.SettleFloat(g_fZMin, vlogz ); + + const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + float4 vnorm = float4(g_filog32, 0, 0,0); + uniform_buffer_constant.SettleFloat(g_fZNorm, vnorm); + + uniform_buffer_constant.SettleFloat(g_fBilinear, float4(-0.2f, -0.65f, 0.9f, 1.0f / 32767.0f ) ); + uniform_buffer_constant.SettleFloat(g_fZBias, float4(1.0f/256.0f, 1.0004f, 1, 0.5f) ); + uniform_buffer_constant.SettleFloat(g_fc0, float4(0,1, 0.001f, 0.5f) ); + + uniform_buffer_constant.SettleFloat(g_fExactColor, float4(0.5f, (conf.settings().exact_color)?0.9f/256.0f:0.5f/256.0f, 0,1/255.0f) ); + uniform_buffer_constant.SettleFloat(g_fMult, float4(1/1024.0f, 0.2f/1024.0f, 1/128.0f, 1/512.0f)); + } + + ZZshParameter g_fparamFogColor, g_vparamPosXY; + ZZshParameter g_fBilinear, g_fZBias, g_fc0, g_fMult, g_fZ, g_fZMin, g_fZNorm, g_fExactColor; + + GlobalUniform uniform_buffer[ZZSH_CTX_ALL]; + ConstantUniform uniform_buffer_constant; + + // Sampler + const ZZshParameter sBlocks, sBilinearBlocks, sConv16to32, sConv32to16; + SamplerParam samplers[4]; + + void ZZshSetParameter4fv(ZZshParameter param, const float* v, int context = ZZSH_CTX_ALL) { + if (context < ZZSH_CTX_ALL) + uniform_buffer[context].SettleFloat((int) param, v); + else + for ( int i = 0; i < ZZSH_CTX_ALL ; i++) + uniform_buffer[i].SettleFloat((int) param, v); + } + + void set_texture(ZZshParameter param, GLuint texid) { + samplers[param].set_texture(texid); + } + + void enable_texture() { + for (int i = 0; i < 4; i++) + samplers[i].enable_texture(); + } +}; +#endif + +#ifndef GLSL4_API struct VERTEXSHADER { VERTEXSHADER() : prog(sZero), Shader(0), sBitBltPos(pZero), sBitBltTex(pZero) {} @@ -230,15 +580,50 @@ struct VERTEXSHADER int ParametersStart, ParametersFinish; }; +#else +struct VERTEXSHADER +{ + + VERTEXSHADER() : prog(sZero), Shader(0) + //: prog(sZero), Shader(0), sBitBltPos(pZero), sBitBltTex(pZero) {} + { + sBitBltPos = (ZZshParameter)offsetof(struct VertexUniform, g_fBitBltPos) /4; + sBitBltTex = (ZZshParameter)offsetof(struct VertexUniform, g_fBitBltTex) /4; + fBitBltTrans = (ZZshParameter)offsetof(struct VertexUniform, g_fBitBltTrans) /4; + + // Default value not sure it is needed + uniform_buffer[0].SettleFloat(fBitBltTrans, float4(0.5f, -0.5f, 0.5, 0.5 + 0.4/416.0f ) ); + uniform_buffer[1].SettleFloat(fBitBltTrans, float4(0.5f, -0.5f, 0.5, 0.5 + 0.4/416.0f ) ); + } + + VertexUniform uniform_buffer[ZZSH_CTX_ALL]; + + ZZshShaderLink prog; + ZZshShader Shader; // useless with separate build + ZZshShaderType ShaderType; + + ZZshParameter sBitBltPos, sBitBltTex, fBitBltTrans; // vertex shader constants + + void ZZshSetParameter4fv(ZZshParameter param, const float* v, int context = ZZSH_CTX_ALL) { + if (context < ZZSH_CTX_ALL) + uniform_buffer[context].SettleFloat((int) param, v); + else + for ( int i = 0; i < ZZSH_CTX_ALL ; i++) + uniform_buffer[i].SettleFloat((int) param, v); + } + +}; +#endif - extern float4 g_vdepth; - extern float4 vlogz; extern VERTEXSHADER pvsBitBlt; extern FRAGMENTSHADER ppsBitBlt[2], ppsBitBltDepth, ppsOne; // ppsOne used to stop using shaders for draw extern FRAGMENTSHADER ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; extern FRAGMENTSHADER ppsRegular[4], ppsTexture[NUM_SHADERS]; extern FRAGMENTSHADER ppsCRTC[2], /*ppsCRTC24[2],*/ ppsCRTCTarg[2]; +#ifdef GLSL4_API + extern COMMONSHADER g_cs; +#endif extern int interlace_mode; @@ -318,16 +703,16 @@ extern void ZZshGLEnableProfile(); // Set the Uniform parameter in host (NOT GL) // Param seem to be an absolute index inside a table of uniform -extern void ZZshSetParameter4fv(ZZshShaderLink prog, ZZshParameter param, const float* v, const char* name); +extern void ZZshSetParameter4fv(ZZshShaderLink& prog, ZZshParameter param, const float* v, const char* name); extern void ZZshSetParameter4fv(ZZshParameter param, const float* v, const char* name); -extern void ZZshSetParameter4fvWithRetry(ZZshParameter* param, ZZshShaderLink prog, const float* v, const char* name); +extern void ZZshSetParameter4fvWithRetry(ZZshParameter* param, ZZshShaderLink& prog, const float* v, const char* name); // Set the Texture parameter in host (NOT GL) extern void ZZshGLSetTextureParameter(ZZshShaderLink prog, ZZshParameter param, GLuint texobj, const char* name); extern void ZZshGLSetTextureParameter(ZZshParameter param, GLuint texobj, const char* name); // Set a default value for 1 uniform in host (NOT GL) -extern void ZZshDefaultOneColor( FRAGMENTSHADER ptr ); +extern void ZZshDefaultOneColor( FRAGMENTSHADER& ptr ); // Link then run with the new Vertex/Fragment Shader extern void ZZshSetVertexShader(ZZshShaderLink prog); @@ -350,5 +735,15 @@ extern u32 ptexConv16to32; // does not exists. This textures should be created o extern u32 ptexBilinearBlocks; extern u32 ptexConv32to16; +#ifdef GLSL4_API +extern GSUniformBufferOGL *constant_buffer; +extern GSUniformBufferOGL *common_buffer; +extern GSUniformBufferOGL *vertex_buffer; +extern GSUniformBufferOGL *fragment_buffer; + +static void init_shader(); +static void PutParametersInProgam(VERTEXSHADER* vs, FRAGMENTSHADER* ps, int context); + +#endif #endif diff --git a/plugins/zzogl-pg/opengl/ZZoglShadersGLSL.cpp b/plugins/zzogl-pg/opengl/ZZoglShadersGLSL.cpp index d44efc89f5..c6283328b5 100644 --- a/plugins/zzogl-pg/opengl/ZZoglShadersGLSL.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglShadersGLSL.cpp @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef GLSL_API // This code is only for GLSL API +#if defined(GLSL_API) && !defined(GLSL4_API) // This code is only for GLSL API // ZZogl Shader manipulation functions. /* @@ -237,10 +237,10 @@ bool ZZshCreateOpenShadersFile() { if ((ShaderFD == -1) || (fstat(ShaderFD, &sb) == -1)) { // Each linux distributions have his rules for path so we give them the possibility to // change it with compilation flags. -- Gregory -#ifdef PLUGIN_DIR_COMPILATION -#define xPLUGIN_DIR_str(s) PLUGIN_DIR_str(s) -#define PLUGIN_DIR_str(s) #s - ShaderFileName = string(xPLUGIN_DIR_str(PLUGIN_DIR_COMPILATION)) + "/ps2hw.glsl"; +#ifdef GLSL_SHADER_DIR_COMPILATION +#define xGLSL_SHADER_DIR_str(s) GLSL_SHADER_DIR_str(s) +#define GLSL_SHADER_DIR_str(s) #s + ShaderFileName = string(xGLSL_SHADER_DIR_str(GLSL_SHADER_DIR_COMPILATION)) + "/ps2hw.glsl"; ShaderFD = open(ShaderFileName.c_str(), O_RDONLY); #endif if ((ShaderFD == -1) || (fstat(ShaderFD, &sb) == -1)) { @@ -290,7 +290,7 @@ void ZZshGLSetTextureParameter(ZZshShaderLink prog, ZZshParameter param, GLuint // This is helper of cgGLSetParameter4fv, made for debug purpose. // Name could be any string. We must use it on compilation time, because erroneus handler does not // return name -void ZZshSetParameter4fv(ZZshShaderLink prog, ZZshParameter param, const float* v, const char* name) { +void ZZshSetParameter4fv(ZZshShaderLink& prog, ZZshParameter param, const float* v, const char* name) { if (param > -1) { // ZZLog::Error_Log("Set float parameter %s %f, %f, %f, %f... Ok", name, v[0], v[1], v[2], v[3]); SettleFloat(UniformsIndex[param].fvalue, v); @@ -307,13 +307,13 @@ void ZZshSetParameter4fv(ZZshParameter param, const float* v, const char* name) } // The same stuff, but also with retry of param, name should be USED name of param for prog. -void ZZshSetParameter4fvWithRetry(ZZshParameter* param, ZZshShaderLink prog, const float* v, const char* name) { +void ZZshSetParameter4fvWithRetry(ZZshParameter* param, ZZshShaderLink& prog, const float* v, const char* name) { if (param != NULL) ZZshSetParameter4fv(prog, *param, v, name); } // Used sometimes for color 1. -void ZZshDefaultOneColor( FRAGMENTSHADER ptr ) { +void ZZshDefaultOneColor( FRAGMENTSHADER& ptr ) { // return; ShaderHandleName = "Set Default One colot"; float4 v = float4 ( 1, 1, 1, 1 ); @@ -426,7 +426,7 @@ inline bool GetLinkLog(ZZshProgram prog) { if (LinkStatus == GL_TRUE && glIsProgram(prog)) return true; -#ifdef DEVBUILD +#if defined(DEVBUILD) || defined(_DEBUG) int* lenght, infologlength; glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &infologlength); char* InfoLog = new char[infologlength]; @@ -474,6 +474,9 @@ static void PutParametersInProgam(int start, int finish) { } else { + // assert(param.texid != 0); + // ZZLog::Error_Log("Set texture (%s) : %d with sampler %d\n", param.ShName, param.texid, param.sampler); + // assert(param.sampler >= 0); glActiveTexture(GL_TEXTURE0 + param.sampler); if (param.type == ZZ_TEXTURE_2D) glBindTexture(GL_TEXTURE_2D, param.texid); @@ -974,4 +977,4 @@ FRAGMENTSHADER* ZZshLoadShadeEffect(int type, int texfilter, int fog, int testae return NULL; } -#endif // GLSL_API +#endif diff --git a/plugins/zzogl-pg/opengl/ZZoglShadersGLSL4.cpp b/plugins/zzogl-pg/opengl/ZZoglShadersGLSL4.cpp new file mode 100644 index 0000000000..5e226704b3 --- /dev/null +++ b/plugins/zzogl-pg/opengl/ZZoglShadersGLSL4.cpp @@ -0,0 +1,843 @@ +/* ZZ Open GL graphics plugin + * Copyright (c)2009 zeydlitz@gmail.com + * Based on Zerofrog's ZeroGS KOSMOS (c)2005-2006 + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef GLSL4_API // This code is only for GLSL API +// ZZogl Shader manipulation functions. + +/* + * used cg calls: + * cgGLIsProfileSupported -- don't needed + * cgGetErrorString -- later + * cgGetLastListing -- later + * cgSetErrorHandler -- later + * cgCreateContext -- think that don't need + * cgGLEnableProfile -- don't need + * cgGLSetOptimalOptions -- don't need? + * cgGLSetManageTextureParameters -- what's this? + * cgCreateParameter -- don't need + * cgGLLoadProgram void LinkProgram(uint program) + * cgGetError -- later + * cgGLDisableProfile -- don't need + * cgGLSetParameter4fv + * cgGetNamedParameter + * cgGLEnableTextureParameter + * cgIsParameterUsed + * cgGLBindProgram void UseProgram(uint program) + * cgConnectParameter + * cgIsProgram bool IsProgram(uint program) + * cgCreateProgramFromFile + */ + +//------------------- Includes +#include "Util.h" +#include "ZZoglShaders.h" +#include "zpipe.h" +#include +#include +#include // this for open(). Maybe linux-specific +#include // and this for mmap + +// ----------------- Defines + +#define TEXWRAP_REPEAT 0 +#define TEXWRAP_CLAMP 1 +#define TEXWRAP_REGION_REPEAT 2 +#define TEXWRAP_REPEAT_CLAMP 3 + +#ifdef DEVBUILD +# define UNIFORM_ERROR_LOG ZZLog::Error_Log +#else +# define UNIFORM_ERROR_LOG +#endif + +// Set it to 0 to diable context usage, 1 -- to enable. FFX-1 have a strange issue with ClampExt. +#define NOCONTEXT 0 +#define NUMBER_OF_SAMPLERS 11 +#define MAX_SHADER_NAME_SIZE 25 +#define MAX_UNIFORM_NAME_SIZE 20 +#define DEFINE_STRING_SIZE 256 +//------------------ Constants + +// Used in a logarithmic Z-test, as (1-o(1))/log(MAX_U32). +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +const static char* g_pTexTypes[] = { "32", "tex32", "clut32", "tex32to16", "tex16to8h" }; +const static char* g_pShaders[4] = { "full", "reduced", "accurate", "accurate-reduced" }; + +// ----------------- Global Variables + +ZZshContext g_cgcontext; +ZZshProfile cgvProf, cgfProf; +int g_nPixelShaderVer = 0; // default +u8* s_lpShaderResources = NULL; +ZZshShaderLink pvs[16] = {sZero}, g_vsprog = sZero, g_psprog = sZero; // 2 -- ZZ +ZZshParameter g_vparamPosXY[2] = {pZero}, g_fparamFogColor = pZero; + +ZZshProgram ZZshMainProgram; +char* ZZshSource; // Shader's source data. +off_t ZZshSourceSize; + +extern char* EFFECT_NAME; // All this variables used for testing and set manually +extern char* EFFECT_DIR; + +bool g_bCRTCBilinear = true; + +float4 g_vdepth, vlogz; +FRAGMENTSHADER ppsBitBlt[2], ppsBitBltDepth, ppsOne; +FRAGMENTSHADER ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; +FRAGMENTSHADER ppsRegular[4], ppsTexture[NUM_SHADERS]; +FRAGMENTSHADER ppsCRTC[2], /*ppsCRTC24[2],*/ ppsCRTCTarg[2]; +VERTEXSHADER pvsStore[16]; +VERTEXSHADER pvsBitBlt; + +inline bool LoadEffects(); +extern bool s_bWriteDepth; + +struct SHADERHEADER +{ + unsigned int index, offset, size; // if highest bit of index is set, pixel shader +}; +map mapShaderResources; + +// Debug variable, store name of the function that call the shader. +const char* ShaderCallerName = ""; +const char* ShaderHandleName = ""; + +int NumActiveUniforms, NumGlobalUniforms; +ZZshParamInfo UniformsIndex[MAX_ACTIVE_UNIFORMS] = {qZero}; +const char* ShaderNames[MAX_ACTIVE_SHADERS] = {""}; +ZZshShaderType ShaderTypes[MAX_ACTIVE_SHADERS] = {ZZ_SH_NONE}; + +ZZshProgram CompiledPrograms[MAX_ACTIVE_SHADERS][MAX_ACTIVE_SHADERS] = {{0}}; +const char* TextureUnits[NUMBER_OF_SAMPLERS] = + {"g_sMemory[0]", "g_sMemory[1]", "g_sSrcFinal", "g_sBitwiseANDX", "g_sBitwiseANDY", "g_sInterlace", \ + "g_sCLUT", "g_sBlocks", "g_sBilinearBlocks", "g_sConv16to32", "g_sConv32to16"}; +ZZshPARAMTYPE TextureTypes[NUMBER_OF_SAMPLERS] = + {ZZ_TEXTURE_RECT, ZZ_TEXTURE_RECT, ZZ_TEXTURE_RECT, ZZ_TEXTURE_RECT, ZZ_TEXTURE_RECT, ZZ_TEXTURE_RECT, \ + ZZ_TEXTURE_2D, ZZ_TEXTURE_2D, ZZ_TEXTURE_2D, ZZ_TEXTURE_2D, ZZ_TEXTURE_3D} ; + +#ifdef GLSL4_API +GSUniformBufferOGL *constant_buffer; +GSUniformBufferOGL *common_buffer; +GSUniformBufferOGL *vertex_buffer; +GSUniformBufferOGL *fragment_buffer; + +COMMONSHADER g_cs; +#endif + +//------------------ Code + +inline int GET_SHADER_INDEX(int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int context, int ps) { + return type + texfilter*NUM_TYPES + NUM_FILTERS*NUM_TYPES*texwrap + NUM_TEXWRAPS*NUM_FILTERS*NUM_TYPES*(fog+2*writedepth+4*testaem+8*exactcolor+16*context+32*ps) ; +} + +// Nothing need to be done. +bool ZZshCheckProfilesSupport() { + return true; +} + +// Error handler. Setup in ZZogl_Create once. +void HandleCgError(ZZshContext ctx, ZZshError err, void* appdata) +{/* + ZZLog::Error_Log("%s->%s: %s", ShaderCallerName, ShaderHandleName, cgGetErrorString(err)); + const char* listing = cgGetLastListing(g_cgcontext); + if (listing != NULL) + ZZLog::Debug_Log(" last listing: %s", listing); +*/ +} + +float ZeroFloat4[4] = {0}; + +inline void SettleFloat(float* f, const float* v) { + f[0] = v[0]; + f[1] = v[1]; + f[2] = v[2]; + f[3] = v[3]; +} + +inline ZZshParamInfo ParamInfo(const char* ShName, ZZshPARAMTYPE type, const float fvalue[], GLuint sampler, GLint texid, bool Constant, bool Settled) { + ZZshParamInfo x; + x.ShName = new char[MAX_UNIFORM_NAME_SIZE]; + x.ShName = ShName; + x.type = type; + SettleFloat(x.fvalue, fvalue); + x.sampler = sampler; + x.texid = texid; + x.Constant = Constant; + x.Settled = Settled; + return x; +} + +bool ZZshStartUsingShaders() { + + ZZLog::Error_Log("Creating effects."); + B_G(LoadEffects(), return false); + if (!glCreateShader) + { + ZZLog::Error_Log("GLSL shaders is not supported, stop."); + return false; + } + + init_shader(); + + // create a sample shader + clampInfo temp; + memset(&temp, 0, sizeof(temp)); + temp.wms = 3; temp.wmt = 3; + + g_nPixelShaderVer = 0;//SHADER_ACCURATE; + // test + bool bFailed; + FRAGMENTSHADER* pfrag = ZZshLoadShadeEffect(0, 1, 1, 1, 1, temp, 0, &bFailed); + if( bFailed || pfrag == NULL ) { + g_nPixelShaderVer = SHADER_ACCURATE|SHADER_REDUCED; + + pfrag = ZZshLoadShadeEffect(0, 0, 1, 1, 0, temp, 0, &bFailed); + if( pfrag != NULL ) + glLinkProgram(pfrag->Shader); + if( bFailed || pfrag == NULL || glGetError() != GL_NO_ERROR) { + g_nPixelShaderVer = SHADER_REDUCED; + ZZLog::Error_Log("Basic shader test failed."); + } + } + ZZshMainProgram = glCreateProgram(); + NumActiveUniforms = 0; + //SetGlobalUniform(&g_fparamFogColor, "g_fFogColor"); + //SetGlobalUniform(&g_vparamPosXY[0], "g_fPosXY[0]"); + //SetGlobalUniform(&g_vparamPosXY[1], NOCONTEXT?"g_fPosXY[1]":"g_fPosXY[0]"); + //NumGlobalUniforms = NumActiveUniforms; + + if (g_nPixelShaderVer & SHADER_REDUCED) + conf.bilinear = 0; + + ZZLog::Error_Log("Creating extra effects."); + B_G(ZZshLoadExtraEffects(), return false); + + ZZLog::Error_Log("Using %s shaders.", g_pShaders[g_nPixelShaderVer]); + + return true; +} + +// open shader file according to build target +bool ZZshCreateOpenShadersFile() { + std::string ShaderFileName("plugins/ps2hw_gl4.glsl"); + int ShaderFD = open(ShaderFileName.c_str(), O_RDONLY); + struct stat sb; + if ((ShaderFD == -1) || (fstat(ShaderFD, &sb) == -1)) { + // Each linux distributions have his rules for path so we give them the possibility to + // change it with compilation flags. -- Gregory +#ifdef GLSL_SHADER_DIR_COMPILATION +#define xGLSL_SHADER_DIR_str(s) GLSL_SHADER_DIR_str(s) +#define GLSL_SHADER_DIR_str(s) #s + ShaderFileName = string(xGLSL_SHADER_DIR_str(GLSL_SHADER_DIR_COMPILATION)) + "/ps2hw_gl4.glsl"; + ShaderFD = open(ShaderFileName.c_str(), O_RDONLY); +#endif + if ((ShaderFD == -1) || (fstat(ShaderFD, &sb) == -1)) { + ZZLog::Error_Log("No source for %s: \n", ShaderFileName.c_str()); + return false; + } + } + + ZZshSourceSize = sb.st_size; + ZZshSource = (char*)mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, ShaderFD, 0); // This function directly maped file into memory. + ZZshSource[ ZZshSourceSize - 1] = 0; // Made source null-terminated. + + close(ShaderFD); + return true; +} + +void ZZshExitCleaning() { + munmap(ZZshSource, ZZshSourceSize); + delete constant_buffer; + delete common_buffer; + delete vertex_buffer; + delete fragment_buffer; +} + +// Disable CG +void ZZshGLDisableProfile() { // This stop all other shader programs from running; + glUseProgram(0); +} +//Enable CG +void ZZshGLEnableProfile() { +} +//------------------------------------------------------------------------------------- + +// The same function for texture, also to cgGLEnable +void ZZshGLSetTextureParameter(ZZshParameter param, GLuint texobj, const char* name) { + g_cs.set_texture(param, texobj); +} + +void ZZshGLSetTextureParameter(ZZshShaderLink prog, ZZshParameter param, GLuint texobj, const char* name) { + FRAGMENTSHADER* shader = (FRAGMENTSHADER*)prog.link; + shader->set_texture(param, texobj); +} + +// This is helper of cgGLSetParameter4fv, made for debug purpose. +// Name could be any string. We must use it on compilation time, because erroneus handler does not +// return name +void ZZshSetParameter4fv(ZZshShaderLink& prog, ZZshParameter param, const float* v, const char* name) { + if (prog.isFragment) { + FRAGMENTSHADER* shader = (FRAGMENTSHADER*)prog.link; + shader->ZZshSetParameter4fv(param, v); + } else { + VERTEXSHADER* shader = (VERTEXSHADER*)prog.link; + shader->ZZshSetParameter4fv(param, v); + } +} + +void ZZshSetParameter4fv(ZZshParameter param, const float* v, const char* name) { + g_cs.ZZshSetParameter4fv(param, v); +} + +// The same stuff, but also with retry of param, name should be USED name of param for prog. +void ZZshSetParameter4fvWithRetry(ZZshParameter* param, ZZshShaderLink& prog, const float* v, const char* name) { + if (prog.isFragment) { + FRAGMENTSHADER* shader = (FRAGMENTSHADER*)prog.link; + shader->ZZshSetParameter4fv(*param, v); + } else { + VERTEXSHADER* shader = (VERTEXSHADER*)prog.link; + shader->ZZshSetParameter4fv(*param, v); + } +} + +// Used sometimes for color 1. +void ZZshDefaultOneColor( FRAGMENTSHADER& ptr ) { +// return; + ShaderHandleName = "Set Default One colot"; + float4 v = float4 ( 1, 1, 1, 1 ); + //ZZshSetParameter4fv(ptr.prog, ptr.sOneColor, v, "DegaultOne"); + // FIXME context + ptr.ZZshSetParameter4fv(ptr.sOneColor, v); +} +//------------------------------------------------------------------------------------- + +const GLchar * EmptyVertex = "void main(void) {gl_Position = ftransform();}"; +const GLchar * EmptyFragment = "void main(void) {gl_FragColor = gl_Color;}"; + +inline ZZshProgram UseEmptyProgram(const char* name, GLenum shaderType) { + GLuint shader = glCreateShader(shaderType); + if (shaderType == GL_VERTEX_SHADER) + glShaderSource(shader, 1, &EmptyVertex, NULL); + else + glShaderSource(shader, 1, &EmptyFragment, NULL); + + glCompileShader(shader); + ZZshProgram prog = glCreateProgram(); + glAttachShader(prog, shader); + glLinkProgram(prog); + if( !glIsProgram(prog) || glGetError() != GL_NO_ERROR ) { + ZZLog::Error_Log("Failed to load empty shader for %s:", name); + return -1; + } + ZZLog::Error_Log("Used Empty program for %s... Ok.",name); + return prog; +} + +ZZshShaderType ZZshGetShaderType(const char* name) { + if (strncmp(name, "TextureFog", 10) == 0) return ZZ_SH_TEXTURE_FOG; + if (strncmp(name, "Texture", 7) == 0) return ZZ_SH_TEXTURE; + if (strncmp(name, "RegularFog", 10) == 0) return ZZ_SH_REGULAR_FOG; + if (strncmp(name, "Regular", 7) == 0) return ZZ_SH_REGULAR; + if (strncmp(name, "Zero", 4) == 0) return ZZ_SH_ZERO; + return ZZ_SH_CRTC; +} + +inline ZZshShader UseEmptyShader(const char* name, GLenum shaderType) { + GLuint shader = glCreateShader(shaderType); + if (shaderType == GL_VERTEX_SHADER) + glShaderSource(shader, 1, &EmptyVertex, NULL); + else + glShaderSource(shader, 1, &EmptyFragment, NULL); + + glCompileShader(shader); + + ShaderNames[shader] = name; + ShaderTypes[shader] = ZZshGetShaderType(name); + + ZZLog::Error_Log("Used Empty shader for %s... Ok.",name); + return shader; +} + +inline bool GetCompilationLog(GLuint shader) { + GLint CompileStatus; + glGetShaderiv(shader, GL_COMPILE_STATUS, &CompileStatus); + if (CompileStatus == GL_TRUE) + return true; + + int* lenght, infologlength; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologlength); + char* InfoLog = new char[infologlength]; + glGetShaderInfoLog(shader, infologlength, lenght, InfoLog); + ZZLog::Error_Log("Compiling... %d:\t %s", shader, InfoLog); + + return false; +} + +inline bool CompileShader(ZZshProgram& shader, const char* DefineString, const char* name, GLenum shaderType) { + const GLchar* ShaderSource[2]; + ShaderSource[0] = (const GLchar*)DefineString; + ShaderSource[1] = (const GLchar*)ZZshSource; + + shader = glCreateShader(shaderType); + glShaderSource(shader, 2, &ShaderSource[0], NULL); + glCompileShader(shader); + ZZLog::Debug_Log("Creating shader %d for %s", shader, name); + + if (!GetCompilationLog(shader)) { + ZZLog::Error_Log("Failed to compile shader for %s:", name); + return false; + } + + ShaderTypes[shader] = ZZshGetShaderType(name); + ShaderNames[shader] = name; + + GL_REPORT_ERRORD(); + return true; +} + +inline bool LoadShaderFromFile(ZZshShader& shader, const char* DefineString, const char* name, GLenum ShaderType) { // Linux specific, as I presume + if (!CompileShader(shader, DefineString, name, ShaderType)) { + ZZLog::Error_Log("Failed to compile shader for %s: ", name); + return false; + } + + ZZLog::Error_Log("Used shader for %s... Ok",name); + return true; +} + +inline bool GetLinkLog(ZZshProgram prog) { + GLint LinkStatus; + glGetProgramiv(prog, GL_LINK_STATUS, &LinkStatus); + + int unif, atrib; + glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &unif); + glGetProgramiv(prog, GL_ACTIVE_ATTRIBUTES, &atrib); + UNIFORM_ERROR_LOG("Uniforms %d, attributes %d", unif, atrib); + + if (LinkStatus == GL_TRUE && glIsProgram(prog)) return true; + +#if defined(DEVBUILD) || defined(_DEBUG) + int* lenght, infologlength; + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &infologlength); + char* InfoLog = new char[infologlength]; + glGetProgramInfoLog(prog, infologlength, lenght, InfoLog); + if (!infologlength == 0) + ZZLog::Error_Log("Linking %d... %d:\t %s", prog, infologlength, InfoLog); +#endif + + return false; + +} + +//------------------------------------------------------------------------------------- + +static bool ValidateProgram(ZZshProgram Prog) { + GLint isValid; + glGetProgramiv(Prog, GL_VALIDATE_STATUS, &isValid); + + if (!isValid) { + glValidateProgram(Prog); + int* lenght, infologlength; + glGetProgramiv(Prog, GL_INFO_LOG_LENGTH, &infologlength); + char* InfoLog = new char[infologlength]; + glGetProgramInfoLog(Prog, infologlength, lenght, InfoLog); + ZZLog::Error_Log("Validation %d... %d:\t %s", Prog, infologlength, InfoLog); + } + return (isValid != 0); +} + +static void PutParametersAndRun(VERTEXSHADER* vs, FRAGMENTSHADER* ps) { + UNIFORM_ERROR_LOG("Run program %s(%d) \t+\t%s(%d)", ShaderNames[vs->Shader], vs->Shader, ShaderNames[ps->Shader], ps->Shader); + + glUseProgram(ZZshMainProgram); + if (glGetError() != GL_NO_ERROR) { + ZZLog::Error_Log("Something weird happened on Linking stage."); + + glUseProgram(0); + return; + } + + // FIXME context argument + int context = 0; + PutParametersInProgam(vs, ps, context); + + ValidateProgram(ZZshMainProgram); + GL_REPORT_ERRORD(); +} + +static void CreateNewProgram(VERTEXSHADER* vs, FRAGMENTSHADER* ps) { + ZZLog::Error_Log("\n---> New shader program %d, %s(%d) \t+\t%s(%d).", ZZshMainProgram, ShaderNames[vs->Shader], vs->Shader, ShaderNames[ps->Shader], ps->Shader); + + if (vs->Shader != 0) + glAttachShader(ZZshMainProgram, vs->Shader); + if (ps->Shader != 0) + glAttachShader(ZZshMainProgram, ps->Shader); + + glLinkProgram(ZZshMainProgram); + if (!GetLinkLog(ZZshMainProgram)) { + ZZLog::Error_Log("Main program linkage error, don't use any shader for this stage."); + return; + } + + GL_REPORT_ERRORD(); +} + +inline bool ZZshCheckShaderCompatibility(VERTEXSHADER* vs, FRAGMENTSHADER* ps) { + if (vs == NULL) return false; + if (vs->ShaderType == ZZ_SH_ZERO) return true; // ZeroPS is compatible with everything + if (ps == NULL) return false; + + return (vs->ShaderType == ps->ShaderType); +} + +static void ZZshSetShader(VERTEXSHADER* vs, FRAGMENTSHADER* ps) { + if (!ZZshCheckShaderCompatibility(vs, ps)) // We don't need to link uncompatible shaders + return; + + int vss = (vs!=NULL)?vs->Shader:0; + int pss = (ps!=NULL)?ps->Shader:0; + + if (vss !=0 && pss != 0) { + if (CompiledPrograms[vss][pss] != 0 && glIsProgram(CompiledPrograms[vss][pss])) { + ZZshMainProgram = CompiledPrograms[vs->Shader][ps->Shader]; + } + else { + ZZshProgram NewProgram = glCreateProgram(); + ZZshMainProgram = NewProgram; + CompiledPrograms[vss][pss] = NewProgram; + CreateNewProgram(vs, ps) ; + } + + PutParametersAndRun(vs, ps); + GL_REPORT_ERRORD(); + } +} + +void ZZshSetVertexShader(ZZshShaderLink prog) { + g_vsprog = prog; + ZZshSetShader((VERTEXSHADER*)(g_vsprog.link), (FRAGMENTSHADER*)(g_psprog.link)) ; +} + +void ZZshSetPixelShader(ZZshShaderLink prog) { + g_psprog = prog; + ZZshSetShader((VERTEXSHADER*)(g_vsprog.link), (FRAGMENTSHADER*)(g_psprog.link)) ; +} + +//------------------------------------------------------------------------------------------------------------------ + +#ifdef GLSL4_API +static void init_shader() { + // Warning put same order than GLSL + constant_buffer = new GSUniformBufferOGL(0, sizeof(ConstantUniform)); + common_buffer = new GSUniformBufferOGL(1, sizeof(GlobalUniform)); + vertex_buffer = new GSUniformBufferOGL(2, sizeof(VertexUniform)); + fragment_buffer = new GSUniformBufferOGL(3, sizeof(FragmentUniform)); + + constant_buffer->bind(); + constant_buffer->upload((void*)&g_cs.uniform_buffer_constant); +} + +static void PutParametersInProgam(VERTEXSHADER* vs, FRAGMENTSHADER* ps, int context) { + + common_buffer->bind(); + common_buffer->upload((void*)&g_cs.uniform_buffer[context]); + + vertex_buffer->bind(); + vertex_buffer->upload((void*)&vs->uniform_buffer[context]); + + fragment_buffer->bind(); + fragment_buffer->upload((void*)&ps->uniform_buffer[context]); + + // FIXME DEBUG +#ifdef _DEBUG + GLint cb_idx = glGetUniformBlockIndex(ZZshMainProgram, "constant_buffer"); + GLint co_idx = glGetUniformBlockIndex(ZZshMainProgram, "common_buffer"); + GLint fb_idx = glGetUniformBlockIndex(ZZshMainProgram, "fragment_buffer"); + GLint vb_idx = glGetUniformBlockIndex(ZZshMainProgram, "vertex_buffer"); + + GLint debug; + + ZZLog::Error_Log("NEW !!!"); + if (cb_idx != GL_INVALID_INDEX) { + glGetActiveUniformBlockiv(ZZshMainProgram, cb_idx, GL_UNIFORM_BLOCK_BINDING, &debug); + ZZLog::Error_Log("cb active : %d", debug); + glGetActiveUniformBlockiv(ZZshMainProgram, cb_idx, GL_UNIFORM_BLOCK_DATA_SIZE, &debug); + ZZLog::Error_Log("size : %d", debug); + } + + if (co_idx != GL_INVALID_INDEX) { + glGetActiveUniformBlockiv(ZZshMainProgram, co_idx, GL_UNIFORM_BLOCK_BINDING, &debug); + ZZLog::Error_Log("co active : %d", debug); + glGetActiveUniformBlockiv(ZZshMainProgram, co_idx, GL_UNIFORM_BLOCK_DATA_SIZE, &debug); + ZZLog::Error_Log("size : %d", debug); + } + + if (vb_idx != GL_INVALID_INDEX) { + glGetActiveUniformBlockiv(ZZshMainProgram, vb_idx, GL_UNIFORM_BLOCK_BINDING, &debug); + ZZLog::Error_Log("vb active : %d", debug); + glGetActiveUniformBlockiv(ZZshMainProgram, vb_idx, GL_UNIFORM_BLOCK_DATA_SIZE, &debug); + ZZLog::Error_Log("size : %d", debug); + } + + if (fb_idx != GL_INVALID_INDEX) { + glGetActiveUniformBlockiv(ZZshMainProgram, fb_idx, GL_UNIFORM_BLOCK_BINDING, &debug); + ZZLog::Error_Log("fb active : %d", debug); + glGetActiveUniformBlockiv(ZZshMainProgram, fb_idx, GL_UNIFORM_BLOCK_DATA_SIZE, &debug); + ZZLog::Error_Log("size : %d", debug); + } +#endif + + g_cs.enable_texture(); + ps->enable_texture(context); +} + +#endif + +static void SetupFragmentProgramParameters(FRAGMENTSHADER* pf, int context, int type) +{ + // uniform parameters + GLint p; + pf->prog.link = (void*)pf; // Setting autolink + pf->prog.isFragment = true; // Setting autolink + pf->ShaderType = ShaderTypes[pf->Shader]; + + g_cs.set_texture(g_cs.sBlocks, ptexBlocks); + g_cs.set_texture(g_cs.sConv16to32, ptexConv16to32); + g_cs.set_texture(g_cs.sConv32to16, ptexConv32to16); + g_cs.set_texture(g_cs.sBilinearBlocks, ptexBilinearBlocks); + + GL_REPORT_ERRORD(); +} + +void SetupVertexProgramParameters(VERTEXSHADER* pf, int context) +{ + GLint p; + pf->prog.link = (void*)pf; // Setting autolink + pf->prog.isFragment = false; // Setting autolink + pf->ShaderType = ShaderTypes[pf->Shader]; + + GL_REPORT_ERRORD(); +} + +//const int GLSL_VERSION = 130; // Sampler2DRect appear in 1.3 +const int GLSL_VERSION = 420; + +// We use strictly compilation from source for GSLS +static __forceinline void GlslHeaderString(char* header_string, const char* name, const char* depth) +{ + sprintf(header_string, "#version %d\n#define %s main\n%s\n", GLSL_VERSION, name, depth); +} + +static __forceinline bool LOAD_VS(char* DefineString, const char* name, VERTEXSHADER& vertex, int shaderver, ZZshProfile context, const char* depth) +{ + bool flag; + char temp[200]; + GlslHeaderString(temp, name, depth); + sprintf(DefineString, "%s#define VERTEX_SHADER 1\n#define CTX %d\n", temp, context * NOCONTEXT); + //ZZLog::WriteLn("Define for VS == '%s'", DefineString); + flag = LoadShaderFromFile(vertex.Shader, DefineString, name, GL_VERTEX_SHADER); + SetupVertexProgramParameters(&vertex, context); + return flag; +} + +static __forceinline bool LOAD_PS(char* DefineString, const char* name, FRAGMENTSHADER& fragment, int shaderver, ZZshProfile context, const char* depth) +{ + bool flag; + char temp[200]; + GlslHeaderString(temp, name, depth); + sprintf(DefineString, "%s#define FRAGMENT_SHADER 1\n#define CTX %d\n", temp, context * NOCONTEXT); + //ZZLog::WriteLn("Define for PS == '%s'", DefineString); + + flag = LoadShaderFromFile(fragment.Shader, DefineString, name, GL_FRAGMENT_SHADER); + SetupFragmentProgramParameters(&fragment, context, 0); + return flag; +} + +inline bool LoadEffects() +{ + // clear the textures + for(u32 i = 0; i < ArraySize(ppsTexture); ++i) { + SAFE_RELEASE_PROG(ppsTexture[i].prog); + } + +#ifndef _DEBUG + memset(ppsTexture, 0, sizeof(ppsTexture)); +#endif + + return true; +} + +bool ZZshLoadExtraEffects() { + bool bLoadSuccess = true; + char DefineString[DEFINE_STRING_SIZE] = ""; + const char* writedepth = "#define WRITE_DEPTH 1\n"; // should we write depth field + + + const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; + + for (int i = 0; i < 4; ++i) { + if (!LOAD_VS(DefineString, pvsshaders[i], pvsStore[2 * i], cgvProf, 0, "")) bLoadSuccess = false; + if (!LOAD_VS(DefineString, pvsshaders[i], pvsStore[2 *i + 1 ], cgvProf, 1, "")) bLoadSuccess = false; + if (!LOAD_VS(DefineString, pvsshaders[i], pvsStore[2 *i + 8 ], cgvProf, 0, writedepth)) bLoadSuccess = false; + if (!LOAD_VS(DefineString, pvsshaders[i], pvsStore[2 *i + 8 + 1], cgvProf, 1, writedepth)) bLoadSuccess = false; + } + for (int i = 0; i < 16; ++i) + pvs[i] = pvsStore[i].prog; + + if (!LOAD_VS(DefineString, "BitBltVS", pvsBitBlt, cgvProf, 0, "")) bLoadSuccess = false; + GLint p; + GL_REPORT_ERRORD(); + + if (!LOAD_PS(DefineString, "RegularPS", ppsRegular[0], cgfProf, 0, "")) bLoadSuccess = false; + if (!LOAD_PS(DefineString, "RegularFogPS", ppsRegular[1], cgfProf, 0, "")) bLoadSuccess = false; + + if( conf.mrtdepth ) { + if (!LOAD_PS(DefineString, "RegularPS", ppsRegular[2], cgfProf, 0, writedepth)) bLoadSuccess = false; + if (!bLoadSuccess) conf.mrtdepth = 0; + + if (!LOAD_PS(DefineString, "RegularFogPS", ppsRegular[3], cgfProf, 0, writedepth)) bLoadSuccess = false; + if (!bLoadSuccess) conf.mrtdepth = 0; + } + + if (!LOAD_PS(DefineString, "BitBltPS", ppsBitBlt[0], cgfProf, 0, "")) bLoadSuccess = false; + if (!LOAD_PS(DefineString, "BitBltAAPS", ppsBitBlt[1], cgfProf, 0, "")) bLoadSuccess = false; + if (!bLoadSuccess) { + ZZLog::Error_Log("Failed to load BitBltAAPS, using BitBltPS."); + if (!LOAD_PS(DefineString, "BitBltPS", ppsBitBlt[1], cgfProf, 0, "")) bLoadSuccess = false; + } + + if (!LOAD_PS(DefineString, "BitBltDepthPS", ppsBitBltDepth, cgfProf, 0, "")) bLoadSuccess = false; + if (!LOAD_PS(DefineString, "CRTCTargPS", ppsCRTCTarg[0], cgfProf, 0, "")) bLoadSuccess = false; + if (!LOAD_PS(DefineString, "CRTCTargInterPS", ppsCRTCTarg[1], cgfProf, 0, "")) bLoadSuccess = false; + + g_bCRTCBilinear = true; + if (!LOAD_PS(DefineString, "CRTCPS", ppsCRTC[0], cgfProf, 0, "")) bLoadSuccess = false; + if( !bLoadSuccess ) { + // switch to simpler + g_bCRTCBilinear = false; + if (!LOAD_PS(DefineString, "CRTCPS_Nearest", ppsCRTC[0], cgfProf, 0, "")) bLoadSuccess = false; + if (!LOAD_PS(DefineString, "CRTCInterPS_Nearest", ppsCRTC[0], cgfProf, 0, "")) bLoadSuccess = false; + } + else { + if (!LOAD_PS(DefineString, "CRTCInterPS", ppsCRTC[1], cgfProf, 0, "")) bLoadSuccess = false; + } + + if( !bLoadSuccess ) + ZZLog::Error_Log("Failed to create CRTC shaders."); + + // if (!LOAD_PS(DefineString, "CRTC24PS", ppsCRTC24[0], cgfProf, 0, "")) bLoadSuccess = false; + // if (!LOAD_PS(DefineString, "CRTC24InterPS", ppsCRTC24[1], cgfProf, 0, "")) bLoadSuccess = false; + if (!LOAD_PS(DefineString, "ZeroPS", ppsOne, cgfProf, 0, "")) bLoadSuccess = false; + if (!LOAD_PS(DefineString, "BaseTexturePS", ppsBaseTexture, cgfProf, 0, "")) bLoadSuccess = false; + if (!LOAD_PS(DefineString, "Convert16to32PS", ppsConvert16to32, cgfProf, 0, "")) bLoadSuccess = false; + if (!LOAD_PS(DefineString, "Convert32to16PS", ppsConvert32to16, cgfProf, 0, "")) bLoadSuccess = false; + + GL_REPORT_ERRORD(); + return true; +} + +const static char* g_pPsTexWrap[] = { "#define REPEAT 1\n", "#define CLAMP 1\n", "#define REGION_REPEAT 1\n", "" }; + +static ZZshShader LoadShaderFromType(const char* srcdir, const char* srcfile, int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int ps, int context) { + + assert( texwrap < NUM_TEXWRAPS); + assert( type < NUM_TYPES ); + //ZZLog::Error_Log("\n"); + + ZZshProgram prog; + + char* name = new char[MAX_SHADER_NAME_SIZE]; + sprintf(name, "Texture%s%d_%sPS", fog?"Fog":"", texfilter, g_pTexTypes[type]); + + ZZLog::Debug_Log("Starting shader for %s", name); + + const char* AddWrap = g_pPsTexWrap[texwrap]; + const char* AddDepth = writedepth?"#define WRITE_DEPTH 1\n":""; + const char* AddAEM = testaem?"#define TEST_AEM 1\n":""; + const char* AddExcolor = exactcolor?"#define EXACT_COLOR 1\n":""; + const char* AddAccurate = (ps & SHADER_ACCURATE)?"#define ACCURATE_DECOMPRESSION 1\n":""; + char DefineString[DEFINE_STRING_SIZE] = ""; + char temp[200]; + GlslHeaderString(temp, name, AddWrap); + sprintf(DefineString, "%s#define FRAGMENT_SHADER 1\n%s%s%s%s\n#define CTX %d\n", temp, AddDepth, AddAEM, AddExcolor, AddAccurate, context * NOCONTEXT); + + ZZshShader shader; + if (!CompileShader(shader, DefineString, name, GL_FRAGMENT_SHADER)) + return UseEmptyShader(name, GL_FRAGMENT_SHADER); + + ZZLog::Debug_Log("Used shader for type:%d filter:%d wrap:%d for:%d depth:%d aem:%d color:%d decompression:%d ctx:%d... Ok \n", type, texfilter, texwrap, fog, writedepth, testaem, exactcolor, ps, context); + + GL_REPORT_ERRORD(); + return shader; +} + +FRAGMENTSHADER* ZZshLoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed) +{ + int texwrap; + + assert( texfilter < NUM_FILTERS ); + //assert( g_nPixelShaderVer == SHADER_30 ); + if( clamp.wms == clamp.wmt ) { + switch( clamp.wms ) { + case 0: texwrap = TEXWRAP_REPEAT; break; + case 1: texwrap = TEXWRAP_CLAMP; break; + case 2: texwrap = TEXWRAP_CLAMP; break; + default: + texwrap = TEXWRAP_REGION_REPEAT; break; + } + } + else if( clamp.wms==3||clamp.wmt==3) + texwrap = TEXWRAP_REGION_REPEAT; + else + texwrap = TEXWRAP_REPEAT_CLAMP; + + int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); + + if( pbFailed != NULL ) *pbFailed = false; + + FRAGMENTSHADER* pf = ppsTexture+index; + + if (ZZshExistProgram(pf)) + { + return pf; + } + pf->Shader = LoadShaderFromType(EFFECT_DIR, EFFECT_NAME, type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, g_nPixelShaderVer, context); + + if (ZZshExistProgram(pf)) { + SetupFragmentProgramParameters(pf, context, type); + GL_REPORT_ERRORD(); + + if( glGetError() != GL_NO_ERROR ) { + ZZLog::Error_Log("Failed to load shader %d,%d,%d,%d.", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if (pbFailed != NULL ) *pbFailed = true; + return pf; + } + + return pf; + } + + ZZLog::Error_Log("Failed to create shader %d,%d,%d,%d.", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if( pbFailed != NULL ) *pbFailed = true; + + GL_REPORT_ERRORD(); + return NULL; +} + +#endif // GLSL_API diff --git a/plugins/zzogl-pg/opengl/ZZoglShoots.cpp b/plugins/zzogl-pg/opengl/ZZoglShoots.cpp index b43c64d942..437762ce21 100644 --- a/plugins/zzogl-pg/opengl/ZZoglShoots.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglShoots.cpp @@ -101,7 +101,7 @@ bool SaveRenderTarget(const char* filename, int width, int height, int jpeg) } // Save selected texture as TGA -bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height) +bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height, int ext_format) { vector data(width*height); glBindTexture(textarget, tex); @@ -109,7 +109,19 @@ bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int he if (glGetError() != GL_NO_ERROR) return false; - return SaveTGA(filename, width, height, &data[0]); + if (ext_format == EXT_BMP) + return SaveBMP(filename, width, height, &data[0]); + else if (ext_format == EXT_TGA) + return SaveTGA(filename, width, height, &data[0]); + else + return false; +} + +// Save image as BMP +bool SaveBMP(const char* filename, int width, int height, void* pdata) +{ + // FIXME + assert(0); } // save image as JPEG diff --git a/plugins/zzogl-pg/opengl/ZZoglShoots.h b/plugins/zzogl-pg/opengl/ZZoglShoots.h index 98bb1383df..0fc56c9205 100644 --- a/plugins/zzogl-pg/opengl/ZZoglShoots.h +++ b/plugins/zzogl-pg/opengl/ZZoglShoots.h @@ -22,9 +22,10 @@ void SaveSnapshot(const char* filename); bool SaveRenderTarget(const char* filename, int width, int height, int jpeg); -bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height); +bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height, int ext_format = 0); bool SaveJPEG(const char* filename, int width, int height, const void* pdata, int quality); bool SaveTGA(const char* filename, int width, int height, void* pdata); +bool SaveBMP(const char* filename, int width, int height, void* pdata); void Stop_Avi(); void Delete_Avi_Capture(); @@ -32,4 +33,10 @@ void StartCapture(); void StopCapture(); void CaptureFrame(); +enum { + EXT_TGA = 0, + EXT_BMP = 1, + EXT_JPG = 2 +}; + #endif // ZZOGLSHOOTS_H_INCLUDED diff --git a/plugins/zzogl-pg/opengl/ps2hw_gl4.glsl b/plugins/zzogl-pg/opengl/ps2hw_gl4.glsl new file mode 100644 index 0000000000..4f910f9e32 --- /dev/null +++ b/plugins/zzogl-pg/opengl/ps2hw_gl4.glsl @@ -0,0 +1,839 @@ +//#version 420 Keep it for text editor detection +// Cg Shaders for PS2 GS emulation + +// divides by z for every pixel, instead of in vertex shader +// fixes kh textures + +#extension ARB_texture_rectangle: require +#define GL_compatibility_profile 1 +#define PERSPECTIVE_CORRECT_TEX + +// When writting GLSL code we should change variables in code according to denominator +// Not than in and out variables are differ! +// in POSITION set by glVertexPointer goes to gl_Vertex; +// out POSITION goes to gl_position +// in COLOR0 gl_Color +// out COLOR0 gl_FrontColor +// in TEXCOORD0 gl_MultiTexCoord0 +// out TEXCOORD0 gl_TexCoord[0] + +//in Fragments: +// in TEXCOORD0 gl_TexCoord[0] +// out COLOR0 gl_FragData[0] + +//#define TEST_AEM // tests AEM for black pixels +//#define REGION_REPEAT // set if texture wrapping mode is region repeat +//#define WRITE_DEPTH // set if depth is also written in a MRT +//#define ACCURATE_DECOMPRESSION // set for less capable hardware ATI Radeon 9000 series +//#define EXACT_COLOR // make sure the output color is clamped to 1/255 boundaries (for alpha testing) + +#ifdef PERSPECTIVE_CORRECT_TEX +#define TEX_XY tex.xy/tex.z +#define TEX_DECL vec4 +#else +#define TEX_XY tex.xy +#define TEX_DECL vec4 +#endif + +#ifdef WRITE_DEPTH +#define DOZWRITE(x) x +#else +#define DOZWRITE(x) +#endif + +// NVidia CG-data types +#define half2 vec2 +#define half3 vec3 +#define half4 vec4 +#define float2 vec2 +#define float3 vec3 +#define float4 vec4 + +//////////////////////////////////////////////////////////////////// +// Texture SAMPLER +//////////////////////////////////////////////////////////////////// +// // main ps2 memory, each pixel is stored in 32bit color +// uniform sampler2DRect g_sMemory[2]; +// +// // used to get the tiled offset into a page given the linear offset +// uniform sampler2DRect g_sSrcFinal; +// uniform sampler2D g_sBlocks; +// uniform sampler2D g_sBilinearBlocks; +// uniform sampler2D g_sConv16to32; +// uniform sampler3D g_sConv32to16; +// uniform sampler2DRect g_sBitwiseANDX; +// uniform sampler2DRect g_sBitwiseANDY; +// uniform sampler2DRect g_sInterlace; +// +// // used only on rare cases where the render target is PSMT8H +// uniform sampler2D g_sCLUT; +// main ps2 memory, each pixel is stored in 32bit color +layout(binding = 0) uniform sampler2DRect g_sMemory; // dual context + +// used to get the tiled offset into a page given the linear offset +layout(binding = 1) uniform sampler2DRect g_sSrcFinal; +layout(binding = 2) uniform sampler2D g_sBlocks; +layout(binding = 3) uniform sampler2D g_sBilinearBlocks; +layout(binding = 4) uniform sampler2D g_sConv16to32; +layout(binding = 5) uniform sampler3D g_sConv32to16; +layout(binding = 6) uniform sampler2DRect g_sBitwiseANDX; +layout(binding = 7) uniform sampler2DRect g_sBitwiseANDY; +layout(binding = 8) uniform sampler2DRect g_sInterlace; + +// used only on rare cases where the render target is PSMT8H +layout(binding = 9) uniform sampler2D g_sCLUT; + +// Uniform buffer +layout(std140, binding = 0) uniform constant_buffer +{ + // Both shader + // .z is used for the addressing fn + // FIXME: not same value between c and shader... + // float4 g_fBilinear = float4(-0.7f, -0.65f, 0.9,1/32767.0f); + float4 g_fBilinear; + float4 g_fZBias; + float4 g_fc0; + float4 g_fMult; + // Vertex + float4 g_fZ; // transforms d3dcolor z into float z + float4 g_fZMin; + float4 g_fZNorm; + // Pixel + half4 g_fExactColor; +}; +layout(std140, binding = 1) uniform common_buffer +{ + float4 g_fPosXY; + float4 g_fFogColor; +}; +layout(std140, binding = 2) uniform vertex_buffer +{ + float4 g_fBitBltPos; + float4 g_fBitBltTex; + float4 g_fBitBltTrans; +}; +layout(std140, binding = 3) uniform fragment_buffer +{ + half4 fTexAlpha2; + + float4 g_fTexOffset; // converts the page and block offsets into the mem addr/1024 + float4 g_fTexDims; // mult by tex dims when accessing the block texture + float4 g_fTexBlock; + + float4 g_fClampExts; // if clamping the texture, use (minu, minv, maxu, maxv) + float4 TexWrapMode; // 0 - repeat/clamp, 1 - region rep (use fRegRepMask) + + float4 g_fRealTexDims; // tex dims used for linear filtering (w,h,1/w,1/h) + + // (alpha0, alpha1, 1 if highlight2 and tcc is rgba, 1-y) + half4 g_fTestBlack; // used for aem bit + + float4 g_fPageOffset; + + half4 fTexAlpha; + + float4 g_fInvTexDims; // similar to g_fClutOff + + // used for rectblitting + float4 g_fBitBltZ; + + half4 g_fOneColor; // col*.xxxy+.zzzw +}; + + +// given a local tex coord, returns the coord in the memory +float2 ps2memcoord(float2 realtex) +{ + float4 off; + + // block off + realtex.xy = realtex.xy * g_fTexDims.xy + g_fTexDims.zw; + realtex.xy = (realtex.xy - fract(realtex.xy)) * g_fMult.zw; + float2 fblock = fract(realtex.xy); + off.xy = realtex.xy-fblock.xy; + +#ifdef ACCURATE_DECOMPRESSION + off.zw = texture(g_sBlocks, g_fTexBlock.xy*fblock + g_fTexBlock.zw).ar; + off.x = dot(off.xy, g_fTexOffset.xy); + float r = g_fTexOffset.w; + float f = fract(off.x); + float fadd = g_fTexOffset.z * off.z; + off.w = off.x + fadd + r; + off.x = fract(f + fadd + r); + off.w -= off.x ; +#else + off.z = texture(g_sBlocks, g_fTexBlock.xy*fblock + g_fTexBlock.zw).a; + + // combine the two + off.x = dot(off.xyz, g_fTexOffset.xyz)+g_fTexOffset.w; + off.x = modf(off.x, off.w); +#endif + + off.xy = off.xw * g_fPageOffset.zy + g_fPageOffset.wx; + //off.y = off.w * g_fPageOffset.y + g_fPageOffset.x; + return off.xy; +} + +// find all texcoords for bilinear filtering +// assume that orgtex are already on boundaries +void ps2memcoord4(float4 orgtex, out float4 off0, out float4 off1) +{ + //float4 off0, off1, off2, off3; + float4 realtex; + + // block off + realtex = (orgtex * g_fTexDims.xyxy + g_fTexDims.zwzw);// * g_fMult.zwzw; + float4 fblock = fract(realtex.xyzw); + float4 ftransblock = g_fTexBlock.xyxy*fblock + g_fTexBlock.zwzw; + realtex -= fblock; + + float4 transvals = g_fTexOffset.x * realtex.xzxz + g_fTexOffset.y * realtex.yyww + g_fTexOffset.w; + + float4 colors;// = texture(g_sBilinearBlocks, ftransblock.xy); + + // this is faster on ffx ingame + colors.x = texture(g_sBlocks, ftransblock.xy).a; + colors.y = texture(g_sBlocks, ftransblock.zy).a; + colors.z = texture(g_sBlocks, ftransblock.xw).a; + colors.w = texture(g_sBlocks, ftransblock.zw).a; + + float4 fr, rem; + +#ifdef ACCURATE_DECOMPRESSION + fr = fract(transvals); + float4 fadd = colors * g_fTexOffset.z; + rem = transvals + fadd; + fr = fract(fr + fadd); + rem -= fr; +#else + transvals += colors * g_fTexOffset.z; + + fr = modf(transvals, rem); +#endif + + rem = rem * g_fPageOffset.y + g_fPageOffset.x; + fr = fr * g_fPageOffset.z + g_fPageOffset.w; + + // combine + off0 = g_fc0.yxyx * fr.xxyy + g_fc0.xyxy * rem.xxyy; + off1 = g_fc0.yxyx * fr.zzww + g_fc0.xyxy * rem.zzww; +} + +void ps2memcoord4_fast(float4 orgtex, out float4 off0, out float4 off1) +{ + float4 realtex; + + realtex = (orgtex * g_fTexDims.xyxy + g_fTexDims.zwzw);// * g_fMult.zwzw; + float4 fblock = fract(realtex.xyzw); + float2 ftransblock = g_fTexBlock.xy*fblock.xy + g_fTexBlock.zw; + realtex -= fblock; + + float4 transvals = g_fTexOffset.x * realtex.xzxz + g_fTexOffset.y * realtex.yyww + g_fTexOffset.w; + + float4 colors = texture(g_sBilinearBlocks, ftransblock.xy); + float4 fr, rem; + +#ifdef ACCURATE_DECOMPRESSION + fr = fract(transvals); + float4 fadd = colors * g_fTexOffset.z; + rem = transvals + fadd; + fr = fract(fr + fadd); + rem -= fr; +#else + transvals += colors * g_fTexOffset.z; + + fr = modf(transvals, rem); +#endif + + rem = rem * g_fPageOffset.y + g_fPageOffset.x; + fr = fr * g_fPageOffset.z; + + off0 = g_fc0.yxyx * fr.xxyy + g_fc0.xyxy * rem.xxyy; + off1 = g_fc0.yxyx * fr.zzww + g_fc0.xyxy * rem.zzww; +} + +// Wrapping modes +#if defined(REPEAT) + +float2 ps2addr(float2 coord) +{ + return fract(coord.xy); +} + +#elif defined(CLAMP) + +float2 ps2addr(float2 coord) +{ + return clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw); +} + +#elif defined(REGION_REPEAT) + +// computes the local tex coord along with addressing modes +float2 ps2addr(float2 coord) +{ + float2 final = fract(clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw)); + + if( TexWrapMode.x > g_fBilinear.z ) // region repeat mode for x (umsk&x)|ufix + final.x = texture(g_sBitwiseANDX, abs(coord.x)*TexWrapMode.zx).x * g_fClampExts.x + g_fClampExts.z; + if( TexWrapMode.y > g_fBilinear.z ) // region repeat mode for x (vmsk&x)|vfix + final.y = texture(g_sBitwiseANDY, abs(coord.y)*TexWrapMode.wy).x * g_fClampExts.y + g_fClampExts.w; + + return final; +} + +#else + +float2 ps2addr(float2 coord) +{ + return fract(clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw)); +} + +#endif + +half4 tex2DPS_32(float2 tex0) +{ + return texture(g_sMemory, ps2memcoord(tex0).xy); +} + +// use when texture is not tiled -- shader 1 +half4 tex2DPS_tex32(float2 tex0) +{ + return texture(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw)*g_fZBias.zzzw+g_fPageOffset.w; +} + +// use when texture is not tiled -- shader 2 +half4 tex2DPS_clut32(float2 tex0) +{ + float index = texture(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw).a+g_fPageOffset.w; + return texture(g_sCLUT, index*g_fExactColor.xz+g_fExactColor.yz); +} + +// Shader 3 +// use when texture is not tiled and converting from 32bit to 16bit +// don't convert on the block level, only on the column level +// so every other 8 pixels, use the upper bits instead of lower +half4 tex2DPS_tex32to16(float2 tex0) +{ + bool upper = false; + tex0.y += g_fPageOffset.z; + float2 ffrac = mod(tex0, g_fTexOffset.xy); + tex0.xy = g_fc0.ww * (tex0.xy + ffrac); + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + upper = true; + } + if( ffrac.y >= g_fTexOffset.w ) { + tex0.y -= g_fTexOffset.w; + tex0.x += g_fc0.w; + } + + half4 color = texture(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw)*g_fZBias.zzzw+g_fPageOffset.w; + float2 uv = upper ? color.xw : color.zy; + return texture(g_sConv16to32, uv+g_fPageOffset.xy); +} + +// Shader 4 +// used when a 16 bit texture is used an 8h +half4 tex2DPS_tex16to8h(float2 tex0) +{ + float4 final; + float2 ffrac = mod(tex0+g_fPageOffset.zw, g_fTexOffset.xy); + tex0.xy = g_fPageOffset.xy * tex0.xy - ffrac * g_fc0.yw; + + if( ffrac.x > g_fTexOffset.x*g_fc0.w ) + tex0.x += g_fTexOffset.x*g_fc0.w; + if( tex0.x >= g_fc0.y ) tex0 += g_fTexOffset.zw; + + float4 upper = texture(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw); + + // only need alpha + float index = texture(g_sConv32to16, upper.zyx-g_fc0.z).y + upper.w*g_fc0.w*g_fc0.w; + return texture(g_sCLUT, index+g_fExactColor.yz); +} + +// Shader 5 +// used when a 16 bit texture is used a 32bit one +half4 tex2DPS_tex16to32(float2 tex0) +{ + float4 final; + float2 ffrac = mod(tex0+g_fPageOffset.zw, g_fTexOffset.xy); + //tex0.xy = g_fPageOffset.xy * tex0.xy - ffrac * g_fc0.yw; + tex0.y += g_fPageOffset.y * ffrac.y; + + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + tex0.y += g_fTexOffset.w; + } + + float fconst = g_fc0.w*g_fc0.w; + float4 lower = texture(g_sSrcFinal, g_fTexDims.xy*tex0); + float4 upper = texture(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw); + + final.zy = texture(g_sConv32to16, lower.zyx).xy + lower.ww*fconst; + final.xw = texture(g_sConv32to16, upper.zyx).xy + upper.ww*fconst; + return final; +} + +half4 tex2DPS_tex16to32h(float2 tex0) +{ + float4 final = vec4(0.0, 0.0, 0.0, 0.0); + return final; +} + +//half4 f; +//f.w = old.y > (127.2f/255.0f) ? 1 : 0; +//old.y -= 0.5f * f.w; +//f.xyz = fract(old.yyx*half3(2.002*255.0f/256.0f, 64.025f*255.0f/256.0f, 8.002*255.0f/256.0f)); +//f.y += old.x * (0.25f*255.0f/256.0f); + +//////////////////////////////// +// calculates the texture color +//////////////////////////////// + +#define decl_ps2shade(num) \ +decl_ps2shade_##num(_32) \ +decl_ps2shade_##num(_tex32) \ +decl_ps2shade_##num(_clut32) \ +decl_ps2shade_##num(_tex32to16) \ +decl_ps2shade_##num(_tex16to8h) \ +decl_ps2shade_##num(_tex16to32h) + +// nearest +#define decl_ps2shade_0(bit) \ +float4 ps2shade0##bit( TEX_DECL tex) \ +{ \ + return tex2DPS##bit( ps2addr(TEX_XY)); \ +} + +// do fast memcoord4 calcs when textures behave well +#ifdef REPEAT +#define PS2MEMCOORD4 ps2memcoord4 +#else +#define PS2MEMCOORD4 ps2memcoord4 +#endif + + +#define decl_BilinearFilter(bit, addrfn) \ +half4 BilinearFilter##bit(float2 tex0) \ +{ \ + float4 off0, off1; \ + float4 ftex; \ + float2 ffrac; \ + ftex.xy = tex0 + g_fBilinear.xy * g_fRealTexDims.zw; \ + ffrac = fract(ftex.xy*g_fRealTexDims.xy); \ + ftex.xy -= ffrac.xy * g_fRealTexDims.zw; \ + \ + ftex.zw = ps2addr(ftex.xy + g_fRealTexDims.zw); \ + ftex.xy = ps2addr(ftex.xy); \ + \ + PS2MEMCOORD4(ftex, off0, off1); \ + half4 c0 = texture(g_sMemory, off0.xy); \ + half4 c1 = texture(g_sMemory, off0.zw); \ + half4 c2 = texture(g_sMemory, off1.xy); \ + half4 c3 = texture(g_sMemory, off1.zw); \ + return mix( mix(c0, c1, vec4(ffrac.x)), mix(c2, c3, ffrac.x), vec4(ffrac.y) ); \ +} + +decl_BilinearFilter(_32, ps2addr) +decl_BilinearFilter(_tex32, ps2addr) +decl_BilinearFilter(_clut32, ps2addr) +decl_BilinearFilter(_tex32to16, ps2addr) +decl_BilinearFilter(_tex16to8h, ps2addr) +decl_BilinearFilter(_tex16to32h, ps2addr) + +//TODO! For mip maps, only apply when LOD >= 0 +// lcm == 0, LOD = log(1/Q)*L + K, lcm == 1, LOD = K + +// bilinear +#define decl_ps2shade_1(bit) \ +half4 ps2shade1##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} + +// nearest, mip nearest +#define decl_ps2shade_2(bit) \ +half4 ps2shade2##bit(TEX_DECL tex) \ +{ \ + return tex2DPS##bit( ps2addr(TEX_XY)); \ +} + +// nearest, mip linear +#define decl_ps2shade_3(bit) \ +half4 ps2shade3##bit(TEX_DECL tex) \ +{ \ + return tex2DPS##bit(ps2addr(TEX_XY)); \ +} + +// linear, mip nearest +#define decl_ps2shade_4(bit) \ +half4 ps2shade4##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} + +// linear, mip linear +#define decl_ps2shade_5(bit) \ +half4 ps2shade5##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} + +decl_ps2shade(0) +decl_ps2shade(1) +decl_ps2shade(2) +decl_ps2shade(3) +decl_ps2shade(4) +decl_ps2shade(5) + + +half4 ps2CalcShade(half4 texcol, half4 color) +{ +#ifdef TEST_AEM + if( dot(texcol.xyzw, g_fTestBlack.xyzw) <= g_fc0.z ) + texcol.w = g_fc0.x; + else +#endif + texcol.w = texcol.w * fTexAlpha.y + fTexAlpha.x; + + texcol = texcol * (fTexAlpha2.zzzw * color + fTexAlpha2.xxxy) + fTexAlpha.zzzw * color.wwww; + + return texcol; +} + +// final ops on the color +#ifdef EXACT_COLOR + +half4 ps2FinalColor(half4 col) +{ + // g_fOneColor has to scale by 255 + half4 temp = col * g_fOneColor.xxxy + g_fOneColor.zzzw; + temp.w = floor(temp.w)*g_fExactColor.w; + return temp; +} + +#else +half4 ps2FinalColor(half4 col) +{ + return col * g_fOneColor.xxxy + g_fOneColor.zzzw; +} +#endif + +#ifdef FRAGMENT_SHADER // This is code only for FRAGMENTS (pixel shader) + +void RegularPS() { + // whenever outputting depth, make sure to mult by 255/256 and 1 + gl_FragData[0] = ps2FinalColor(gl_Color); + DOZWRITE(gl_FragData[1] = gl_TexCoord[0];) +} + +#ifdef WRITE_DEPTH + +#define DECL_TEXPS(num, bit) \ +void Texture##num##bit##PS() \ +{ \ + gl_FragData[0] = ps2FinalColor(ps2CalcShade(ps2shade##num##bit(gl_TexCoord[0]), gl_Color)); \ + gl_FragData[1] = gl_TexCoord[1]; \ +} + +#else + +#define DECL_TEXPS(num, bit) \ +void Texture##num##bit##PS() \ +{ \ + gl_FragData[0] = ps2FinalColor(ps2CalcShade(ps2shade##num##bit(gl_TexCoord[0]), gl_Color)); \ +} + +#endif + + +#define DECL_TEXPS_(num) \ +DECL_TEXPS(num, _32) \ +DECL_TEXPS(num, _tex32) \ +DECL_TEXPS(num, _clut32) \ +DECL_TEXPS(num, _tex32to16) \ +DECL_TEXPS(num, _tex16to8h) + +DECL_TEXPS_(0) +DECL_TEXPS_(1) +DECL_TEXPS_(2) +DECL_TEXPS_(3) +DECL_TEXPS_(4) +DECL_TEXPS_(5) + +void RegularFogPS() { + half4 c; + c.xyz = mix(g_fFogColor.xyz, gl_Color.xyz, vec3(gl_TexCoord[0].x)); + c.w = gl_Color.w; + gl_FragData[0] = ps2FinalColor(c); + DOZWRITE(gl_FragData[1] = gl_TexCoord[1];) +} + +#ifdef WRITE_DEPTH + +#define DECL_TEXFOGPS(num, bit) \ +void TextureFog##num##bit##PS() \ +{ \ + half4 c = ps2CalcShade(ps2shade##num##bit(gl_TexCoord[0]), gl_Color); \ + c.xyz = mix(g_fFogColor.xyz, c.xyz, vec3(gl_TexCoord[1].x)); \ + gl_FragData[0] = ps2FinalColor(c); \ + gl_FragData[1] = gl_TexCoord[2]; \ +} + +#else + +#define DECL_TEXFOGPS(num, bit) \ +void TextureFog##num##bit##PS() \ +{ \ + half4 c = ps2CalcShade(ps2shade##num##bit(gl_TexCoord[0]), gl_Color); \ + c.xyz = mix(g_fFogColor.xyz, c.xyz, vec3(gl_TexCoord[1].x)); \ + gl_FragData[0] = ps2FinalColor(c); \ +} + +#endif + +#define DECL_TEXFOGPS_(num) \ +DECL_TEXFOGPS(num, _32) \ +DECL_TEXFOGPS(num, _tex32) \ +DECL_TEXFOGPS(num, _clut32) \ +DECL_TEXFOGPS(num, _tex32to16) \ +DECL_TEXFOGPS(num, _tex16to8h) + +DECL_TEXFOGPS_(0) +DECL_TEXFOGPS_(1) +DECL_TEXFOGPS_(2) +DECL_TEXFOGPS_(3) +DECL_TEXFOGPS_(4) +DECL_TEXFOGPS_(5) + +//------------------------------------------------------- +// Techniques not related to the main primitive commands +half4 BilinearBitBlt(float2 tex0) +{ + float4 ftex; + float2 ffrac; + + ffrac.xy = fract(tex0*g_fRealTexDims.xy); + ftex.xy = tex0 - ffrac.xy * g_fRealTexDims.zw; + ftex.zw = ftex.xy + g_fRealTexDims.zw; + + float4 off0, off1; + ps2memcoord4_fast(ftex, off0, off1); + half4 c0 = texture(g_sMemory, off0.xy); + half4 c1 = texture(g_sMemory, off0.zw); + half4 c2 = texture(g_sMemory, off1.xy); + half4 c3 = texture(g_sMemory, off1.zw); + + return mix( mix(c0, c1, vec4(ffrac.x)), mix(c2, c3, vec4(ffrac.x)), vec4(ffrac.y) ); +} + +void BitBltPS() { + gl_FragData[0] = texture(g_sMemory, ps2memcoord(gl_TexCoord[0].xy).xy)*g_fOneColor.xxxy; +} + +// used when AA +void BitBltAAPS() { + gl_FragData[0] = BilinearBitBlt(gl_TexCoord[0].xy) * g_fOneColor.xxxy; +} + +void BitBltDepthPS() { + vec4 data; + data = texture(g_sMemory, ps2memcoord(gl_TexCoord[0].xy)); + gl_FragData[0] = data + g_fZBias.y; + gl_FragDepth = (log(g_fc0.y + dot(data, g_fBitBltZ)) * g_fOneColor.w) * g_fZMin.y + dot(data, g_fBitBltZ) * g_fZMin.x ; +} + +void BitBltDepthMRTPS() { + vec4 data; + data = texture(g_sMemory, ps2memcoord(gl_TexCoord[0].xy)); + gl_FragData[0] = data + g_fZBias.y; + gl_FragData[1].x = g_fc0.x; + gl_FragDepth = (log(g_fc0.y + dot(data, g_fBitBltZ)) * g_fOneColor.w) * g_fZMin.y + dot(data, g_fBitBltZ) * g_fZMin.x ; +} + +// static const float BlurKernel[9] = { +// 0.027601, +// 0.066213, +// 0.123701, +// 0.179952, +// 0.205065, +// 0.179952, +// 0.123701, +// 0.066213, +// 0.027601 +// }; + +half4 BilinearFloat16(float2 tex0) +{ + return texture(g_sSrcFinal, tex0.xy); +} + +void CRTCTargInterPS() { + float finter = texture(g_sInterlace, gl_TexCoord[1].yy).x * g_fOneColor.z + g_fOneColor.w + g_fc0.w; + float4 c = BilinearFloat16(gl_TexCoord[0].xy); + c.w = ( g_fc0.w*c.w * g_fOneColor.x + g_fOneColor.y ) * finter; + gl_FragData[0] = c; +} + +void CRTCTargPS() { + float4 c = BilinearFloat16(gl_TexCoord[0].xy); + c.w = g_fc0.w * c.w * g_fOneColor.x + g_fOneColor.y; + gl_FragData[0] = c; +} + +void CRTCInterPS() { + float finter = texture(g_sInterlace, gl_TexCoord[1].yy).x * g_fOneColor.z + g_fOneColor.w + g_fc0.w; + float2 filtcoord = trunc(gl_TexCoord[0].xy) * g_fInvTexDims.xy + g_fInvTexDims.zw; + half4 c = BilinearBitBlt(filtcoord); + c.w = (c.w * g_fOneColor.x + g_fOneColor.y)*finter; + gl_FragData[0] = c; +} + +// simpler +void CRTCInterPS_Nearest() { + float finter = texture(g_sInterlace, gl_TexCoord[1].yy).x * g_fOneColor.z + g_fOneColor.w + g_fc0.w; + half4 c = texture(g_sMemory, ps2memcoord(gl_TexCoord[0].xy).xy); + c.w = (c.w * g_fOneColor.x + g_fOneColor.y)*finter; + gl_FragData[0] = c; +} + +void CRTCPS() { + float2 filtcoord = gl_TexCoord[0].xy * g_fInvTexDims.xy+g_fInvTexDims.zw; + half4 c = BilinearBitBlt(filtcoord); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + gl_FragData[0] = c; +} + +// simpler +void CRTCPS_Nearest() { + half4 c = texture(g_sMemory, ps2memcoord(gl_TexCoord[0].xy).xy); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + gl_FragData[0] = c; +} + +void CRTC24InterPS() { + float finter = texture(g_sInterlace, gl_TexCoord[1].yy).x * g_fOneColor.z + g_fOneColor.w + g_fc0.w; + float2 filtcoord = trunc(gl_TexCoord[0].xy) * g_fInvTexDims.xy + g_fInvTexDims.zw; + + half4 c = texture(g_sMemory, ps2memcoord(filtcoord).xy); + c.w = (c.w * g_fOneColor.x + g_fOneColor.y)*finter; + gl_FragData[0] = c; +} + +void CRTC24PS() { + float2 filtcoord = trunc(gl_TexCoord[0].xy) * g_fInvTexDims.xy + g_fInvTexDims.zw; + half4 c = texture(g_sMemory, ps2memcoord(filtcoord).xy); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + gl_FragData[0] = c; +} + +void ZeroPS() { + gl_FragData[0] = g_fOneColor; +} + +void BaseTexturePS() { + gl_FragData[0] = texture(g_sSrcFinal, gl_TexCoord[0].xy) * g_fOneColor; +} + +void Convert16to32PS() { + float4 final; + float2 ffrac = mod ( gl_TexCoord[0].xy + g_fTexDims.zw, g_fTexOffset.xy); + float2 tex0 = g_fTexDims.xy * gl_TexCoord[0].xy - ffrac * g_fc0.yw; + + if (ffrac.x > g_fTexOffset.x*g_fc0.w) + tex0.x += g_fTexOffset.x*g_fc0.w; + if (tex0.x >= g_fc0.y) + tex0 += g_fTexOffset.zw; + + float4 lower = texture(g_sSrcFinal, tex0); + float4 upper = texture(g_sSrcFinal, tex0 + g_fPageOffset.xy); + + final.zy = texture(g_sConv32to16, lower.zyx).xy + lower.ww*g_fPageOffset.zw; + final.xw = texture(g_sConv32to16, upper.zyx).xy + upper.ww*g_fPageOffset.zw; + + gl_FragData[0]= final; +} + +// use when texture is not tiled and converting from 32bit to 16bit +// don't convert on the block level, only on the column level +// so every other 8 pixels, use the upper bits instead of lower +void Convert32to16PS() { + bool upper = false; + float2 ffrac = mod(gl_TexCoord[0].xy + g_fTexDims.zw, g_fTexOffset.xy); + float2 tex0 = g_fc0.ww * (gl_TexCoord[0].xy + ffrac); + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + upper = true; + } + if( ffrac.y >= g_fTexOffset.w ) { + tex0.y -= g_fTexOffset.w; + tex0.x += g_fc0.w; + } + + half4 color = texture(g_sSrcFinal, tex0*g_fTexDims.xy)*g_fc0.yyyw; + float2 uv = upper ? color.xw : color.zy; + gl_FragData[0] = texture(g_sConv16to32, uv*g_fPageOffset.xy+g_fPageOffset.zw)*g_fTexDims.xxxy; +} +#endif //FRAGMENT_SHADER + +#ifdef VERTEX_SHADER + +float4 OutPosition(float4 vertex) { + float4 Position; + Position.xy = gl_Vertex.xy * g_fPosXY.xy + g_fPosXY.zw; + Position.z = (log(g_fc0.y + dot(g_fZ, gl_SecondaryColor.zyxw)) * g_fZNorm.x + g_fZNorm.y) * g_fZMin.y + dot(g_fZ, gl_SecondaryColor.zyxw) * g_fZMin.x ; + Position.w = g_fc0.y; + return Position; +} + +// just smooth shadering +void RegularVS() { + gl_Position = OutPosition(gl_Vertex); + gl_FrontColor = gl_Color; + DOZWRITE(gl_TexCoord[0] = gl_SecondaryColor * g_fZBias.x + g_fZBias.y; gl_TexCoord[0].w = g_fc0.y;) +} + +// diffuse texture mapping +void TextureVS() { + gl_Position = OutPosition(gl_Vertex); + gl_FrontColor = gl_Color; +#ifdef PERSPECTIVE_CORRECT_TEX + gl_TexCoord[0].xyz = gl_MultiTexCoord0.xyz; +#else + gl_TexCoord[0].xy = gl_MultiTexCoord0.xy/gl_MultiTexCoord0.z; +#endif + DOZWRITE(gl_TexCoord[1] = gl_SecondaryColor * g_fZBias.x + g_fZBias.y; gl_TexCoord[1].w = g_fc0.y;) +} + +void RegularFogVS() { + float4 position = OutPosition(gl_Vertex); + gl_Position = position; + gl_FrontColor = gl_Color; + gl_TexCoord[0].x = position.z * g_fBilinear.w; + DOZWRITE(gl_TexCoord[1] = gl_SecondaryColor * g_fZBias.x + g_fZBias.y; gl_TexCoord[1].w = g_fc0.y;) +} + +void TextureFogVS() { + gl_Position = OutPosition(gl_Vertex); + gl_FrontColor = gl_Color; +#ifdef PERSPECTIVE_CORRECT_TEX + gl_TexCoord[0].xyz = gl_MultiTexCoord0.xyz; +#else + gl_TexCoord[0].xy = gl_MultiTexCoord0.xy / gl_MultiTexCoord0.z; +#endif + gl_TexCoord[1].x = gl_Vertex.z * g_fBilinear.w; + DOZWRITE(gl_TexCoord[2] = gl_SecondaryColor * g_fZBias.x + g_fZBias.y; gl_TexCoord[2].w = g_fc0.y;) +} + +void BitBltVS() { + vec4 position; + position.xy = gl_Vertex.xy * g_fBitBltPos.xy + g_fBitBltPos.zw; + position.zw = g_fc0.xy; + gl_Position = position; + + gl_TexCoord[0].xy = gl_MultiTexCoord0.xy * g_fBitBltTex.xy + g_fBitBltTex.zw; + gl_TexCoord[1].xy = position.xy * g_fBitBltTrans.xy + g_fBitBltTrans.zw; +} + +#endif