diff --git a/plugins/GSdx/GSDevice11.h b/plugins/GSdx/GSDevice11.h index 5f959f4f3a..cf40cf1609 100644 --- a/plugins/GSdx/GSDevice11.h +++ b/plugins/GSdx/GSDevice11.h @@ -145,7 +145,7 @@ public: // TODO hash_map m_vs; CComPtr m_vs_cb; hash_map > m_gs; - hash_map > m_ps; + hash_map > m_ps; CComPtr m_ps_cb; hash_map > m_ps_ss; CComPtr m_palette_ss; diff --git a/plugins/GSdx/GSDevice9.h b/plugins/GSdx/GSDevice9.h index b77f8710e1..3814b4f9ea 100644 --- a/plugins/GSdx/GSDevice9.h +++ b/plugins/GSdx/GSDevice9.h @@ -173,7 +173,7 @@ public: // TODO // Shaders... hash_map m_vs; - hash_map > m_ps; + hash_map > m_ps; hash_map m_ps_ss; hash_map m_om_dss; hash_map m_om_bs; diff --git a/plugins/GSdx/GSDeviceDX.h b/plugins/GSdx/GSDeviceDX.h index 36bb0ae13f..e9469c8090 100644 --- a/plugins/GSdx/GSDeviceDX.h +++ b/plugins/GSdx/GSDeviceDX.h @@ -34,13 +34,13 @@ public: { GSVector4 VertexScale; GSVector4 VertexOffset; - GSVector4 TextureScale; + GSVector4 Texture_Scale_Offset; struct VSConstantBuffer() { VertexScale = GSVector4::zero(); VertexOffset = GSVector4::zero(); - TextureScale = GSVector4::zero(); + Texture_Scale_Offset = GSVector4::zero(); } __forceinline bool Update(const VSConstantBuffer* cb) @@ -48,15 +48,12 @@ public: GSVector4i* a = (GSVector4i*)this; GSVector4i* b = (GSVector4i*)cb; - GSVector4i b0 = b[0]; - GSVector4i b1 = b[1]; - GSVector4i b2 = b[2]; - - if(!((a[0] == b0) & (a[1] == b1) & (a[2] == b2)).alltrue()) + if(!((a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3])).alltrue()) { - a[0] = b0; - a[1] = b1; - a[2] = b2; + a[0] = b[0]; + a[1] = b[1]; + a[2] = b[2]; + a[3] = b[3]; return true; } @@ -112,21 +109,14 @@ public: GSVector4i* a = (GSVector4i*)this; GSVector4i* b = (GSVector4i*)cb; - GSVector4i b0 = b[0]; - GSVector4i b1 = b[1]; - GSVector4i b2 = b[2]; - GSVector4i b3 = b[3]; - GSVector4i b4 = b[4]; - GSVector4i b5 = b[5]; - - if(!((a[0] == b0) /*& (a[1] == b1)*/ & (a[2] == b2) & (a[3] == b3) & (a[4] == b4) & (a[5] == b5)).alltrue()) // if WH matches HalfTexel does too + if(!((a[0] == b[0]) /*& (a[1] == b1)*/ & (a[2] == b[2]) & (a[3] == b[3]) & (a[4] == b[4]) & (a[5] == b[5])).alltrue()) // if WH matches HalfTexel does too { - a[0] = b0; - a[1] = b1; - a[2] = b2; - a[3] = b3; - a[4] = b4; - a[5] = b5; + a[0] = b[0]; + a[1] = b[1]; + a[2] = b[2]; + a[3] = b[3]; + a[4] = b[4]; + a[5] = b[5]; return true; } @@ -162,7 +152,7 @@ public: uint32 fst:1; uint32 wms:2; uint32 wmt:2; - uint32 fmt:3; + uint32 fmt:4; uint32 aem:1; uint32 tfx:3; uint32 tcc:1; @@ -180,12 +170,14 @@ public: uint32 point_sampler:1; uint32 shuffle:1; uint32 read_ba:1; + + uint32 _free:32; }; - uint32 key; + uint64 key; }; - operator uint32() {return key & 0xfffffff;} + operator uint64() {return key;} PSSelector() : key(0) {} }; diff --git a/plugins/GSdx/GSRendererCS.cpp b/plugins/GSdx/GSRendererCS.cpp index 072edab8e7..d0dd4678f8 100644 --- a/plugins/GSdx/GSRendererCS.cpp +++ b/plugins/GSdx/GSRendererCS.cpp @@ -597,7 +597,7 @@ void GSRendererCS::Draw() CComPtr ps[2] = {m_ps0, NULL}; - hash_map >::const_iterator i = m_ps1.find(ps_sel); + hash_map >::const_iterator i = m_ps1.find(ps_sel); if(i != m_ps1.end()) { diff --git a/plugins/GSdx/GSRendererCS.h b/plugins/GSdx/GSRendererCS.h index 01f9071b18..39108b5f48 100644 --- a/plugins/GSdx/GSRendererCS.h +++ b/plugins/GSdx/GSRendererCS.h @@ -111,7 +111,7 @@ class GSRendererCS : public GSRenderer CComPtr m_vs_cb; hash_map > m_gs; CComPtr m_ps0; - hash_map > m_ps1; + hash_map > m_ps1; CComPtr m_ps_cb; void Write(GSOffset* off, const GSVector4i& r); diff --git a/plugins/GSdx/GSRendererDX.cpp b/plugins/GSdx/GSRendererDX.cpp index 65e2fc9138..567d60af90 100644 --- a/plugins/GSdx/GSRendererDX.cpp +++ b/plugins/GSdx/GSRendererDX.cpp @@ -34,10 +34,12 @@ GSRendererDX::GSRendererDX(GSTextureCache* tc, const GSVector2& pixelcenter) UserHacks_AlphaHack = theApp.GetConfigB("UserHacks_AlphaHack"); UserHacks_AlphaStencil = theApp.GetConfigB("UserHacks_AlphaStencil"); UserHacks_TCOffset = theApp.GetConfigI("UserHacks_TCOffset"); + UserHacks_HPO = theApp.GetConfigI("UserHacks_HalfPixelOffset"); } else { UserHacks_AlphaHack = false; UserHacks_AlphaStencil = false; UserHacks_TCOffset = 0; + UserHacks_HPO = 0; } UserHacks_TCO_x = (UserHacks_TCOffset & 0xFFFF) / -1000.0f; @@ -58,39 +60,39 @@ void GSRendererDX::EmulateAtst(const int pass, const GSTextureCache::Source* tex switch (atst) { case ATST_LESS: if (tex && tex->m_spritehack_t) { - ps_sel.atst = 0; + m_ps_sel.atst = 0; } else { ps_cb.FogColor_AREF.a = (float)m_context->TEST.AREF - 0.1f; - ps_sel.atst = 1; + m_ps_sel.atst = 1; } break; case ATST_LEQUAL: ps_cb.FogColor_AREF.a = (float)m_context->TEST.AREF - 0.1f + 1.0f; - ps_sel.atst = 1; + m_ps_sel.atst = 1; break; case ATST_GEQUAL: // Maybe a -1 trick multiplication factor could be used to merge with ATST_LEQUAL case ps_cb.FogColor_AREF.a = (float)m_context->TEST.AREF - 0.1f; - ps_sel.atst = 2; + m_ps_sel.atst = 2; break; case ATST_GREATER: // Maybe a -1 trick multiplication factor could be used to merge with ATST_LESS case ps_cb.FogColor_AREF.a = (float)m_context->TEST.AREF - 0.1f + 1.0f; - ps_sel.atst = 2; + m_ps_sel.atst = 2; break; case ATST_EQUAL: ps_cb.FogColor_AREF.a = (float)m_context->TEST.AREF; - ps_sel.atst = 3; + m_ps_sel.atst = 3; break; case ATST_NOTEQUAL: ps_cb.FogColor_AREF.a = (float)m_context->TEST.AREF; - ps_sel.atst = 4; + m_ps_sel.atst = 4; break; case ATST_NEVER: case ATST_ALWAYS: default: - ps_sel.atst = 0; + m_ps_sel.atst = 0; break; } } @@ -145,6 +147,141 @@ void GSRendererDX::EmulateZbuffer() } } +void GSRendererDX::EmulateTextureSampler(const GSTextureCache::Source* tex) +{ + const GSLocalMemory::psm_t &psm = GSLocalMemory::m_psm[m_context->TEX0.PSM]; + const GSLocalMemory::psm_t &cpsm = psm.pal > 0 ? GSLocalMemory::m_psm[m_context->TEX0.CPSM] : psm; + + const uint8 wms = m_context->CLAMP.WMS; + const uint8 wmt = m_context->CLAMP.WMT; + bool complex_wms_wmt = !!((wms | wmt) & 2); + + bool bilinear = m_vt.IsLinear(); + bool shader_emulated_sampler = tex->m_palette || cpsm.fmt != 0 || complex_wms_wmt; + + // 1 and 0 are equivalent + m_ps_sel.wms = (wms & 2) ? wms : 0; + m_ps_sel.wmt = (wmt & 2) ? wmt : 0; + + int w = tex->m_texture->GetWidth(); + int h = tex->m_texture->GetHeight(); + + int tw = (int)(1 << m_context->TEX0.TW); + int th = (int)(1 << m_context->TEX0.TH); + + GSVector4 WH(tw, th, w, h); + + // Performance note: + // 1/ Don't set 0 as it is the default value + // 2/ Only keep aem when it is useful (avoid useless shader permutation) + if (m_ps_sel.shuffle) { + // Force a 32 bits access (normally shuffle is done on 16 bits) + // m_ps_sel.tex_fmt = 0; // removed as an optimization + m_ps_sel.aem = m_env.TEXA.AEM; + ASSERT(tex->m_target); + + // Shuffle is a 16 bits format, so aem is always required + GSVector4 ta(m_env.TEXA & GSVector4i::x000000ff()); + ps_cb.MinF_TA = (GSVector4(ps_cb.MskFix) + 0.5f).xyxy(ta) / WH.xyxy(GSVector4(255, 255)); + + bilinear &= m_vt.IsLinear(); + + GSVector4 half_offset = RealignTargetTextureCoordinate(tex); + vs_cb.Texture_Scale_Offset.z = half_offset.x; + vs_cb.Texture_Scale_Offset.w = half_offset.y; + + } else if (tex->m_target) { + // Use an old target. AEM and index aren't resolved it must be done + // on the GPU + + // Select the 32/24/16 bits color (AEM) + m_ps_sel.fmt = cpsm.fmt; + m_ps_sel.aem = m_env.TEXA.AEM; + + // Don't upload AEM if format is 32 bits + if (cpsm.fmt) { + GSVector4 ta(m_env.TEXA & GSVector4i::x000000ff()); + ps_cb.MinF_TA = (GSVector4(ps_cb.MskFix) + 0.5f).xyxy(ta) / WH.xyxy(GSVector4(255, 255)); + } + + // Select the index format + if (tex->m_palette) { + // FIXME Potentially improve fmt field in GSLocalMemory + if (m_context->TEX0.PSM == PSM_PSMT4HL) + m_ps_sel.fmt |= 1 << 2; + else if (m_context->TEX0.PSM == PSM_PSMT4HH) + m_ps_sel.fmt |= 2 << 2; + else + m_ps_sel.fmt |= 3 << 2; + + // Alpha channel of the RT is reinterpreted as an index. Star + // Ocean 3 uses it to emulate a stencil buffer. It is a very + // bad idea to force bilinear filtering on it. + bilinear &= m_vt.IsLinear(); + } + + GSVector4 half_offset = RealignTargetTextureCoordinate(tex); + vs_cb.Texture_Scale_Offset.z = half_offset.x; + vs_cb.Texture_Scale_Offset.w = half_offset.y; + } + else if (tex->m_palette) { + // Use a standard 8 bits texture. AEM is already done on the CLUT + // Therefore you only need to set the index + // m_ps_sel.aem = 0; // removed as an optimization + + // Note 4 bits indexes are converted to 8 bits + m_ps_sel.fmt = 3 << 2; + + } + else { + // Standard texture. Both index and AEM expansion were already done by the CPU. + // m_ps_sel.tex_fmt = 0; // removed as an optimization + // m_ps_sel.aem = 0; // removed as an optimization + } + + + if (m_context->TEX0.TFX == TFX_MODULATE && m_vt.m_eq.rgba == 0xFFFF && m_vt.m_min.c.eq(GSVector4i(128))) { + // Micro optimization that reduces GPU load (removes 5 instructions on the FS program) + m_ps_sel.tfx = TFX_DECAL; + } + else { + m_ps_sel.tfx = m_context->TEX0.TFX; + } + + m_ps_sel.tcc = m_context->TEX0.TCC; + + m_ps_sel.ltf = bilinear && shader_emulated_sampler; + + m_ps_sel.rt = tex->m_target; + m_ps_sel.spritehack = tex->m_spritehack_t; + m_ps_sel.point_sampler = !(bilinear && !shader_emulated_sampler); + + if (PRIM->FST) + { + GSVector4 TextureScale = GSVector4(0.0625f) / WH.xyxy(); + vs_cb.Texture_Scale_Offset.x = TextureScale.x; + vs_cb.Texture_Scale_Offset.y = TextureScale.y; + //Maybe better? + //vs_cb.TextureScale = GSVector4(1.0f / 16) * GSVector4(tex->m_texture->GetScale()).xyxy() / WH.zwzw(); + m_ps_sel.fst = 1; + } + + ps_cb.WH = WH; + ps_cb.HalfTexel = GSVector4(-0.5f, 0.5f).xxyy() / WH.zwzw(); + if (complex_wms_wmt) { + ps_cb.MskFix = GSVector4i(m_context->CLAMP.MINU, m_context->CLAMP.MINV, m_context->CLAMP.MAXU, m_context->CLAMP.MAXV); + ps_cb.MinMax = GSVector4(ps_cb.MskFix) / WH.xyxy(); + } + + // TC Offset Hack + m_ps_sel.tcoffsethack = !!UserHacks_TCOffset; + ps_cb.TC_OffsetHack = GSVector4(UserHacks_TCO_x, UserHacks_TCO_y).xyxy() / WH.xyxy(); + + m_ps_ssel.tau = (m_context->CLAMP.WMS + 3) >> 1; + m_ps_ssel.tav = (m_context->CLAMP.WMT + 3) >> 1; + m_ps_ssel.ltf = bilinear && !shader_emulated_sampler; +} + void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex) { const GSVector2i& rtsize = ds ? ds->GetSize() : rt->GetSize(); @@ -155,6 +292,10 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc bool ate_first_pass = m_context->TEST.DoFirstPass(); bool ate_second_pass = m_context->TEST.DoSecondPass(); + m_gs_sel.key = 0; + + vs_cb.Texture_Scale_Offset = GSVector4(0.0f); + GSTexture* rtcopy = NULL; ASSERT(m_dev != NULL); @@ -257,8 +398,6 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc vs_sel.logz = dev->HasDepth32() ? 0 : m_logz ? 1 : 0; vs_sel.rtcopy = !!rtcopy; - GSDeviceDX::VSConstantBuffer vs_cb; - float sx = 2.0f * rtscale.x / (rtsize.x << 4); float sy = 2.0f * rtscale.y / (rtsize.y << 4); float ox = (float)(int)m_context->XYOFFSET.OFX; @@ -272,7 +411,7 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc //The resulting shifted output aligns better with common blending / corona / blurring effects, //but introduces a few bad pixels on the edges. - if(rt && rt->LikelyOffset) + if(rt && rt->LikelyOffset && UserHacks_HPO == 1) { // DX9 has pixelcenter set to 0.0, so give it some value here @@ -294,14 +433,14 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc // ps - ps_sel.key = 0; - ps_ssel.key = 0; + m_ps_sel.key = 0; + m_ps_ssel.key = 0; // Gregory: code is not yet ready so let's only enable it when // CRC is below the FULL level if (m_texture_shuffle && (m_crc_hack_level < CRCHackLevel::Full)) { - ps_sel.shuffle = 1; - ps_sel.fmt = 0; + m_ps_sel.shuffle = 1; + m_ps_sel.fmt = 0; const GIFRegXYOFFSET& o = m_context->XYOFFSET; GSVertex* v = &m_vertex.buff[0]; @@ -312,9 +451,9 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc bool write_ba = (pos > 112 && pos < 136); // Read texture is 8 to 16 pixels (same as above) int tex_pos = v[0].U & 0xFF; - ps_sel.read_ba = (tex_pos > 112 && tex_pos < 144); + m_ps_sel.read_ba = (tex_pos > 112 && tex_pos < 144); - GL_INS("Color shuffle %s => %s", ps_sel.read_ba ? "BA" : "RG", write_ba ? "BA" : "RG"); + GL_INS("Color shuffle %s => %s", m_ps_sel.read_ba ? "BA" : "RG", write_ba ? "BA" : "RG"); // Convert the vertex info to a 32 bits color format equivalent for (size_t i = 0; i < count; i += 2) { @@ -323,7 +462,7 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc else v[i + 1].XYZ.X += 128u; - if (ps_sel.read_ba) + if (m_ps_sel.read_ba) v[i].U -= 128u; else v[i + 1].U += 128u; @@ -390,24 +529,24 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc } else { - ps_sel.date = 1 + m_context->TEST.DATM; + m_ps_sel.date = 1 + m_context->TEST.DATM; } } if(m_env.COLCLAMP.CLAMP == 0 && /* hack */ !tex && PRIM->PRIM != GS_POINTLIST) { - ps_sel.colclip = 1; + m_ps_sel.colclip = 1; } - ps_sel.clr1 = om_bsel.IsCLR1(); - ps_sel.fba = m_context->FBA.FBA; - ps_sel.aout = m_context->FRAME.PSM == PSM_PSMCT16 || m_context->FRAME.PSM == PSM_PSMCT16S || (m_context->FRAME.FBMSK & 0xff000000) == 0x7f000000 ? 1 : 0; - ps_sel.aout &= !ps_sel.shuffle; - if(UserHacks_AlphaHack) ps_sel.aout = 1; + m_ps_sel.clr1 = om_bsel.IsCLR1(); + m_ps_sel.fba = m_context->FBA.FBA; + m_ps_sel.aout = m_context->FRAME.PSM == PSM_PSMCT16 || m_context->FRAME.PSM == PSM_PSMCT16S || (m_context->FRAME.FBMSK & 0xff000000) == 0x7f000000 ? 1 : 0; + m_ps_sel.aout &= !m_ps_sel.shuffle; + if(UserHacks_AlphaHack) m_ps_sel.aout = 1; if(PRIM->FGE) { - ps_sel.fog = 1; + m_ps_sel.fog = 1; ps_cb.FogColor_AREF = GSVector4::rgba32(m_env.FOGCOL.u32[0]) / 255; } @@ -457,12 +596,12 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc if (!m_context->FBA.FBA) { if (m_context->TEST.DATM == 0) - ps_sel.atst = 2; // >= + m_ps_sel.atst = 2; // >= else { if (tex && tex->m_spritehack_t) - ps_sel.atst = 0; // < + m_ps_sel.atst = 0; // < else - ps_sel.atst = 1; // < + m_ps_sel.atst = 1; // < } ps_cb.FogColor_AREF.a = (float)0x80; } @@ -472,67 +611,11 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc if(tex) { - const GSLocalMemory::psm_t &psm = GSLocalMemory::m_psm[m_context->TEX0.PSM]; - const GSLocalMemory::psm_t &cpsm = psm.pal > 0 ? GSLocalMemory::m_psm[m_context->TEX0.CPSM] : psm; - // The texture cache will handle various format conversion internally for non-target texture - // After the conversion the texture will be RGBA8 (aka 32 bits) hence the 0 below - int gpu_tex_fmt = (tex->m_target) ? cpsm.fmt : 0; - - bool bilinear = m_vt.IsLinear(); - bool simple_sample = !tex->m_palette && gpu_tex_fmt == 0 && m_context->CLAMP.WMS < 2 && m_context->CLAMP.WMT < 2; - - ps_sel.wms = m_context->CLAMP.WMS; - ps_sel.wmt = m_context->CLAMP.WMT; - if (ps_sel.shuffle) { - ps_sel.fmt = 0; - } else { - ps_sel.fmt = tex->m_palette ? gpu_tex_fmt | 4 : gpu_tex_fmt; - } - ps_sel.aem = m_env.TEXA.AEM; - ps_sel.tfx = m_context->TEX0.TFX; - ps_sel.tcc = m_context->TEX0.TCC; - ps_sel.ltf = bilinear && !simple_sample; - ps_sel.rt = tex->m_target; - ps_sel.spritehack = tex->m_spritehack_t; - ps_sel.point_sampler = !(bilinear && simple_sample); - - int w = tex->m_texture->GetWidth(); - int h = tex->m_texture->GetHeight(); - - int tw = (int)(1 << m_context->TEX0.TW); - int th = (int)(1 << m_context->TEX0.TH); - - GSVector4 WH(tw, th, w, h); - - if(PRIM->FST) - { - vs_cb.TextureScale = GSVector4(1.0f / 16) / WH.xyxy(); - //Maybe better? - //vs_cb.TextureScale = GSVector4(1.0f / 16) * GSVector4(tex->m_texture->GetScale()).xyxy() / WH.zwzw(); - ps_sel.fst = 1; - } - - ps_cb.WH = WH; - ps_cb.HalfTexel = GSVector4(-0.5f, 0.5f).xxyy() / WH.zwzw(); - ps_cb.MskFix = GSVector4i(m_context->CLAMP.MINU, m_context->CLAMP.MINV, m_context->CLAMP.MAXU, m_context->CLAMP.MAXV); - - // TC Offset Hack - ps_sel.tcoffsethack = !!UserHacks_TCOffset; - ps_cb.TC_OffsetHack = GSVector4(UserHacks_TCO_x, UserHacks_TCO_y).xyxy() / WH.xyxy(); - - GSVector4 clamp(ps_cb.MskFix); - GSVector4 ta(m_env.TEXA & GSVector4i::x000000ff()); - - ps_cb.MinMax = clamp / WH.xyxy(); - ps_cb.MinF_TA = (clamp + 0.5f).xyxy(ta) / WH.xyxy(GSVector4(255, 255)); - - ps_ssel.tau = (m_context->CLAMP.WMS + 3) >> 1; - ps_ssel.tav = (m_context->CLAMP.WMT + 3) >> 1; - ps_ssel.ltf = bilinear && simple_sample; + EmulateTextureSampler(tex); } else { - ps_sel.tfx = 4; + m_ps_sel.tfx = 4; } // rs @@ -551,7 +634,7 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc dev->SetupOM(om_dssel, om_bsel, afix); dev->SetupVS(vs_sel, &vs_cb); dev->SetupGS(gs_sel); - dev->SetupPS(ps_sel, &ps_cb, ps_ssel); + dev->SetupPS(m_ps_sel, &ps_cb, m_ps_ssel); // draw @@ -562,13 +645,13 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc if (m_env.COLCLAMP.CLAMP == 0 && /* hack */ !tex && PRIM->PRIM != GS_POINTLIST) { GSDeviceDX::OMBlendSelector om_bselneg(om_bsel); - GSDeviceDX::PSSelector ps_selneg(ps_sel); + GSDeviceDX::PSSelector ps_selneg(m_ps_sel); om_bselneg.negative = 1; ps_selneg.colclip = 2; dev->SetupOM(om_dssel, om_bselneg, afix); - dev->SetupPS(ps_selneg, &ps_cb, ps_ssel); + dev->SetupPS(ps_selneg, &ps_cb, m_ps_ssel); dev->DrawIndexedPrimitive(); dev->SetupOM(om_dssel, om_bsel, afix); @@ -590,7 +673,7 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc EmulateAtst(2, tex); } - dev->SetupPS(ps_sel, &ps_cb, ps_ssel); + dev->SetupPS(m_ps_sel, &ps_cb, m_ps_ssel); bool z = om_dssel.zwe; bool r = om_bsel.wr; @@ -633,13 +716,13 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc if (m_env.COLCLAMP.CLAMP == 0 && /* hack */ !tex && PRIM->PRIM != GS_POINTLIST) { GSDeviceDX::OMBlendSelector om_bselneg(om_bsel); - GSDeviceDX::PSSelector ps_selneg(ps_sel); + GSDeviceDX::PSSelector ps_selneg(m_ps_sel); om_bselneg.negative = 1; ps_selneg.colclip = 2; dev->SetupOM(om_dssel, om_bselneg, afix); - dev->SetupPS(ps_selneg, &ps_cb, ps_ssel); + dev->SetupPS(ps_selneg, &ps_cb, m_ps_ssel); dev->DrawIndexedPrimitive(); } diff --git a/plugins/GSdx/GSRendererDX.h b/plugins/GSdx/GSRendererDX.h index da5cd821f2..da8cd7e3df 100644 --- a/plugins/GSdx/GSRendererDX.h +++ b/plugins/GSdx/GSRendererDX.h @@ -36,12 +36,14 @@ class GSRendererDX : public GSRendererHW protected: void EmulateAtst(const int pass, const GSTextureCache::Source* tex); void EmulateZbuffer(); + void EmulateTextureSampler(const GSTextureCache::Source* tex); virtual void DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex); virtual void SetupIA() = 0; virtual void UpdateFBA(GSTexture* rt) {} unsigned int UserHacks_TCOffset; float UserHacks_TCO_x, UserHacks_TCO_y; + int UserHacks_HPO; bool DATE; @@ -53,9 +55,11 @@ protected: GSDeviceDX::OMDepthStencilSelector om_dssel; GSDeviceDX::OMBlendSelector om_bsel; - GSDeviceDX::PSSelector ps_sel; - GSDeviceDX::PSSamplerSelector ps_ssel; + GSDeviceDX::PSSelector m_ps_sel; + GSDeviceDX::PSSamplerSelector m_ps_ssel; + GSDeviceDX::PSConstantBuffer ps_cb; + GSDeviceDX::VSConstantBuffer vs_cb; public: GSRendererDX(GSTextureCache* tc, const GSVector2& pixelcenter = GSVector2(0)); diff --git a/plugins/GSdx/GSRendererHW.cpp b/plugins/GSdx/GSRendererHW.cpp index 10d621e928..8b8c980925 100644 --- a/plugins/GSdx/GSRendererHW.cpp +++ b/plugins/GSdx/GSRendererHW.cpp @@ -40,10 +40,12 @@ GSRendererHW::GSRendererHW(GSTextureCache* tc) m_userhacks_align_sprite_X = theApp.GetConfigB("UserHacks_align_sprite_X"); m_userhacks_round_sprite_offset = theApp.GetConfigI("UserHacks_round_sprite_offset"); m_userhacks_disable_gs_mem_clear = theApp.GetConfigB("UserHacks_DisableGsMemClear"); + m_userHacks_HPO = theApp.GetConfigI("UserHacks_HalfPixelOffset"); } else { m_userhacks_align_sprite_X = false; m_userhacks_round_sprite_offset = 0; m_userhacks_disable_gs_mem_clear = false; + m_userHacks_HPO = 0; } if (!m_upscale_multiplier) { //Custom Resolution @@ -265,6 +267,65 @@ GSTexture* GSRendererHW::GetFeedbackOutput() return t; } +GSVector4 GSRendererHW::RealignTargetTextureCoordinate(const GSTextureCache::Source* tex) +{ + if (m_userHacks_HPO <= 1 || GetUpscaleMultiplier() == 1) return GSVector4(0.0f); + + GSVertex* v = &m_vertex.buff[0]; + const GSVector2& scale = tex->m_texture->GetScale(); + bool linear = m_vt.IsRealLinear(); + int t_position = v[0].U; + GSVector4 half_offset(0.0f); + + // FIXME Let's start with something wrong same mess on X and Y + // FIXME Maybe it will be enough to check linear + + if (PRIM->FST) { + + if (m_userHacks_HPO == 3) { + if (!linear && t_position == 8) { + half_offset.x = 8; + half_offset.y = 8; + } else if (linear && t_position == 16) { + half_offset.x = 16; + half_offset.y = 16; + } else if (m_vt.m_min.p.x == -0.5f) { + half_offset.x = 8; + half_offset.y = 8; + } + } else { + if (!linear && t_position == 8) { + half_offset.x = 8 - 8 / scale.x; + half_offset.y = 8 - 8 / scale.y; + } else if (linear && t_position == 16) { + half_offset.x = 16 - 16 / scale.x; + half_offset.y = 16 - 16 / scale.y; + } else if (m_vt.m_min.p.x == -0.5f) { + half_offset.x = 8; + half_offset.y = 8; + } + } + + GL_INS("offset detected %f,%f t_pos %d (linear %d, scale %f)", + half_offset.x, half_offset.y, t_position, linear, scale.x); + + } else if (m_vt.m_eq.q) { + float tw = (float)(1 << m_context->TEX0.TW); + float th = (float)(1 << m_context->TEX0.TH); + float q = v[0].RGBAQ.Q; + + // Tales of Abyss + half_offset.x = 0.5f * q / tw; + half_offset.y = 0.5f * q / th; + + GL_INS("ST offset detected %f,%f (linear %d, scale %f)", + half_offset.x, half_offset.y, linear, scale.x); + + } + + return half_offset; +} + void GSRendererHW::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r) { // printf("[%d] InvalidateVideoMem %d,%d - %d,%d %05x (%d)\n", (int)m_perfmon.GetFrame(), r.left, r.top, r.right, r.bottom, (int)BITBLTBUF.DBP, (int)BITBLTBUF.DPSM); diff --git a/plugins/GSdx/GSRendererHW.h b/plugins/GSdx/GSRendererHW.h index 229d0c6da6..9f1d98c499 100644 --- a/plugins/GSdx/GSRendererHW.h +++ b/plugins/GSdx/GSRendererHW.h @@ -151,6 +151,7 @@ protected: virtual void DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex) = 0; int m_userhacks_round_sprite_offset; + int m_userHacks_HPO; bool m_channel_shuffle; @@ -165,6 +166,7 @@ public: int GetUpscaleMultiplier(); GSVector2i GetCustomResolution(); void SetScaling(); + GSVector4 RealignTargetTextureCoordinate(const GSTextureCache::Source* tex); void Reset(); void VSync(int field); diff --git a/plugins/GSdx/GSRendererOGL.cpp b/plugins/GSdx/GSRendererOGL.cpp index 0c5b4ea14e..fc74522812 100644 --- a/plugins/GSdx/GSRendererOGL.cpp +++ b/plugins/GSdx/GSRendererOGL.cpp @@ -753,65 +753,6 @@ void GSRendererOGL::EmulateBlending(bool DATE_GL42) } } -void GSRendererOGL::RealignTargetTextureCoordinate(const GSTextureCache::Source* tex) -{ - if (UserHacks_HPO <= 1 || GetUpscaleMultiplier() == 1) return; - - GSVertex* v = &m_vertex.buff[0]; - const GSVector2& scale = tex->m_texture->GetScale(); - bool linear = m_vt.IsRealLinear(); - int t_position = v[0].U; - GSVector4 half_offset(0.0f); - - // FIXME Let's start with something wrong same mess on X and Y - // FIXME Maybe it will be enough to check linear - - if (PRIM->FST) { - - if (UserHacks_HPO == 3) { - if (!linear && t_position == 8) { - half_offset.x = 8; - half_offset.y = 8; - } else if (linear && t_position == 16) { - half_offset.x = 16; - half_offset.y = 16; - } else if (m_vt.m_min.p.x == -0.5f) { - half_offset.x = 8; - half_offset.y = 8; - } - } else { - if (!linear && t_position == 8) { - half_offset.x = 8 - 8 / scale.x; - half_offset.y = 8 - 8 / scale.y; - } else if (linear && t_position == 16) { - half_offset.x = 16 - 16 / scale.x; - half_offset.y = 16 - 16 / scale.y; - } else if (m_vt.m_min.p.x == -0.5f) { - half_offset.x = 8; - half_offset.y = 8; - } - } - - GL_INS("offset detected %f,%f t_pos %d (linear %d, scale %f)", - half_offset.x, half_offset.y, t_position, linear, scale.x); - - } else if (m_vt.m_eq.q) { - float tw = (float)(1 << m_context->TEX0.TW); - float th = (float)(1 << m_context->TEX0.TH); - float q = v[0].RGBAQ.Q; - - // Tales of Abyss - half_offset.x = 0.5f * q / tw; - half_offset.y = 0.5f * q / th; - - GL_INS("ST offset detected %f,%f (linear %d, scale %f)", - half_offset.x, half_offset.y, linear, scale.x); - - } - - vs_cb.TextureOffset = GSVector4(half_offset); -} - void GSRendererOGL::EmulateTextureSampler(const GSTextureCache::Source* tex) { GSDeviceOGL* dev = (GSDeviceOGL*)m_dev; @@ -883,7 +824,7 @@ void GSRendererOGL::EmulateTextureSampler(const GSTextureCache::Source* tex) // The purpose of texture shuffle is to move color channel. Extra interpolation is likely a bad idea. bilinear &= m_vt.IsLinear(); - RealignTargetTextureCoordinate(tex); + vs_cb.TextureOffset = RealignTargetTextureCoordinate(tex); } else if (tex->m_target) { // Use an old target. AEM and index aren't resolved it must be done @@ -933,7 +874,7 @@ void GSRendererOGL::EmulateTextureSampler(const GSTextureCache::Source* tex) bilinear &= m_vt.IsLinear(); } - RealignTargetTextureCoordinate(tex); + vs_cb.TextureOffset = RealignTargetTextureCoordinate(tex); } else if (tex->m_palette) { // Use a standard 8 bits texture. AEM is already done on the CLUT diff --git a/plugins/GSdx/GSRendererOGL.h b/plugins/GSdx/GSRendererOGL.h index d92749ba08..29f3f55d6f 100644 --- a/plugins/GSdx/GSRendererOGL.h +++ b/plugins/GSdx/GSRendererOGL.h @@ -77,7 +77,6 @@ class GSRendererOGL final : public GSRendererHW inline void ResetStates(); inline void Lines2Sprites(); inline void SetupIA(const float& sx, const float& sy); - inline void RealignTargetTextureCoordinate(const GSTextureCache::Source* tex); inline void EmulateTextureShuffleAndFbmask(); inline void EmulateChannelShuffle(GSTexture** rt, const GSTextureCache::Source* tex); inline void EmulateBlending(bool DATE_GL42); diff --git a/plugins/GSdx/GSSettingsDlg.cpp b/plugins/GSdx/GSSettingsDlg.cpp index 1b100f5c8b..0bef306927 100644 --- a/plugins/GSdx/GSSettingsDlg.cpp +++ b/plugins/GSdx/GSSettingsDlg.cpp @@ -688,12 +688,8 @@ void GSHacksDlg::OnInit() CheckDlgButton(m_hWnd, IDC_AUTO_FLUSH, theApp.GetConfigB("UserHacks_AutoFlush")); CheckDlgButton(m_hWnd, IDC_UNSCALE_POINT_LINE, theApp.GetConfigB("UserHacks_unscale_point_line")); CheckDlgButton(m_hWnd, IDC_MEMORY_WRAPPING, theApp.GetConfigB("wrap_gs_mem")); - std::vector hpo_combobox = theApp.m_gs_offset_hack; - if (!ogl) - { - hpo_combobox.erase(hpo_combobox.begin() + 2, hpo_combobox.begin() + 4); - } - ComboBoxInit(IDC_OFFSETHACK, hpo_combobox,theApp.GetConfigI("UserHacks_HalfPixelOffset")); + + ComboBoxInit(IDC_OFFSETHACK, theApp.m_gs_offset_hack, theApp.GetConfigI("UserHacks_HalfPixelOffset")); ComboBoxInit(IDC_ROUND_SPRITE, theApp.m_gs_hack, theApp.GetConfigI("UserHacks_round_sprite_offset")); ComboBoxInit(IDC_SPRITEHACK, theApp.m_gs_hack, theApp.GetConfigI("UserHacks_SpriteHack")); @@ -720,6 +716,8 @@ void GSHacksDlg::OnInit() EnableWindow(GetDlgItem(m_hWnd, IDC_ROUND_SPRITE), !native); EnableWindow(GetDlgItem(m_hWnd, IDC_SPRITEHACK_TEXT), !native); EnableWindow(GetDlgItem(m_hWnd, IDC_ROUND_SPRITE_TEXT), !native); + EnableWindow(GetDlgItem(m_hWnd, IDC_OFFSETHACK_TEXT), !native); + EnableWindow(GetDlgItem(m_hWnd, IDC_OFFSETHACK), !native); AddTooltip(IDC_SKIPDRAWHACKEDIT); AddTooltip(IDC_SKIPDRAWHACK); diff --git a/plugins/GSdx/GSTextureFX11.cpp b/plugins/GSdx/GSTextureFX11.cpp index 00619a7848..4e83785dbb 100644 --- a/plugins/GSdx/GSTextureFX11.cpp +++ b/plugins/GSdx/GSTextureFX11.cpp @@ -178,11 +178,11 @@ void GSDevice11::SetupGS(GSSelector sel) void GSDevice11::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel) { - hash_map >::const_iterator i = m_ps.find(sel); + hash_map >::const_iterator i = m_ps.find(sel); if(i == m_ps.end()) { - string str[20]; + string str[21]; str[0] = format("%d", sel.fst); str[1] = format("%d", sel.wms); @@ -204,6 +204,7 @@ void GSDevice11::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSe str[17] = format("%d", sel.point_sampler); str[18] = format("%d", sel.shuffle); str[19] = format("%d", sel.read_ba); + str[20] = format("%d", sel.fmt >> 2); D3D_SHADER_MACRO macro[] = { @@ -227,6 +228,7 @@ void GSDevice11::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSe {"PS_POINT_SAMPLER", str[17].c_str()}, {"PS_SHUFFLE", str[18].c_str() }, {"PS_READ_BA", str[19].c_str() }, + {"PS_PAL_FMT", str[20].c_str() }, {NULL, NULL}, }; diff --git a/plugins/GSdx/GSTextureFX9.cpp b/plugins/GSdx/GSTextureFX9.cpp index e6d2f1efb4..3c07bcfa78 100644 --- a/plugins/GSdx/GSTextureFX9.cpp +++ b/plugins/GSdx/GSTextureFX9.cpp @@ -133,11 +133,11 @@ void GSDevice9::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSel } } - hash_map >::const_iterator i = m_ps.find(sel); + hash_map >::const_iterator i = m_ps.find(sel); if(i == m_ps.end()) { - string str[17]; + string str[18]; str[0] = format("%d", sel.fst); str[1] = format("%d", sel.wms); @@ -156,6 +156,7 @@ void GSDevice9::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSel str[14] = format("%d", sel.spritehack); str[15] = format("%d", sel.tcoffsethack); str[16] = format("%d", sel.point_sampler); + str[17] = format("%d", sel.fmt >> 2); D3D_SHADER_MACRO macro[] = { @@ -176,6 +177,7 @@ void GSDevice9::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSel {"PS_SPRITEHACK", str[14].c_str()}, {"PS_TCOFFSETHACK", str[15].c_str()}, {"PS_POINT_SAMPLER", str[16].c_str()}, + {"PS_PAL_FMT", str[17].c_str()}, {NULL, NULL}, }; diff --git a/plugins/GSdx/res/tfx.fx b/plugins/GSdx/res/tfx.fx index 0a3e73ac76..4fcc670dc6 100644 --- a/plugins/GSdx/res/tfx.fx +++ b/plugins/GSdx/res/tfx.fx @@ -2,7 +2,6 @@ #define FMT_32 0 #define FMT_24 1 #define FMT_16 2 -#define FMT_PAL 4 /* flag bit */ // And I say this as an ATI user. #define ATI_SUCKS 1 @@ -41,6 +40,7 @@ #define PS_POINT_SAMPLER 0 #define PS_SHUFFLE 0 #define PS_READ_BA 0 +#define PS_PAL_FMT 0 #endif struct VS_INPUT @@ -91,7 +91,7 @@ cbuffer cb0 { float4 VertexScale; float4 VertexOffset; - float2 TextureScale; + float4 Texture_Scale_Offset; }; cbuffer cb1 @@ -155,6 +155,7 @@ float4 sample_rt(float2 uv) #define PS_LTF 0 #define PS_COLCLIP 0 #define PS_DATE 0 +#define PS_PAL_FMT 0 #endif struct VS_INPUT @@ -194,7 +195,7 @@ float4 vs_params[3]; #define VertexScale vs_params[0] #define VertexOffset vs_params[1] -#define TextureScale vs_params[2].xy +#define Texture_Scale_Offset vs_params[2] float4 ps_params[7]; @@ -225,7 +226,9 @@ float4 sample_rt(float2 uv) #endif -float4 wrapuv(float4 uv) +#define PS_AEM_FMT (PS_FMT & 3) + +float4 clamp_wrap_uv(float4 uv) { if(PS_WMS == PS_WMT) { @@ -311,24 +314,6 @@ float4 wrapuv(float4 uv) return uv; } -float2 clampuv(float2 uv) -{ - if(PS_WMS == 2 && PS_WMT == 2) - { - uv = clamp(uv, MinF, MinMax.zw); - } - else if(PS_WMS == 2) - { - uv.x = clamp(uv.x, MinF.x, MinMax.z); - } - else if(PS_WMT == 2) - { - uv.y = clamp(uv.y, MinF.y, MinMax.w); - } - - return uv; -} - float4x4 sample_4c(float4 uv) { float4x4 c; @@ -381,16 +366,10 @@ float4 sample(float2 st, float q) float4x4 c; float2 dd; -/* - if(!PS_LTF && PS_FMT <= FMT_16 && PS_WMS < 2 && PS_WMT < 2) + if (PS_LTF == 0 && PS_AEM_FMT == FMT_32 && PS_PAL_FMT == 0 && PS_WMS < 2 && PS_WMT < 2) { c[0] = sample_c(st); } -*/ - if (!PS_LTF && PS_FMT <= FMT_16 && PS_WMS < 3 && PS_WMT < 3) - { - c[0] = sample_c(clampuv(st)); - } else { float4 uv; @@ -405,32 +384,29 @@ float4 sample(float2 st, float q) uv = st.xyxy; } - uv = wrapuv(uv); + uv = clamp_wrap_uv(uv); - if(PS_FMT & FMT_PAL) - { +#if PS_PAL_FMT != 0 c = sample_4p(sample_4a(uv)); - } - else - { +#else c = sample_4c(uv); - } +#endif } [unroll] for (uint i = 0; i < 4; i++) { - if((PS_FMT & ~FMT_PAL) == FMT_32) + if(PS_AEM_FMT == FMT_32) { #if SHADER_MODEL <= 0x300 if(PS_RT) c[i].a *= 128.0f / 255; #endif } - else if((PS_FMT & ~FMT_PAL) == FMT_24) + else if(PS_AEM_FMT == FMT_24) { c[i].a = !PS_AEM || any(c[i].rgb) ? TA.x : 0; } - else if((PS_FMT & ~FMT_PAL) == FMT_16) + else if(PS_AEM_FMT == FMT_16) { c[i].a = c[i].a >= 0.5 ? TA.y : !PS_AEM || any(c[i].rgb) ? TA.x : 0; } @@ -631,12 +607,14 @@ VS_OUTPUT vs_main(VS_INPUT input) { if(VS_FST) { - output.t.xy = input.uv * TextureScale; - output.t.w = 1.0f; + float2 uv = input.uv - Texture_Scale_Offset.zw; + + output.t.xy = uv * Texture_Scale_Offset.xy; + output.t.zw = uv; } else { - output.t.xy = input.st; + output.t.xy = input.st - Texture_Scale_Offset.zw; output.t.w = input.q; } } @@ -808,14 +786,16 @@ VS_OUTPUT vs_main(VS_INPUT input) if(VS_TME) { + float2 t = input.t - Texture_Scale_Offset.zw; if(VS_FST) { - output.t.xy = input.t * TextureScale; - output.t.w = 1.0f; + + output.t.xy = t * Texture_Scale_Offset.xy; + output.t.zw = t; } else { - output.t.xy = input.t; + output.t.xy = t; output.t.w = input.p.w; } }