pcsx2/plugins/GSdx/Renderers/DX9/GSRendererDX9.cpp

297 lines
6.8 KiB
C++
Raw Normal View History

/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* 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, 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 GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSRendererDX9.h"
#include "GSCrc.h"
#include "resource.h"
GSRendererDX9::GSRendererDX9()
: GSRendererDX(new GSTextureCache9(this))
{
}
bool GSRendererDX9::CreateDevice(GSDevice* dev)
{
if(!__super::CreateDevice(dev))
return false;
//
memset(&m_fba.dss, 0, sizeof(m_fba.dss));
m_fba.dss.StencilEnable = true;
m_fba.dss.StencilReadMask = 2;
m_fba.dss.StencilWriteMask = 2;
m_fba.dss.StencilFunc = D3DCMP_EQUAL;
m_fba.dss.StencilPassOp = D3DSTENCILOP_ZERO;
m_fba.dss.StencilFailOp = D3DSTENCILOP_ZERO;
m_fba.dss.StencilDepthFailOp = D3DSTENCILOP_ZERO;
m_fba.dss.StencilRef = 2;
memset(&m_fba.bs, 0, sizeof(m_fba.bs));
m_fba.bs.RenderTargetWriteMask = D3DCOLORWRITEENABLE_ALPHA;
//
return true;
}
void GSRendererDX9::EmulateChannelShuffle(GSTexture** rt, const GSTextureCache::Source* tex)
{
// Channel shuffle will never be supported on Direct3D9 through shaders so just
// use code that skips the bad draw calls.
if (m_channel_shuffle)
{
if (m_game.title == CRC::Tekken5)
{
if (m_context->FRAME.FBW == 1)
{
// Used in stages: Secret Garden, Acid Rain, Moonlit Wilderness
// 12 pages: 2 calls by channel, 3 channels, 1 blit
// Minus current draw call
m_skip = 12 * (3 + 3 + 1) - 1;
}
else
{
// Could skip model drawing if wrongly detected
m_channel_shuffle = false;
}
}
else if ((tex->m_texture->GetType() == GSTexture::DepthStencil) && !(tex->m_32_bits_fmt))
{
// So far 2 games hit this code path. Urban Chaos and Tales of Abyss.
throw GSDXRecoverableError();
}
else if (m_index.tail <= 64 && m_context->CLAMP.WMT == 3)
{
// Blood will tell. I think it is channel effect too but again
// implemented in a different way. I don't want to add more CRC stuff. So
// let's disable channel when the signature is different.
//
// Note: Tales Of Abyss and Tekken5 could hit this path too. Those games are
// handled above.
m_channel_shuffle = false;
}
else if (m_context->CLAMP.WMS == 3 && ((m_context->CLAMP.MAXU & 0x8) == 8))
{
// Read either blue or Alpha.
// MGS3/Kill Zone
throw GSDXRecoverableError();
}
else if (m_context->CLAMP.WMS == 3 && ((m_context->CLAMP.MINU & 0x8) == 0))
{
// Read either Red or Green.
// Terminator 3
throw GSDXRecoverableError();
}
else
{
m_channel_shuffle = false;
}
}
}
GSdx-D3D: Texture and channel shuffle improvements. Texture Shuffle changes: Always Enable Texture shuffle on D3D10/11. Previously Texture shuffle was enabled if CRC hack level was below Full, this was kinda not good since D3D also relies on CRC hacks on Full so you could either stick with texture shuffle or crc hacks. Texture shuffle is not supported on D3D9, however we can do a partial port where instead of vertical lines with the effect we get the effect on the entire screen. Better than nothing I suppose. Ported some of the code from OpenGL to D3D ( just a copy - paste job :) ), part of the code misses a dedicated shader but we can still use it to fix various issues on many games. List of affected games tested so far: The Godfather, Final Fight Streetwise, The Suffering Ties that Bind, Urban Chaos have their vertical lines issues fixed (highly possible for other games as well), MGS and Stolen see an improvement but they are still broken without crc hacks. Other games that suffered similar issues are probably affected as well. Channel Shuffle changes: Update Channel Shuffle detection. A lot of games should see an improvement, MGS, Urban Chaos, Stolen have their top left corner issues resolved. Other games should be affected as well that use similar logic. They still miss a shader so some effects are still broken/show glitches but it's a nice improvement for D3D users. Shared changes: Texture Shuffle and Channel shuffle have been moved to their own dedicated functions. Should make things a bit cleaner. Move part of the code for Texture Shuffle to GSRendererHW to be shared across all HW renderers, should aboid copy paste/duplicate code.
2018-03-18 09:08:36 +00:00
void GSRendererDX9::EmulateTextureShuffleAndFbmask()
{
if (m_texture_shuffle)
{
// Texture shuffle is not supported so make sure nothing is written on all channels.
m_om_bsel.wrgba = 0;
}
else
{
m_ps_sel.dfmt = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmt;
m_om_bsel.wrgba = ~GSVector4i::load((int)m_context->FRAME.FBMSK).eq8(GSVector4i::xffffffff()).mask();
GSdx-D3D: Texture and channel shuffle improvements. Texture Shuffle changes: Always Enable Texture shuffle on D3D10/11. Previously Texture shuffle was enabled if CRC hack level was below Full, this was kinda not good since D3D also relies on CRC hacks on Full so you could either stick with texture shuffle or crc hacks. Texture shuffle is not supported on D3D9, however we can do a partial port where instead of vertical lines with the effect we get the effect on the entire screen. Better than nothing I suppose. Ported some of the code from OpenGL to D3D ( just a copy - paste job :) ), part of the code misses a dedicated shader but we can still use it to fix various issues on many games. List of affected games tested so far: The Godfather, Final Fight Streetwise, The Suffering Ties that Bind, Urban Chaos have their vertical lines issues fixed (highly possible for other games as well), MGS and Stolen see an improvement but they are still broken without crc hacks. Other games that suffered similar issues are probably affected as well. Channel Shuffle changes: Update Channel Shuffle detection. A lot of games should see an improvement, MGS, Urban Chaos, Stolen have their top left corner issues resolved. Other games should be affected as well that use similar logic. They still miss a shader so some effects are still broken/show glitches but it's a nice improvement for D3D users. Shared changes: Texture Shuffle and Channel shuffle have been moved to their own dedicated functions. Should make things a bit cleaner. Move part of the code for Texture Shuffle to GSRendererHW to be shared across all HW renderers, should aboid copy paste/duplicate code.
2018-03-18 09:08:36 +00:00
}
}
void GSRendererDX9::SetupIA(const float& sx, const float& sy)
{
D3DPRIMITIVETYPE topology;
switch(m_vt.m_primclass)
{
case GS_POINT_CLASS:
topology = D3DPT_POINTLIST;
break;
case GS_LINE_CLASS:
topology = D3DPT_LINELIST;
if(PRIM->IIP == 0)
{
for(size_t i = 0, j = m_index.tail; i < j; i += 2)
{
uint32 tmp = m_index.buff[i + 0];
m_index.buff[i + 0] = m_index.buff[i + 1];
m_index.buff[i + 1] = tmp;
}
}
break;
case GS_TRIANGLE_CLASS:
topology = D3DPT_TRIANGLELIST;
if(PRIM->IIP == 0)
{
for(size_t i = 0, j = m_index.tail; i < j; i += 3)
{
uint32 tmp = m_index.buff[i + 0];
m_index.buff[i + 0] = m_index.buff[i + 2];
m_index.buff[i + 2] = tmp;
}
}
break;
case GS_SPRITE_CLASS:
topology = D3DPT_TRIANGLELIST;
// each sprite converted to quad needs twice the space
Lines2Sprites();
break;
default:
__assume(0);
}
GSDevice9* dev = (GSDevice9*)m_dev;
(*dev)->SetRenderState(D3DRS_SHADEMODE, PRIM->IIP ? D3DSHADE_GOURAUD : D3DSHADE_FLAT); // TODO
void* ptr = NULL;
if(dev->IAMapVertexBuffer(&ptr, sizeof(GSVertexHW9), m_vertex.next))
{
GSVertex* RESTRICT s = (GSVertex*)m_vertex.buff;
GSVertexHW9* RESTRICT d = (GSVertexHW9*)ptr;
for(uint32 i = 0; i < m_vertex.next; i++, s++, d++)
{
GSVector4 p = GSVector4(GSVector4i::load(s->XYZ.u32[0]).upl16());
if(PRIM->TME && !PRIM->FST)
{
p = p.xyxy(GSVector4((float)s->XYZ.Z, s->RGBAQ.Q));
}
else
{
p = p.xyxy(GSVector4::load((float)s->XYZ.Z));
}
GSVector4 t = GSVector4::zero();
if(PRIM->TME)
{
if(PRIM->FST)
{
if(UserHacks_WildHack && !isPackedUV_HackFlag)
{
t = GSVector4(GSVector4i::load(s->UV & 0x3FEF3FEF).upl16());
//printf("GSDX: %08X | D3D9(%d) %s\n", s->UV & 0x3FEF3FEF, m_vertex.next, i == 0 ? "*" : "");
}
else
{
t = GSVector4(GSVector4i::load(s->UV).upl16());
}
}
else
{
t = GSVector4::loadl(&s->ST);
}
}
t = t.xyxy(GSVector4::cast(GSVector4i(s->RGBAQ.u32[0], s->FOG)));
d->p = p;
d->t = t;
}
dev->IAUnmapVertexBuffer();
}
dev->IASetIndexBuffer(m_index.buff, m_index.tail);
dev->IASetPrimitiveTopology(topology);
}
void GSRendererDX9::UpdateFBA(GSTexture* rt)
{
if (!rt)
return;
GSDevice9* dev = (GSDevice9*)m_dev;
dev->BeginScene();
// om
dev->OMSetDepthStencilState(&m_fba.dss);
dev->OMSetBlendState(&m_fba.bs, 0);
// ia
GSVector4 s = GSVector4(rt->GetScale().x / rt->GetWidth(), rt->GetScale().y / rt->GetHeight());
2015-05-15 18:40:09 +00:00
GSVector4 off = GSVector4(-1.0f, 1.0f);
2015-05-15 18:40:09 +00:00
GSVector4 src = ((m_vt.m_min.p.xyxy(m_vt.m_max.p) + off.xxyy()) * s.xyxy()).sat(off.zzyy());
GSVector4 dst = src * 2.0f + off.xxxx();
GSVertexPT1 vertices[] =
{
{GSVector4(dst.x, -dst.y, 0.5f, 1.0f), GSVector2(0)},
{GSVector4(dst.z, -dst.y, 0.5f, 1.0f), GSVector2(0)},
{GSVector4(dst.x, -dst.w, 0.5f, 1.0f), GSVector2(0)},
{GSVector4(dst.z, -dst.w, 0.5f, 1.0f), GSVector2(0)},
};
dev->IASetVertexBuffer(vertices, sizeof(vertices[0]), countof(vertices));
dev->IASetInputLayout(dev->m_convert.il);
dev->IASetPrimitiveTopology(D3DPT_TRIANGLESTRIP);
// vs
dev->VSSetShader(dev->m_convert.vs, NULL, 0);
// ps
dev->PSSetShader(dev->m_convert.ps[4], NULL, 0);
//
dev->DrawPrimitive();
//
dev->EndScene();
}