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

297 lines
6.8 KiB
C++

/*
* 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;
}
}
}
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();
}
}
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());
GSVector4 off = GSVector4(-1.0f, 1.0f);
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();
}