mirror of https://github.com/PCSX2/pcsx2.git
228 lines
5.1 KiB
C++
228 lines
5.1 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "GPURenderer.h"
|
|
#include "GPUDrawScanline.h"
|
|
|
|
template <class Device>
|
|
class GPURendererSW : public GPURenderer<Device, GSVertexSW>
|
|
{
|
|
protected:
|
|
GSRasterizerList m_rl;
|
|
Texture m_texture;
|
|
|
|
void ResetDevice()
|
|
{
|
|
m_texture = Texture();
|
|
}
|
|
|
|
bool GetOutput(Texture& t)
|
|
{
|
|
CRect r = m_env.GetDisplayRect();
|
|
|
|
r.left <<= m_scale.cx;
|
|
r.top <<= m_scale.cy;
|
|
r.right <<= m_scale.cx;
|
|
r.bottom <<= m_scale.cy;
|
|
|
|
// TODO
|
|
static DWORD* buff = (DWORD*)_aligned_malloc(m_mem.GetWidth() * m_mem.GetHeight() * sizeof(DWORD), 16);
|
|
|
|
m_mem.ReadFrame32(r, buff, !!m_env.STATUS.ISRGB24);
|
|
|
|
r.OffsetRect(-r.TopLeft());
|
|
|
|
if(m_texture.GetWidth() != r.Width() || m_texture.GetHeight() != r.Height())
|
|
{
|
|
m_texture = Texture();
|
|
}
|
|
|
|
if(!m_texture && !m_dev.CreateTexture(m_texture, r.Width(), r.Height()))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_texture.Update(r, buff, m_mem.GetWidth() * sizeof(DWORD));
|
|
|
|
t = m_texture;
|
|
|
|
return true;
|
|
}
|
|
|
|
void VertexKick()
|
|
{
|
|
GSVertexSW& v = m_vl.AddTail();
|
|
|
|
// TODO: x/y + off.x/y should wrap around at +/-1024
|
|
|
|
int x = (int)(m_v.XY.X + m_env.DROFF.X) << m_scale.cx;
|
|
int y = (int)(m_v.XY.Y + m_env.DROFF.Y) << m_scale.cy;
|
|
|
|
int s = m_v.UV.X;
|
|
int t = m_v.UV.Y;
|
|
|
|
GSVector4 pt(x, y, s, t);
|
|
|
|
v.p = pt.xyxy(GSVector4::zero());
|
|
v.t = (pt.zwzw(GSVector4::zero()) + GSVector4(0.125f)) * 256.0f;
|
|
v.c = GSVector4((DWORD)m_v.RGB.ai32) * 128.0f;
|
|
|
|
__super::VertexKick();
|
|
}
|
|
|
|
void DrawingKickTriangle(GSVertexSW* v, int& count)
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void DrawingKickLine(GSVertexSW* v, int& count)
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void DrawingKickSprite(GSVertexSW* v, int& count)
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
GSVector4i GetScissor()
|
|
{
|
|
GSVector4i v;
|
|
|
|
v.x = (int)m_env.DRAREATL.X << m_scale.cx;
|
|
v.y = (int)m_env.DRAREATL.Y << m_scale.cy;
|
|
v.z = min((int)(m_env.DRAREABR.X + 1) << m_scale.cx, m_mem.GetWidth());
|
|
v.w = min((int)(m_env.DRAREABR.Y + 1) << m_scale.cy, m_mem.GetHeight());
|
|
|
|
return v;
|
|
}
|
|
|
|
void Draw()
|
|
{
|
|
const GPUDrawingEnvironment& env = m_env;
|
|
|
|
//
|
|
|
|
GPUScanlineParam p;
|
|
|
|
p.sel.key = 0;
|
|
p.sel.iip = env.PRIM.IIP;
|
|
p.sel.me = env.STATUS.ME;
|
|
|
|
if(env.PRIM.ABE)
|
|
{
|
|
p.sel.abe = env.PRIM.ABE;
|
|
p.sel.abr = env.STATUS.ABR;
|
|
}
|
|
|
|
p.sel.tge = env.PRIM.TGE;
|
|
|
|
if(env.PRIM.TME)
|
|
{
|
|
p.sel.tme = env.PRIM.TME;
|
|
p.sel.tlu = env.STATUS.TP < 2;
|
|
p.sel.twin = (env.TWIN.ai32 & 0xfffff) != 0;
|
|
p.sel.ltf = m_filter == 1 && env.PRIM.TYPE == GPU_POLYGON || m_filter == 2 ? 1 : 0;
|
|
|
|
const void* t = m_mem.GetTexture(env.STATUS.TP, env.STATUS.TX, env.STATUS.TY);
|
|
|
|
if(!t) {ASSERT(0); return;}
|
|
|
|
p.tex = t;
|
|
p.clut = m_mem.GetCLUT(env.STATUS.TP, env.CLUT.X, env.CLUT.Y);
|
|
}
|
|
|
|
p.sel.dtd = m_dither ? env.STATUS.DTD : 0;
|
|
p.sel.md = env.STATUS.MD;
|
|
p.sel.sprite = env.PRIM.TYPE == GPU_SPRITE;
|
|
|
|
//
|
|
|
|
GSRasterizerData data;
|
|
|
|
data.scissor = GetScissor();
|
|
data.vertices = m_vertices;
|
|
data.count = m_count;
|
|
data.param = &p;
|
|
|
|
switch(env.PRIM.TYPE)
|
|
{
|
|
case GPU_POLYGON: data.primclass = GS_TRIANGLE_CLASS; break;
|
|
case GPU_LINE: data.primclass = GS_LINE_CLASS; break;
|
|
case GPU_SPRITE: data.primclass = GS_SPRITE_CLASS; break;
|
|
default: __assume(0);
|
|
}
|
|
|
|
m_rl.Draw(&data);
|
|
|
|
GSRasterizerStats stats;
|
|
|
|
m_rl.GetStats(stats);
|
|
|
|
m_perfmon.Put(GSPerfMon::Draw, 1);
|
|
m_perfmon.Put(GSPerfMon::Prim, stats.prims);
|
|
m_perfmon.Put(GSPerfMon::Fillrate, stats.pixels);
|
|
|
|
// TODO
|
|
|
|
{
|
|
GSVector4 tl(+1e10f);
|
|
GSVector4 br(-1e10f);
|
|
|
|
for(int i = 0, j = m_count; i < j; i++)
|
|
{
|
|
GSVector4 p = m_vertices[i].p;
|
|
|
|
tl = tl.minv(p);
|
|
br = br.maxv(p);
|
|
}
|
|
|
|
GSVector4i scissor = data.scissor;
|
|
|
|
CRect r;
|
|
|
|
r.left = max(scissor.x, min(scissor.z, (int)tl.x)) >> m_scale.cx;
|
|
r.top = max(scissor.y, min(scissor.w, (int)tl.y)) >> m_scale.cy;
|
|
r.right = max(scissor.x, min(scissor.z, (int)br.x)) >> m_scale.cx;
|
|
r.bottom = max(scissor.y, min(scissor.w, (int)br.y)) >> m_scale.cy;
|
|
|
|
Invalidate(r);
|
|
}
|
|
}
|
|
|
|
public:
|
|
GPURendererSW(const GPURendererSettings& rs, int threads)
|
|
: GPURenderer(rs)
|
|
{
|
|
m_rl.Create<GPUDrawScanline>(this, threads);
|
|
|
|
m_fpDrawingKickHandlers[GPU_POLYGON] = (DrawingKickHandler)&GPURendererSW::DrawingKickTriangle;
|
|
m_fpDrawingKickHandlers[GPU_LINE] = (DrawingKickHandler)&GPURendererSW::DrawingKickLine;
|
|
m_fpDrawingKickHandlers[GPU_SPRITE] = (DrawingKickHandler)&GPURendererSW::DrawingKickSprite;
|
|
}
|
|
|
|
virtual ~GPURendererSW()
|
|
{
|
|
}
|
|
};
|