2010-04-25 00:31:27 +00:00
|
|
|
/*
|
2009-02-09 21:15:56 +00:00
|
|
|
* 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.
|
2010-04-25 00:31:27 +00:00
|
|
|
*
|
2009-02-09 21:15:56 +00:00
|
|
|
* 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.
|
2010-04-25 00:31:27 +00:00
|
|
|
*
|
2009-02-09 21:15:56 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with GNU Make; see the file COPYING. If not, write to
|
2012-09-09 18:16:11 +00:00
|
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
|
2009-02-09 21:15:56 +00:00
|
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2009-02-20 10:59:10 +00:00
|
|
|
// TODO: JIT Draw* (flags: depth, texture, color (+iip), scissor)
|
2009-02-15 02:27:51 +00:00
|
|
|
|
2011-02-19 03:36:30 +00:00
|
|
|
#include "stdafx.h"
|
2009-02-09 21:15:56 +00:00
|
|
|
#include "GSRasterizer.h"
|
|
|
|
|
2016-07-10 15:44:56 +00:00
|
|
|
int GSRasterizerData::s_counter = 0;
|
2011-12-20 14:33:28 +00:00
|
|
|
|
2016-07-10 15:44:56 +00:00
|
|
|
static int compute_best_thread_height(int threads) {
|
|
|
|
// - for more threads screen segments should be smaller to better distribute the pixels
|
|
|
|
// - but not too small to keep the threading overhead low
|
|
|
|
// - ideal value between 3 and 5, or log2(64 / number of threads)
|
2011-02-17 18:22:47 +00:00
|
|
|
|
2016-07-10 15:44:56 +00:00
|
|
|
int th = theApp.GetConfigI("extrathreads_height");
|
|
|
|
|
|
|
|
if (th > 0 && th < 9)
|
|
|
|
return th;
|
|
|
|
else
|
|
|
|
return 4;
|
|
|
|
}
|
2012-02-08 16:57:14 +00:00
|
|
|
|
2011-12-22 01:48:16 +00:00
|
|
|
GSRasterizer::GSRasterizer(IDrawScanline* ds, int id, int threads, GSPerfMon* perfmon)
|
2013-06-28 17:32:37 +00:00
|
|
|
: m_perfmon(perfmon)
|
|
|
|
, m_ds(ds)
|
2011-12-18 08:13:20 +00:00
|
|
|
, m_id(id)
|
|
|
|
, m_threads(threads)
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2013-06-23 10:46:24 +00:00
|
|
|
memset(&m_pixels, 0, sizeof(m_pixels));
|
|
|
|
|
2016-07-10 15:44:56 +00:00
|
|
|
m_thread_height = compute_best_thread_height(threads);
|
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
m_edge.buff = (GSVertexSW*)vmalloc(sizeof(GSVertexSW) * 2048, false);
|
2011-03-08 01:48:15 +00:00
|
|
|
m_edge.count = 0;
|
2011-03-29 14:07:48 +00:00
|
|
|
|
2017-02-08 18:30:53 +00:00
|
|
|
int rows = (2048 >> m_thread_height) + 16;
|
|
|
|
m_scanline = (uint8*)_aligned_malloc(rows, 64);
|
2011-03-29 14:07:48 +00:00
|
|
|
|
2011-12-18 08:13:20 +00:00
|
|
|
int row = 0;
|
|
|
|
|
2017-02-08 18:30:53 +00:00
|
|
|
while(row < rows)
|
2011-12-18 08:13:20 +00:00
|
|
|
{
|
|
|
|
for(int i = 0; i < threads; i++, row++)
|
|
|
|
{
|
2012-01-18 11:47:31 +00:00
|
|
|
m_scanline[row] = i == id ? 1 : 0;
|
2011-12-18 08:13:20 +00:00
|
|
|
}
|
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GSRasterizer::~GSRasterizer()
|
|
|
|
{
|
2012-01-18 11:47:31 +00:00
|
|
|
_aligned_free(m_scanline);
|
2011-03-29 14:07:48 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
if(m_edge.buff != NULL) vmfree(m_edge.buff, sizeof(GSVertexSW) * 2048);
|
2011-03-08 01:48:15 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
delete m_ds;
|
|
|
|
}
|
|
|
|
|
2011-12-23 15:53:53 +00:00
|
|
|
bool GSRasterizer::IsOneOfMyScanlines(int top) const
|
2009-12-03 23:08:52 +00:00
|
|
|
{
|
2012-01-13 18:10:05 +00:00
|
|
|
ASSERT(top >= 0 && top < 2048);
|
|
|
|
|
2016-07-10 15:44:56 +00:00
|
|
|
return m_scanline[top >> m_thread_height] != 0;
|
2009-12-03 23:08:52 +00:00
|
|
|
}
|
|
|
|
|
2011-12-16 19:13:58 +00:00
|
|
|
bool GSRasterizer::IsOneOfMyScanlines(int top, int bottom) const
|
|
|
|
{
|
2012-01-13 18:10:05 +00:00
|
|
|
ASSERT(top >= 0 && top < 2048 && bottom >= 0 && bottom < 2048);
|
|
|
|
|
2016-07-10 15:44:56 +00:00
|
|
|
top = top >> m_thread_height;
|
|
|
|
bottom = (bottom + (1 << m_thread_height) - 1) >> m_thread_height;
|
2011-12-16 19:13:58 +00:00
|
|
|
|
2011-12-18 21:57:48 +00:00
|
|
|
while(top < bottom)
|
2011-12-16 19:13:58 +00:00
|
|
|
{
|
2012-01-18 11:47:31 +00:00
|
|
|
if(m_scanline[top++])
|
2011-12-18 21:57:48 +00:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2011-12-16 19:13:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-12-23 15:53:53 +00:00
|
|
|
int GSRasterizer::FindMyNextScanline(int top) const
|
|
|
|
{
|
2016-07-10 15:44:56 +00:00
|
|
|
int i = top >> m_thread_height;
|
2011-12-23 15:53:53 +00:00
|
|
|
|
2012-01-18 11:47:31 +00:00
|
|
|
if(m_scanline[i] == 0)
|
2011-12-23 15:53:53 +00:00
|
|
|
{
|
2012-01-18 11:47:31 +00:00
|
|
|
while(m_scanline[++i] == 0);
|
2011-12-23 15:53:53 +00:00
|
|
|
|
2016-07-10 15:44:56 +00:00
|
|
|
top = i << m_thread_height;
|
2011-12-23 15:53:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return top;
|
|
|
|
}
|
|
|
|
|
2015-03-21 14:09:58 +00:00
|
|
|
void GSRasterizer::Queue(const shared_ptr<GSRasterizerData>& data)
|
2011-12-16 19:13:58 +00:00
|
|
|
{
|
2012-01-08 17:10:00 +00:00
|
|
|
Draw(data.get());
|
2011-12-16 19:13:58 +00:00
|
|
|
}
|
|
|
|
|
2016-07-10 15:44:56 +00:00
|
|
|
int GSRasterizer::GetPixels(bool reset)
|
2012-01-08 17:10:00 +00:00
|
|
|
{
|
2013-06-23 10:46:24 +00:00
|
|
|
int pixels = m_pixels.sum;
|
2016-07-10 15:44:56 +00:00
|
|
|
|
2012-01-08 17:10:00 +00:00
|
|
|
if(reset)
|
|
|
|
{
|
2013-06-23 10:46:24 +00:00
|
|
|
m_pixels.sum = 0;
|
2012-01-08 17:10:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return pixels;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GSRasterizer::Draw(GSRasterizerData* data)
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2011-12-22 01:48:16 +00:00
|
|
|
GSPerfMonAutoTimer pmat(m_perfmon, GSPerfMon::WorkerDraw0 + m_id);
|
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
if(data->vertex != NULL && data->vertex_count == 0 || data->index != NULL && data->index_count == 0) return;
|
2011-12-23 15:53:53 +00:00
|
|
|
|
2013-06-23 10:46:24 +00:00
|
|
|
m_pixels.actual = 0;
|
|
|
|
m_pixels.total = 0;
|
|
|
|
|
2012-02-08 16:57:14 +00:00
|
|
|
data->start = __rdtsc();
|
|
|
|
|
2012-01-08 17:10:00 +00:00
|
|
|
m_ds->BeginDraw(data);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
const GSVertexSW* vertex = data->vertex;
|
|
|
|
const GSVertexSW* vertex_end = data->vertex + data->vertex_count;
|
2016-07-10 15:44:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
const uint32* index = data->index;
|
|
|
|
const uint32* index_end = data->index + data->index_count;
|
|
|
|
|
|
|
|
uint32 tmp_index[] = {0, 1, 2};
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-12-18 08:13:20 +00:00
|
|
|
bool scissor_test = !data->bbox.eq(data->bbox.rintersect(data->scissor));
|
|
|
|
|
2011-03-08 01:48:15 +00:00
|
|
|
m_scissor = data->scissor;
|
2011-12-31 15:41:07 +00:00
|
|
|
m_fscissor_x = GSVector4(data->scissor).xzxz();
|
|
|
|
m_fscissor_y = GSVector4(data->scissor).ywyw();
|
2011-03-08 01:48:15 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
switch(data->primclass)
|
|
|
|
{
|
|
|
|
case GS_POINT_CLASS:
|
2011-12-23 15:53:53 +00:00
|
|
|
|
|
|
|
if(scissor_test)
|
|
|
|
{
|
2012-01-05 02:40:24 +00:00
|
|
|
DrawPoint<true>(vertex, data->vertex_count, index, data->index_count);
|
2011-12-23 15:53:53 +00:00
|
|
|
}
|
2016-07-10 15:44:56 +00:00
|
|
|
else
|
2011-12-23 15:53:53 +00:00
|
|
|
{
|
2012-01-05 02:40:24 +00:00
|
|
|
DrawPoint<false>(vertex, data->vertex_count, index, data->index_count);
|
2011-12-23 15:53:53 +00:00
|
|
|
}
|
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
break;
|
2011-12-23 15:53:53 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
case GS_LINE_CLASS:
|
2016-07-10 15:44:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
if(index != NULL)
|
|
|
|
{
|
|
|
|
do {DrawLine(vertex, index); index += 2;}
|
|
|
|
while(index < index_end);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do {DrawLine(vertex, tmp_index); vertex += 2;}
|
|
|
|
while(vertex < vertex_end);
|
|
|
|
}
|
2011-12-23 15:53:53 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
break;
|
2011-12-23 15:53:53 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
case GS_TRIANGLE_CLASS:
|
2016-07-10 15:44:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
if(index != NULL)
|
|
|
|
{
|
|
|
|
do {DrawTriangle(vertex, index); index += 3;}
|
|
|
|
while(index < index_end);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do {DrawTriangle(vertex, tmp_index); vertex += 3;}
|
|
|
|
while(vertex < vertex_end);
|
|
|
|
}
|
2011-12-23 15:53:53 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
break;
|
2011-12-23 15:53:53 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
case GS_SPRITE_CLASS:
|
2016-07-10 15:44:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
if(index != NULL)
|
|
|
|
{
|
2012-01-13 18:10:05 +00:00
|
|
|
do {DrawSprite(vertex, index); index += 2;}
|
2012-01-05 02:40:24 +00:00
|
|
|
while(index < index_end);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-01-13 18:10:05 +00:00
|
|
|
do {DrawSprite(vertex, tmp_index); vertex += 2;}
|
2012-01-05 02:40:24 +00:00
|
|
|
while(vertex < vertex_end);
|
|
|
|
}
|
2011-12-23 15:53:53 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
break;
|
2011-12-23 15:53:53 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
default:
|
|
|
|
__assume(0);
|
|
|
|
}
|
|
|
|
|
2013-06-20 05:07:52 +00:00
|
|
|
#if _M_SSE >= 0x501
|
|
|
|
_mm256_zeroupper();
|
|
|
|
#endif
|
|
|
|
|
2013-06-23 10:46:24 +00:00
|
|
|
data->pixels = m_pixels.actual;
|
2012-02-08 16:57:14 +00:00
|
|
|
|
|
|
|
uint64 ticks = __rdtsc() - data->start;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2013-06-23 10:46:24 +00:00
|
|
|
m_pixels.sum += m_pixels.actual;
|
|
|
|
|
|
|
|
m_ds->EndDraw(data->frame, ticks, m_pixels.actual, m_pixels.total);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2011-12-19 01:20:55 +00:00
|
|
|
template<bool scissor_test>
|
2012-01-05 02:40:24 +00:00
|
|
|
void GSRasterizer::DrawPoint(const GSVertexSW* vertex, int vertex_count, const uint32* index, int index_count)
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2012-01-09 08:41:33 +00:00
|
|
|
if(index != NULL)
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2012-01-09 08:41:33 +00:00
|
|
|
for(int i = 0; i < index_count; i++, index++)
|
|
|
|
{
|
|
|
|
const GSVertexSW& v = vertex[*index];
|
|
|
|
|
|
|
|
GSVector4i p(v.p);
|
2012-01-05 02:40:24 +00:00
|
|
|
|
2012-01-09 08:41:33 +00:00
|
|
|
if(!scissor_test || m_scissor.left <= p.x && p.x < m_scissor.right && m_scissor.top <= p.y && p.y < m_scissor.bottom)
|
|
|
|
{
|
|
|
|
if(IsOneOfMyScanlines(p.y))
|
|
|
|
{
|
|
|
|
m_ds->SetupPrim(vertex, index, GSVertexSW::zero());
|
|
|
|
|
2013-06-23 10:46:24 +00:00
|
|
|
DrawScanline(1, p.x, p.y, v);
|
2012-01-09 08:41:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint32 tmp_index[1] = {0};
|
2011-03-27 03:12:12 +00:00
|
|
|
|
2012-01-09 08:41:33 +00:00
|
|
|
for(int i = 0; i < vertex_count; i++, vertex++)
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2012-01-09 08:41:33 +00:00
|
|
|
const GSVertexSW& v = vertex[0];
|
|
|
|
|
|
|
|
GSVector4i p(v.p);
|
|
|
|
|
|
|
|
if(!scissor_test || m_scissor.left <= p.x && p.x < m_scissor.right && m_scissor.top <= p.y && p.y < m_scissor.bottom)
|
2011-03-27 03:12:12 +00:00
|
|
|
{
|
2012-01-09 08:41:33 +00:00
|
|
|
if(IsOneOfMyScanlines(p.y))
|
|
|
|
{
|
|
|
|
m_ds->SetupPrim(vertex, tmp_index, GSVertexSW::zero());
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2013-06-23 10:46:24 +00:00
|
|
|
DrawScanline(1, p.x, p.y, v);
|
2012-01-09 08:41:33 +00:00
|
|
|
}
|
2011-03-27 03:12:12 +00:00
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
void GSRasterizer::DrawLine(const GSVertexSW* vertex, const uint32* index)
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2012-01-05 02:40:24 +00:00
|
|
|
const GSVertexSW& v0 = vertex[index[0]];
|
|
|
|
const GSVertexSW& v1 = vertex[index[1]];
|
2016-07-10 15:44:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
GSVertexSW dv = v1 - v0;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
GSVector4 dp = dv.p.abs();
|
2009-03-09 01:42:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
int i = (dp < dp.yxwz()).mask() & 1; // |dx| <= |dy|
|
|
|
|
|
2011-12-18 08:13:20 +00:00
|
|
|
if(m_ds->HasEdge())
|
2009-03-09 01:42:56 +00:00
|
|
|
{
|
2012-01-05 02:40:24 +00:00
|
|
|
DrawEdge(v0, v1, dv, i, 0);
|
|
|
|
DrawEdge(v0, v1, dv, i, 1);
|
2011-03-08 01:48:15 +00:00
|
|
|
|
2012-01-09 08:41:33 +00:00
|
|
|
Flush(vertex, index, GSVertexSW::zero(), true);
|
2009-03-09 01:42:56 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
GSVector4i dpi(dp);
|
|
|
|
|
|
|
|
if(dpi.y == 0)
|
|
|
|
{
|
|
|
|
if(dpi.x > 0)
|
|
|
|
{
|
|
|
|
// shortcut for horizontal lines
|
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
GSVector4 mask = (v0.p > v1.p).xxxx();
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-12-04 18:35:16 +00:00
|
|
|
GSVertexSW scan;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
scan.p = v0.p.blend32(v1.p, mask);
|
|
|
|
scan.t = v0.t.blend32(v1.t, mask);
|
|
|
|
scan.c = v0.c.blend32(v1.c, mask);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-12-04 18:35:16 +00:00
|
|
|
GSVector4i p(scan.p);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-12-04 18:35:16 +00:00
|
|
|
if(m_scissor.top <= p.y && p.y < m_scissor.bottom && IsOneOfMyScanlines(p.y))
|
|
|
|
{
|
2012-01-05 02:40:24 +00:00
|
|
|
GSVector4 lrf = scan.p.upl(v1.p.blend32(v0.p, mask)).ceil();
|
2011-12-31 15:41:07 +00:00
|
|
|
GSVector4 l = lrf.max(m_fscissor_x);
|
|
|
|
GSVector4 r = lrf.min(m_fscissor_x);
|
2011-12-04 18:35:16 +00:00
|
|
|
GSVector4i lr = GSVector4i(l.xxyy(r));
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-12-04 18:35:16 +00:00
|
|
|
int left = lr.extract32<0>();
|
|
|
|
int right = lr.extract32<2>();
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-12-04 18:35:16 +00:00
|
|
|
int pixels = right - left;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-12-04 18:35:16 +00:00
|
|
|
if(pixels > 0)
|
|
|
|
{
|
|
|
|
GSVertexSW dscan = dv / dv.p.xxxx();
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-12-04 18:35:16 +00:00
|
|
|
scan += dscan * (l - scan.p).xxxx();
|
2009-02-24 20:12:46 +00:00
|
|
|
|
2012-01-09 08:41:33 +00:00
|
|
|
m_ds->SetupPrim(vertex, index, dscan);
|
2011-12-04 18:35:16 +00:00
|
|
|
|
2013-06-23 10:46:24 +00:00
|
|
|
DrawScanline(pixels, left, p.y, scan);
|
2011-12-04 18:35:16 +00:00
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
int steps = dpi.v[i];
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
if(steps > 0)
|
|
|
|
{
|
2012-01-05 02:40:24 +00:00
|
|
|
GSVertexSW edge = v0;
|
2011-03-09 11:52:53 +00:00
|
|
|
GSVertexSW dedge = dv / GSVector4(dp.v[i]);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
GSVertexSW* RESTRICT e = m_edge.buff;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
GSVector4i p(edge.p);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
if(m_scissor.left <= p.x && p.x < m_scissor.right && m_scissor.top <= p.y && p.y < m_scissor.bottom)
|
|
|
|
{
|
|
|
|
if(IsOneOfMyScanlines(p.y))
|
|
|
|
{
|
2011-03-27 03:12:12 +00:00
|
|
|
AddScanline(e, 1, p.x, p.y, edge);
|
2011-03-09 11:52:53 +00:00
|
|
|
|
|
|
|
e++;
|
|
|
|
}
|
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
if(--steps == 0) break;
|
|
|
|
|
|
|
|
edge += dedge;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_edge.count = e - m_edge.buff;
|
|
|
|
|
2012-01-09 08:41:33 +00:00
|
|
|
Flush(vertex, index, GSVertexSW::zero());
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-29 06:45:35 +00:00
|
|
|
static const uint8 s_ysort[8][4] =
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2011-03-29 06:45:35 +00:00
|
|
|
{0, 1, 2, 0}, // y0 <= y1 <= y2
|
|
|
|
{1, 0, 2, 0}, // y1 < y0 <= y2
|
2009-02-09 21:15:56 +00:00
|
|
|
{0, 0, 0, 0},
|
2011-03-29 06:45:35 +00:00
|
|
|
{1, 2, 0, 0}, // y1 <= y2 < y0
|
|
|
|
{0, 2, 1, 0}, // y0 <= y2 < y1
|
2009-02-09 21:15:56 +00:00
|
|
|
{0, 0, 0, 0},
|
2011-03-29 06:45:35 +00:00
|
|
|
{2, 0, 1, 0}, // y2 < y0 <= y1
|
|
|
|
{2, 1, 0, 0}, // y2 < y1 < y0
|
2009-02-09 21:15:56 +00:00
|
|
|
};
|
|
|
|
|
2013-07-01 21:28:58 +00:00
|
|
|
#if _M_SSE >= 0x501
|
|
|
|
|
|
|
|
void GSRasterizer::DrawTriangle(const GSVertexSW* vertex, const uint32* index)
|
|
|
|
{
|
|
|
|
GSVertexSW2 dv[3];
|
|
|
|
GSVertexSW2 edge;
|
|
|
|
GSVertexSW2 dedge;
|
|
|
|
GSVertexSW2 dscan;
|
|
|
|
|
|
|
|
GSVector4 y0011 = vertex[index[0]].p.yyyy(vertex[index[1]].p);
|
|
|
|
GSVector4 y1221 = vertex[index[1]].p.yyyy(vertex[index[2]].p).xzzx();
|
|
|
|
|
|
|
|
int m1 = (y0011 > y1221).mask() & 7;
|
|
|
|
|
|
|
|
int i[3];
|
|
|
|
|
|
|
|
i[0] = index[s_ysort[m1][0]];
|
|
|
|
i[1] = index[s_ysort[m1][1]];
|
|
|
|
i[2] = index[s_ysort[m1][2]];
|
|
|
|
|
|
|
|
const GSVertexSW2* _v = (const GSVertexSW2*)vertex;
|
|
|
|
|
|
|
|
const GSVertexSW2& v0 = _v[i[0]];
|
|
|
|
const GSVertexSW2& v1 = _v[i[1]];
|
|
|
|
const GSVertexSW2& v2 = _v[i[2]];
|
|
|
|
|
|
|
|
y0011 = v0.p.yyyy(v1.p);
|
|
|
|
y1221 = v1.p.yyyy(v2.p).xzzx();
|
|
|
|
|
|
|
|
m1 = (y0011 == y1221).mask() & 7;
|
|
|
|
|
|
|
|
// if(i == 0) => y0 < y1 < y2
|
|
|
|
// if(i == 1) => y0 == y1 < y2
|
|
|
|
// if(i == 4) => y0 < y1 == y2
|
|
|
|
|
|
|
|
if(m1 == 7) return; // y0 == y1 == y2
|
|
|
|
|
|
|
|
GSVector4 tbf = y0011.xzxz(y1221).ceil();
|
|
|
|
GSVector4 tbmax = tbf.max(m_fscissor_y);
|
|
|
|
GSVector4 tbmin = tbf.min(m_fscissor_y);
|
|
|
|
GSVector4i tb = GSVector4i(tbmax.xzyw(tbmin)); // max(y0, t) max(y1, t) min(y1, b) min(y2, b)
|
|
|
|
|
|
|
|
dv[0] = v1 - v0;
|
|
|
|
dv[1] = v2 - v0;
|
|
|
|
dv[2] = v2 - v1;
|
|
|
|
|
|
|
|
GSVector4 cross = dv[0].p * dv[1].p.yxwz();
|
|
|
|
|
|
|
|
cross = (cross - cross.yxwz()).yyyy(); // select the second component, the negated cross product
|
|
|
|
|
|
|
|
// the longest horizontal span would be cross.x / dv[1].p.y, but we don't need its actual value
|
|
|
|
|
|
|
|
int m2 = cross.upl(cross == GSVector4::zero()).mask();
|
|
|
|
|
|
|
|
if(m2 & 2) return;
|
|
|
|
|
|
|
|
m2 &= 1;
|
|
|
|
|
|
|
|
GSVector4 dxy01 = dv[0].p.xyxy(dv[1].p);
|
|
|
|
|
|
|
|
GSVector4 dx = dxy01.xzxy(dv[2].p);
|
|
|
|
GSVector4 dy = dxy01.ywyx(dv[2].p);
|
|
|
|
|
|
|
|
GSVector4 ddx[3];
|
|
|
|
|
|
|
|
ddx[0] = dx / dy;
|
|
|
|
ddx[1] = ddx[0].yxzw();
|
|
|
|
ddx[2] = ddx[0].xzyw();
|
|
|
|
|
2017-02-27 18:40:05 +00:00
|
|
|
// Precision is important here. Don't use reciprocal, it will break Jak3/Xenosaga1
|
|
|
|
GSVector8 _dxy01c(dxy01 / cross);
|
2013-07-01 21:28:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
dscan = dv[1] * dxy01c.yyyy() - dv[0] * dxy01c.wwww();
|
|
|
|
dedge = dv[0] * dxy01c.zzzz() - dv[1] * dxy01c.xxxx();
|
|
|
|
*/
|
|
|
|
|
|
|
|
dscan.p = dv[1].p * _dxy01c.yyyy().extract<0>() - dv[0].p * _dxy01c.wwww().extract<0>();
|
|
|
|
dscan.tc = dv[1].tc * _dxy01c.yyyy() - dv[0].tc * _dxy01c.wwww();
|
|
|
|
|
|
|
|
dedge.p = dv[0].p * _dxy01c.zzzz().extract<0>() - dv[1].p * _dxy01c.xxxx().extract<0>();
|
|
|
|
dedge.tc = dv[0].tc * _dxy01c.zzzz() - dv[1].tc * _dxy01c.xxxx();
|
|
|
|
|
|
|
|
if(m1 & 1)
|
|
|
|
{
|
|
|
|
if(tb.y < tb.w)
|
|
|
|
{
|
|
|
|
edge = _v[i[1 - m2]];
|
|
|
|
|
|
|
|
edge.p = edge.p.insert32<0, 1>(vertex[i[m2]].p);
|
|
|
|
dedge.p = ddx[2 - (m2 << 1)].yzzw(dedge.p);
|
|
|
|
|
|
|
|
DrawTriangleSection(tb.x, tb.w, edge, dedge, dscan, vertex[i[1 - m2]].p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(tb.x < tb.z)
|
|
|
|
{
|
|
|
|
edge = v0;
|
|
|
|
|
|
|
|
edge.p = edge.p.xxzw();
|
|
|
|
dedge.p = ddx[m2].xyzw(dedge.p);
|
|
|
|
|
|
|
|
DrawTriangleSection(tb.x, tb.z, edge, dedge, dscan, v0.p);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(tb.y < tb.w)
|
|
|
|
{
|
|
|
|
edge = v1;
|
|
|
|
|
|
|
|
edge.p = (v0.p.xxxx() + ddx[m2] * dv[0].p.yyyy()).xyzw(edge.p);
|
|
|
|
dedge.p = ddx[2 - (m2 << 1)].yzzw(dedge.p);
|
|
|
|
|
|
|
|
DrawTriangleSection(tb.y, tb.w, edge, dedge, dscan, v1.p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Flush(vertex, index, (GSVertexSW&)dscan);
|
|
|
|
|
|
|
|
if(m_ds->HasEdge())
|
|
|
|
{
|
|
|
|
GSVector4 a = dx.abs() < dy.abs(); // |dx| <= |dy|
|
|
|
|
GSVector4 b = dx < GSVector4::zero(); // dx < 0
|
|
|
|
GSVector4 c = cross < GSVector4::zero(); // longest.p.x < 0
|
|
|
|
|
|
|
|
int orientation = a.mask();
|
|
|
|
int side = ((a | b) ^ c).mask() ^ 2; // evil
|
|
|
|
|
|
|
|
DrawEdge((GSVertexSW&)v0, (GSVertexSW&)v1, (GSVertexSW&)dv[0], orientation & 1, side & 1);
|
|
|
|
DrawEdge((GSVertexSW&)v0, (GSVertexSW&)v2, (GSVertexSW&)dv[1], orientation & 2, side & 2);
|
|
|
|
DrawEdge((GSVertexSW&)v1, (GSVertexSW&)v2, (GSVertexSW&)dv[2], orientation & 4, side & 4);
|
|
|
|
|
|
|
|
Flush(vertex, index, GSVertexSW::zero(), true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GSRasterizer::DrawTriangleSection(int top, int bottom, GSVertexSW2& edge, const GSVertexSW2& dedge, const GSVertexSW2& dscan, const GSVector4& p0)
|
|
|
|
{
|
|
|
|
ASSERT(top < bottom);
|
|
|
|
ASSERT(edge.p.x <= edge.p.y);
|
|
|
|
|
|
|
|
GSVertexSW* RESTRICT e = &m_edge.buff[m_edge.count];
|
|
|
|
|
|
|
|
GSVector4 scissor = m_fscissor_x;
|
|
|
|
|
|
|
|
top = FindMyNextScanline(top);
|
2016-07-10 15:44:56 +00:00
|
|
|
|
2013-07-01 21:28:58 +00:00
|
|
|
while(top < bottom)
|
|
|
|
{
|
|
|
|
GSVector8 dy(GSVector4(top) - p0.yyyy());
|
|
|
|
|
|
|
|
GSVertexSW2 scan;
|
|
|
|
|
|
|
|
scan.p = edge.p + dedge.p * dy.extract<0>();
|
|
|
|
|
|
|
|
GSVector4 lrf = scan.p.ceil();
|
|
|
|
GSVector4 l = lrf.max(scissor);
|
|
|
|
GSVector4 r = lrf.min(scissor);
|
|
|
|
GSVector4i lr = GSVector4i(l.xxyy(r));
|
|
|
|
|
|
|
|
int left = lr.extract32<0>();
|
|
|
|
int right = lr.extract32<2>();
|
|
|
|
|
|
|
|
int pixels = right - left;
|
|
|
|
|
|
|
|
if(pixels > 0)
|
|
|
|
{
|
|
|
|
scan.tc = edge.tc + dedge.tc * dy;
|
|
|
|
|
|
|
|
GSVector8 prestep((l - p0).xxxx());
|
|
|
|
|
|
|
|
scan.p = scan.p + dscan.p * prestep.extract<0>();
|
|
|
|
scan.tc = scan.tc + dscan.tc * prestep;
|
|
|
|
|
|
|
|
AddScanline(e++, pixels, left, top, (GSVertexSW&)scan);
|
|
|
|
}
|
|
|
|
|
|
|
|
top++;
|
|
|
|
|
|
|
|
if(!IsOneOfMyScanlines(top))
|
|
|
|
{
|
2016-07-10 15:44:56 +00:00
|
|
|
top += (m_threads - 1) << m_thread_height;
|
2013-07-01 21:28:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_edge.count += e - &m_edge.buff[m_edge.count];
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
void GSRasterizer::DrawTriangle(const GSVertexSW* vertex, const uint32* index)
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2011-03-08 01:48:15 +00:00
|
|
|
GSVertexSW dv[3];
|
2011-03-27 15:46:32 +00:00
|
|
|
GSVertexSW edge;
|
|
|
|
GSVertexSW dedge;
|
2011-03-08 01:48:15 +00:00
|
|
|
GSVertexSW dscan;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
GSVector4 y0011 = vertex[index[0]].p.yyyy(vertex[index[1]].p);
|
|
|
|
GSVector4 y1221 = vertex[index[1]].p.yyyy(vertex[index[2]].p).xzzx();
|
|
|
|
|
|
|
|
int m1 = (y0011 > y1221).mask() & 7;
|
|
|
|
|
|
|
|
int i[3];
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
i[0] = index[s_ysort[m1][0]];
|
|
|
|
i[1] = index[s_ysort[m1][1]];
|
|
|
|
i[2] = index[s_ysort[m1][2]];
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
const GSVertexSW& v0 = vertex[i[0]];
|
|
|
|
const GSVertexSW& v1 = vertex[i[1]];
|
|
|
|
const GSVertexSW& v2 = vertex[i[2]];
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
y0011 = v0.p.yyyy(v1.p);
|
|
|
|
y1221 = v1.p.yyyy(v2.p).xzzx();
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
m1 = (y0011 == y1221).mask() & 7;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-11-25 23:48:59 +00:00
|
|
|
// if(i == 0) => y0 < y1 < y2
|
|
|
|
// if(i == 1) => y0 == y1 < y2
|
|
|
|
// if(i == 4) => y0 < y1 == y2
|
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
if(m1 == 7) return; // y0 == y1 == y2
|
2011-03-27 15:46:32 +00:00
|
|
|
|
2011-03-29 06:45:35 +00:00
|
|
|
GSVector4 tbf = y0011.xzxz(y1221).ceil();
|
2011-12-31 15:41:07 +00:00
|
|
|
GSVector4 tbmax = tbf.max(m_fscissor_y);
|
|
|
|
GSVector4 tbmin = tbf.min(m_fscissor_y);
|
2012-01-13 18:10:05 +00:00
|
|
|
GSVector4i tb = GSVector4i(tbmax.xzyw(tbmin)); // max(y0, t) max(y1, t) min(y1, b) min(y2, b)
|
2011-03-08 01:48:15 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
dv[0] = v1 - v0;
|
|
|
|
dv[1] = v2 - v0;
|
|
|
|
dv[2] = v2 - v1;
|
2009-03-09 01:42:56 +00:00
|
|
|
|
2011-03-27 15:46:32 +00:00
|
|
|
GSVector4 cross = dv[0].p * dv[1].p.yxwz();
|
|
|
|
|
|
|
|
cross = (cross - cross.yxwz()).yyyy(); // select the second component, the negated cross product
|
2011-12-19 01:20:55 +00:00
|
|
|
|
2011-03-27 15:46:32 +00:00
|
|
|
// the longest horizontal span would be cross.x / dv[1].p.y, but we don't need its actual value
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
int m2 = cross.upl(cross == GSVector4::zero()).mask();
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
if(m2 & 2) return;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
m2 &= 1;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-03-29 06:45:35 +00:00
|
|
|
GSVector4 dxy01 = dv[0].p.xyxy(dv[1].p);
|
2011-03-27 15:46:32 +00:00
|
|
|
|
2011-03-29 06:45:35 +00:00
|
|
|
GSVector4 dx = dxy01.xzxy(dv[2].p);
|
|
|
|
GSVector4 dy = dxy01.ywyx(dv[2].p);
|
2011-03-27 15:46:32 +00:00
|
|
|
|
2011-12-19 01:20:55 +00:00
|
|
|
GSVector4 ddx[3];
|
|
|
|
|
2011-03-29 06:45:35 +00:00
|
|
|
ddx[0] = dx / dy;
|
|
|
|
ddx[1] = ddx[0].yxzw();
|
|
|
|
ddx[2] = ddx[0].xzyw();
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2017-02-27 18:40:05 +00:00
|
|
|
// Precision is important here. Don't use reciprocal, it will break Jak3/Xenosaga1
|
|
|
|
GSVector4 dxy01c = dxy01 / cross;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-29 10:12:20 +00:00
|
|
|
/*
|
|
|
|
dscan = dv[1] * dxy01c.yyyy() - dv[0] * dxy01c.wwww();
|
|
|
|
dedge = dv[0] * dxy01c.zzzz() - dv[1] * dxy01c.xxxx();
|
|
|
|
*/
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-29 10:12:20 +00:00
|
|
|
dscan.p = dv[1].p * dxy01c.yyyy() - dv[0].p * dxy01c.wwww();
|
|
|
|
dscan.t = dv[1].t * dxy01c.yyyy() - dv[0].t * dxy01c.wwww();
|
|
|
|
dscan.c = dv[1].c * dxy01c.yyyy() - dv[0].c * dxy01c.wwww();
|
2011-03-27 15:46:32 +00:00
|
|
|
|
2012-01-29 10:12:20 +00:00
|
|
|
dedge.p = dv[0].p * dxy01c.zzzz() - dv[1].p * dxy01c.xxxx();
|
|
|
|
dedge.t = dv[0].t * dxy01c.zzzz() - dv[1].t * dxy01c.xxxx();
|
|
|
|
dedge.c = dv[0].c * dxy01c.zzzz() - dv[1].c * dxy01c.xxxx();
|
2011-03-27 15:46:32 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
if(m1 & 1)
|
2011-03-08 01:48:15 +00:00
|
|
|
{
|
2011-11-25 23:48:59 +00:00
|
|
|
if(tb.y < tb.w)
|
|
|
|
{
|
2012-01-05 02:40:24 +00:00
|
|
|
edge = vertex[i[1 - m2]];
|
2011-11-25 23:48:59 +00:00
|
|
|
|
2013-06-17 04:11:10 +00:00
|
|
|
edge.p = edge.p.insert32<0, 1>(vertex[i[m2]].p);
|
2012-01-05 02:40:24 +00:00
|
|
|
dedge.p = ddx[2 - (m2 << 1)].yzzw(dedge.p);
|
2011-03-27 15:46:32 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
DrawTriangleSection(tb.x, tb.w, edge, dedge, dscan, vertex[i[1 - m2]].p);
|
2011-11-25 23:48:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-03-08 01:48:15 +00:00
|
|
|
if(tb.x < tb.z)
|
|
|
|
{
|
2012-01-05 02:40:24 +00:00
|
|
|
edge = v0;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-03-27 15:46:32 +00:00
|
|
|
edge.p = edge.p.xxzw();
|
2012-01-05 02:40:24 +00:00
|
|
|
dedge.p = ddx[m2].xyzw(dedge.p);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
DrawTriangleSection(tb.x, tb.z, edge, dedge, dscan, v0.p);
|
2011-03-08 01:48:15 +00:00
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-03-08 01:48:15 +00:00
|
|
|
if(tb.y < tb.w)
|
|
|
|
{
|
2012-01-05 02:40:24 +00:00
|
|
|
edge = v1;
|
2011-03-12 22:10:58 +00:00
|
|
|
|
2013-06-17 04:11:10 +00:00
|
|
|
edge.p = (v0.p.xxxx() + ddx[m2] * dv[0].p.yyyy()).xyzw(edge.p);
|
2012-01-05 02:40:24 +00:00
|
|
|
dedge.p = ddx[2 - (m2 << 1)].yzzw(dedge.p);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
DrawTriangleSection(tb.y, tb.w, edge, dedge, dscan, v1.p);
|
2011-03-08 01:48:15 +00:00
|
|
|
}
|
2011-03-27 15:46:32 +00:00
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-09 08:41:33 +00:00
|
|
|
Flush(vertex, index, dscan);
|
2009-02-19 13:13:20 +00:00
|
|
|
|
2011-12-18 08:13:20 +00:00
|
|
|
if(m_ds->HasEdge())
|
2011-03-27 15:46:32 +00:00
|
|
|
{
|
|
|
|
GSVector4 a = dx.abs() < dy.abs(); // |dx| <= |dy|
|
|
|
|
GSVector4 b = dx < GSVector4::zero(); // dx < 0
|
|
|
|
GSVector4 c = cross < GSVector4::zero(); // longest.p.x < 0
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
int orientation = a.mask();
|
|
|
|
int side = ((a | b) ^ c).mask() ^ 2; // evil
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
DrawEdge(v0, v1, dv[0], orientation & 1, side & 1);
|
|
|
|
DrawEdge(v0, v2, dv[1], orientation & 2, side & 2);
|
|
|
|
DrawEdge(v1, v2, dv[2], orientation & 4, side & 4);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-09 08:41:33 +00:00
|
|
|
Flush(vertex, index, GSVertexSW::zero(), true);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-16 19:13:58 +00:00
|
|
|
void GSRasterizer::DrawTriangleSection(int top, int bottom, GSVertexSW& edge, const GSVertexSW& dedge, const GSVertexSW& dscan, const GSVector4& p0)
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
|
|
|
ASSERT(top < bottom);
|
2011-03-27 15:46:32 +00:00
|
|
|
ASSERT(edge.p.x <= edge.p.y);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
GSVertexSW* RESTRICT e = &m_edge.buff[m_edge.count];
|
2011-03-08 01:48:15 +00:00
|
|
|
|
2011-12-31 15:41:07 +00:00
|
|
|
GSVector4 scissor = m_fscissor_x;
|
2011-03-27 03:12:12 +00:00
|
|
|
|
2011-12-23 15:53:53 +00:00
|
|
|
top = FindMyNextScanline(top);
|
2016-07-10 15:44:56 +00:00
|
|
|
|
2011-12-23 15:53:53 +00:00
|
|
|
while(top < bottom)
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2011-12-23 15:53:53 +00:00
|
|
|
GSVector4 dy = GSVector4(top) - p0.yyyy();
|
2011-12-16 19:13:58 +00:00
|
|
|
|
2011-12-23 15:53:53 +00:00
|
|
|
GSVertexSW scan;
|
2011-12-19 01:20:55 +00:00
|
|
|
|
2013-06-17 04:11:10 +00:00
|
|
|
scan.p = edge.p + dedge.p * dy;
|
2011-12-16 19:13:58 +00:00
|
|
|
|
2011-12-23 15:53:53 +00:00
|
|
|
GSVector4 lrf = scan.p.ceil();
|
|
|
|
GSVector4 l = lrf.max(scissor);
|
|
|
|
GSVector4 r = lrf.min(scissor);
|
|
|
|
GSVector4i lr = GSVector4i(l.xxyy(r));
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-12-23 15:53:53 +00:00
|
|
|
int left = lr.extract32<0>();
|
|
|
|
int right = lr.extract32<2>();
|
2009-02-19 13:13:20 +00:00
|
|
|
|
2011-12-23 15:53:53 +00:00
|
|
|
int pixels = right - left;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-12-23 15:53:53 +00:00
|
|
|
if(pixels > 0)
|
|
|
|
{
|
2013-06-17 04:11:10 +00:00
|
|
|
scan.t = edge.t + dedge.t * dy;
|
|
|
|
scan.c = edge.c + dedge.c * dy;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-29 10:12:20 +00:00
|
|
|
GSVector4 prestep = (l - p0).xxxx();
|
|
|
|
|
2013-06-17 04:11:10 +00:00
|
|
|
scan.p = scan.p + dscan.p * prestep;
|
|
|
|
scan.t = scan.t + dscan.t * prestep;
|
|
|
|
scan.c = scan.c + dscan.c * prestep;
|
2012-01-29 10:12:20 +00:00
|
|
|
|
|
|
|
AddScanline(e++, pixels, left, top, scan);
|
2011-12-23 15:53:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
top++;
|
|
|
|
|
|
|
|
if(!IsOneOfMyScanlines(top))
|
|
|
|
{
|
2016-07-10 15:44:56 +00:00
|
|
|
top += (m_threads - 1) << m_thread_height;
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
}
|
2011-12-19 01:20:55 +00:00
|
|
|
|
2011-03-08 01:48:15 +00:00
|
|
|
m_edge.count += e - &m_edge.buff[m_edge.count];
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2013-07-01 21:28:58 +00:00
|
|
|
#endif
|
|
|
|
|
2012-01-13 18:10:05 +00:00
|
|
|
void GSRasterizer::DrawSprite(const GSVertexSW* vertex, const uint32* index)
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2012-01-05 02:40:24 +00:00
|
|
|
const GSVertexSW& v0 = vertex[index[0]];
|
|
|
|
const GSVertexSW& v1 = vertex[index[1]];
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
GSVector4 mask = (v0.p < v1.p).xyzw(GSVector4::zero());
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
GSVertexSW v[2];
|
|
|
|
|
|
|
|
v[0].p = v1.p.blend32(v0.p, mask);
|
|
|
|
v[0].t = v1.t.blend32(v0.t, mask);
|
|
|
|
v[0].c = v1.c;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-05 02:40:24 +00:00
|
|
|
v[1].p = v0.p.blend32(v1.p, mask);
|
|
|
|
v[1].t = v0.t.blend32(v1.t, mask);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
GSVector4i r(v[0].p.xyxy(v[1].p).ceil());
|
|
|
|
|
2011-03-08 01:48:15 +00:00
|
|
|
r = r.rintersect(m_scissor);
|
2010-04-25 00:31:27 +00:00
|
|
|
|
2009-05-14 16:41:52 +00:00
|
|
|
if(r.rempty()) return;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
GSVertexSW scan = v[0];
|
|
|
|
|
2012-01-13 18:10:05 +00:00
|
|
|
if(m_ds->IsSolidRect())
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2011-12-31 15:41:07 +00:00
|
|
|
if(m_threads == 1)
|
|
|
|
{
|
|
|
|
m_ds->DrawRect(r, scan);
|
|
|
|
|
2013-06-23 10:46:24 +00:00
|
|
|
int pixels = r.width() * r.height();
|
|
|
|
|
|
|
|
m_pixels.actual += pixels;
|
|
|
|
m_pixels.total += pixels;
|
2011-12-31 15:41:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int top = FindMyNextScanline(r.top);
|
|
|
|
int bottom = r.bottom;
|
|
|
|
|
|
|
|
while(top < bottom)
|
|
|
|
{
|
|
|
|
r.top = top;
|
2016-07-10 15:44:56 +00:00
|
|
|
r.bottom = std::min<int>((top + (1 << m_thread_height)) & ~((1 << m_thread_height) - 1), bottom);
|
2011-12-31 15:41:07 +00:00
|
|
|
|
|
|
|
m_ds->DrawRect(r, scan);
|
2016-07-10 15:44:56 +00:00
|
|
|
|
2013-06-23 10:46:24 +00:00
|
|
|
int pixels = r.width() * r.height();
|
|
|
|
|
|
|
|
m_pixels.actual += pixels;
|
|
|
|
m_pixels.total += pixels;
|
2011-12-31 15:41:07 +00:00
|
|
|
|
2016-07-10 15:44:56 +00:00
|
|
|
top = r.bottom + ((m_threads - 1) << m_thread_height);
|
2011-12-31 15:41:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
GSVertexSW dv = v[1] - v[0];
|
|
|
|
|
2015-08-04 01:34:46 +00:00
|
|
|
GSVector4 dt = dv.t / dv.p.xyxy();
|
2011-04-25 01:44:00 +00:00
|
|
|
|
|
|
|
GSVertexSW dedge;
|
|
|
|
GSVertexSW dscan;
|
2011-03-12 22:10:58 +00:00
|
|
|
|
2015-08-04 01:34:46 +00:00
|
|
|
dedge.t = GSVector4::zero().insert32<1, 1>(dt);
|
|
|
|
dscan.t = GSVector4::zero().insert32<0, 0>(dt);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-03-27 03:12:12 +00:00
|
|
|
GSVector4 prestep = GSVector4(r.left, r.top) - scan.p;
|
|
|
|
|
|
|
|
int m = (prestep == GSVector4::zero()).mask();
|
|
|
|
|
|
|
|
if((m & 2) == 0) scan.t += dedge.t * prestep.yyyy();
|
|
|
|
if((m & 1) == 0) scan.t += dscan.t * prestep.xxxx();
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2012-01-09 08:41:33 +00:00
|
|
|
m_ds->SetupPrim(vertex, index, dscan);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
while(1)
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2010-04-25 00:31:27 +00:00
|
|
|
if(IsOneOfMyScanlines(r.top))
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2013-06-23 10:46:24 +00:00
|
|
|
DrawScanline(r.width(), r.left, r.top, scan);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
2011-03-09 11:52:53 +00:00
|
|
|
|
|
|
|
if(++r.top >= r.bottom) break;
|
|
|
|
|
|
|
|
scan.t += dedge.t;
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-08 01:48:15 +00:00
|
|
|
void GSRasterizer::DrawEdge(const GSVertexSW& v0, const GSVertexSW& v1, const GSVertexSW& dv, int orientation, int side)
|
2009-03-09 01:42:56 +00:00
|
|
|
{
|
2010-04-25 00:31:27 +00:00
|
|
|
// orientation:
|
2009-03-09 01:42:56 +00:00
|
|
|
// - true: |dv.p.y| > |dv.p.x|
|
2010-04-25 00:31:27 +00:00
|
|
|
// - false |dv.p.x| > |dv.p.y|
|
|
|
|
// side:
|
2009-03-09 01:42:56 +00:00
|
|
|
// - true: top/left edge
|
|
|
|
// - false: bottom/right edge
|
|
|
|
|
|
|
|
// TODO: bit slow and too much duplicated code
|
|
|
|
// TODO: inner pre-step is still missing (hardly noticable)
|
2011-03-27 15:46:32 +00:00
|
|
|
// TODO: it does not always line up with the edge of the surrounded triangle
|
2009-03-09 01:42:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
GSVertexSW* RESTRICT e = &m_edge.buff[m_edge.count];
|
2011-12-19 01:20:55 +00:00
|
|
|
|
2009-03-09 01:42:56 +00:00
|
|
|
if(orientation)
|
|
|
|
{
|
2011-12-31 15:41:07 +00:00
|
|
|
GSVector4 tbf = v0.p.yyyy(v1.p).ceil(); // t t b b
|
2015-08-04 01:34:46 +00:00
|
|
|
GSVector4 tbmax = tbf.max(m_fscissor_y); // max(t, st) max(t, sb) max(b, st) max(b, sb)
|
|
|
|
GSVector4 tbmin = tbf.min(m_fscissor_y); // min(t, st) min(t, sb) min(b, st) min(b, sb)
|
|
|
|
GSVector4i tb = GSVector4i(tbmax.xzyw(tbmin)); // max(t, st) max(b, sb) min(t, st) min(b, sb)
|
2009-03-09 01:42:56 +00:00
|
|
|
|
|
|
|
int top, bottom;
|
|
|
|
|
|
|
|
GSVertexSW edge, dedge;
|
|
|
|
|
|
|
|
if((dv.p >= GSVector4::zero()).mask() & 2)
|
|
|
|
{
|
2015-08-04 01:34:46 +00:00
|
|
|
top = tb.extract32<0>(); // max(t, st)
|
2011-12-31 15:41:07 +00:00
|
|
|
bottom = tb.extract32<3>(); // min(b, sb)
|
2009-03-09 01:42:56 +00:00
|
|
|
|
|
|
|
if(top >= bottom) return;
|
|
|
|
|
|
|
|
edge = v0;
|
|
|
|
dedge = dv / dv.p.yyyy();
|
|
|
|
|
2011-12-31 15:41:07 +00:00
|
|
|
edge += dedge * (tbmax.xxxx() - edge.p.yyyy());
|
2009-03-09 01:42:56 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-08-04 01:34:46 +00:00
|
|
|
top = tb.extract32<1>(); // max(b, st)
|
2011-12-31 15:41:07 +00:00
|
|
|
bottom = tb.extract32<2>(); // min(t, sb)
|
2009-03-09 01:42:56 +00:00
|
|
|
|
|
|
|
if(top >= bottom) return;
|
|
|
|
|
|
|
|
edge = v1;
|
|
|
|
dedge = dv / dv.p.yyyy();
|
|
|
|
|
2011-12-31 15:41:07 +00:00
|
|
|
edge += dedge * (tbmax.zzzz() - edge.p.yyyy());
|
2009-03-09 01:42:56 +00:00
|
|
|
}
|
|
|
|
|
2009-03-16 22:17:50 +00:00
|
|
|
GSVector4i p = GSVector4i(edge.p.upl(dedge.p) * 0x10000);
|
|
|
|
|
|
|
|
int x = p.extract32<0>();
|
|
|
|
int dx = p.extract32<1>();
|
|
|
|
|
2009-03-09 01:42:56 +00:00
|
|
|
if(side)
|
|
|
|
{
|
|
|
|
while(1)
|
|
|
|
{
|
2011-03-09 11:52:53 +00:00
|
|
|
int xi = x >> 16;
|
|
|
|
int xf = x & 0xffff;
|
|
|
|
|
2011-03-27 15:46:32 +00:00
|
|
|
if(m_scissor.left <= xi && xi < m_scissor.right && IsOneOfMyScanlines(top))
|
2009-03-09 01:42:56 +00:00
|
|
|
{
|
2011-03-27 03:12:12 +00:00
|
|
|
AddScanline(e, 1, xi, top, edge);
|
2009-03-09 01:42:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
e->t.u32[3] = (0x10000 - xf) & 0xffff;
|
2009-03-09 01:42:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
e++;
|
2009-03-09 01:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(++top >= bottom) break;
|
|
|
|
|
|
|
|
edge += dedge;
|
2009-03-16 22:17:50 +00:00
|
|
|
x += dx;
|
2009-03-09 01:42:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while(1)
|
|
|
|
{
|
2011-03-09 11:52:53 +00:00
|
|
|
int xi = (x >> 16) + 1;
|
|
|
|
int xf = x & 0xffff;
|
|
|
|
|
2011-03-27 15:46:32 +00:00
|
|
|
if(m_scissor.left <= xi && xi < m_scissor.right && IsOneOfMyScanlines(top))
|
2009-03-09 01:42:56 +00:00
|
|
|
{
|
2011-03-27 03:12:12 +00:00
|
|
|
AddScanline(e, 1, xi, top, edge);
|
2009-03-09 01:42:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
e->t.u32[3] = xf;
|
2009-03-09 01:42:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
e++;
|
2009-03-09 01:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(++top >= bottom) break;
|
|
|
|
|
|
|
|
edge += dedge;
|
2009-03-16 22:17:50 +00:00
|
|
|
x += dx;
|
2009-03-09 01:42:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-12-31 15:41:07 +00:00
|
|
|
GSVector4 lrf = v0.p.xxxx(v1.p).ceil(); // l l r r
|
2015-08-04 01:34:46 +00:00
|
|
|
GSVector4 lrmax = lrf.max(m_fscissor_x); // max(l, sl) max(l, sr) max(r, sl) max(r, sr)
|
|
|
|
GSVector4 lrmin = lrf.min(m_fscissor_x); // min(l, sl) min(l, sr) min(r, sl) min(r, sr)
|
|
|
|
GSVector4i lr = GSVector4i(lrmax.xzyw(lrmin)); // max(l, sl) max(r, sl) min(l, sr) min(r, sr)
|
2009-03-09 01:42:56 +00:00
|
|
|
|
|
|
|
int left, right;
|
|
|
|
|
|
|
|
GSVertexSW edge, dedge;
|
|
|
|
|
|
|
|
if((dv.p >= GSVector4::zero()).mask() & 1)
|
|
|
|
{
|
2011-12-31 15:41:07 +00:00
|
|
|
left = lr.extract32<0>(); // max(l, sl)
|
2015-08-04 01:34:46 +00:00
|
|
|
right = lr.extract32<3>(); // min(r, sr)
|
2009-03-09 01:42:56 +00:00
|
|
|
|
|
|
|
if(left >= right) return;
|
|
|
|
|
|
|
|
edge = v0;
|
|
|
|
dedge = dv / dv.p.xxxx();
|
|
|
|
|
|
|
|
edge += dedge * (lrmax.xxxx() - edge.p.xxxx());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-12-31 15:41:07 +00:00
|
|
|
left = lr.extract32<1>(); // max(r, sl)
|
2015-08-04 01:34:46 +00:00
|
|
|
right = lr.extract32<2>(); // min(l, sr)
|
2009-03-09 01:42:56 +00:00
|
|
|
|
|
|
|
if(left >= right) return;
|
|
|
|
|
|
|
|
edge = v1;
|
|
|
|
dedge = dv / dv.p.xxxx();
|
|
|
|
|
2011-12-31 15:41:07 +00:00
|
|
|
edge += dedge * (lrmax.zzzz() - edge.p.xxxx());
|
2009-03-09 01:42:56 +00:00
|
|
|
}
|
|
|
|
|
2009-03-16 22:17:50 +00:00
|
|
|
GSVector4i p = GSVector4i(edge.p.upl(dedge.p) * 0x10000);
|
|
|
|
|
|
|
|
int y = p.extract32<2>();
|
|
|
|
int dy = p.extract32<3>();
|
|
|
|
|
2009-03-09 01:42:56 +00:00
|
|
|
if(side)
|
|
|
|
{
|
|
|
|
while(1)
|
|
|
|
{
|
2011-03-09 11:52:53 +00:00
|
|
|
int yi = y >> 16;
|
|
|
|
int yf = y & 0xffff;
|
2009-03-09 01:42:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
if(m_scissor.top <= yi && yi < m_scissor.bottom && IsOneOfMyScanlines(yi))
|
|
|
|
{
|
2011-03-27 03:12:12 +00:00
|
|
|
AddScanline(e, 1, left, yi, edge);
|
2009-03-09 01:42:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
e->t.u32[3] = (0x10000 - yf) & 0xffff;
|
2009-03-09 01:42:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
e++;
|
2009-03-09 01:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(++left >= right) break;
|
|
|
|
|
|
|
|
edge += dedge;
|
2009-03-16 22:17:50 +00:00
|
|
|
y += dy;
|
2009-03-09 01:42:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while(1)
|
|
|
|
{
|
2011-03-09 11:52:53 +00:00
|
|
|
int yi = (y >> 16) + 1;
|
|
|
|
int yf = y & 0xffff;
|
2009-03-09 01:42:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
if(m_scissor.top <= yi && yi < m_scissor.bottom && IsOneOfMyScanlines(yi))
|
|
|
|
{
|
2011-03-27 03:12:12 +00:00
|
|
|
AddScanline(e, 1, left, yi, edge);
|
2009-03-09 01:42:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
e->t.u32[3] = yf;
|
2009-03-09 01:42:56 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
e++;
|
2009-03-09 01:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(++left >= right) break;
|
|
|
|
|
|
|
|
edge += dedge;
|
2009-03-16 22:17:50 +00:00
|
|
|
y += dy;
|
2009-03-09 01:42:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-03-08 01:48:15 +00:00
|
|
|
|
2011-12-16 19:13:58 +00:00
|
|
|
m_edge.count += e - &m_edge.buff[m_edge.count];
|
2011-03-27 03:12:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GSRasterizer::AddScanline(GSVertexSW* e, int pixels, int left, int top, const GSVertexSW& scan)
|
|
|
|
{
|
|
|
|
*e = scan;
|
|
|
|
|
2013-06-17 04:11:10 +00:00
|
|
|
e->_pad.i32[0] = pixels;
|
|
|
|
e->_pad.i32[1] = left;
|
|
|
|
e->_pad.i32[2] = top;
|
2011-03-08 01:48:15 +00:00
|
|
|
}
|
|
|
|
|
2012-01-09 08:41:33 +00:00
|
|
|
void GSRasterizer::Flush(const GSVertexSW* vertex, const uint32* index, const GSVertexSW& dscan, bool edge)
|
2011-03-08 01:48:15 +00:00
|
|
|
{
|
|
|
|
// TODO: on win64 this could be the place where xmm6-15 are preserved (not by each DrawScanline)
|
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
int count = m_edge.count;
|
2011-03-08 01:48:15 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
if(count > 0)
|
2011-03-08 01:48:15 +00:00
|
|
|
{
|
2012-01-09 08:41:33 +00:00
|
|
|
m_ds->SetupPrim(vertex, index, dscan);
|
2011-03-08 01:48:15 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
const GSVertexSW* RESTRICT e = m_edge.buff;
|
2011-03-27 03:12:12 +00:00
|
|
|
const GSVertexSW* RESTRICT ee = e + count;
|
2011-03-08 01:48:15 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
if(!edge)
|
|
|
|
{
|
2011-12-19 01:20:55 +00:00
|
|
|
do
|
2011-03-27 03:12:12 +00:00
|
|
|
{
|
2013-06-17 04:11:10 +00:00
|
|
|
int pixels = e->_pad.i32[0];
|
|
|
|
int left = e->_pad.i32[1];
|
|
|
|
int top = e->_pad.i32[2];
|
2011-03-27 03:12:12 +00:00
|
|
|
|
2013-06-23 10:46:24 +00:00
|
|
|
DrawScanline(pixels, left, top, *e++);
|
2011-03-27 03:12:12 +00:00
|
|
|
}
|
|
|
|
while(e < ee);
|
2011-03-09 11:52:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-12-19 01:20:55 +00:00
|
|
|
do
|
2011-03-27 03:12:12 +00:00
|
|
|
{
|
2013-06-17 04:11:10 +00:00
|
|
|
int pixels = e->_pad.i32[0];
|
|
|
|
int left = e->_pad.i32[1];
|
|
|
|
int top = e->_pad.i32[2];
|
2011-03-27 03:12:12 +00:00
|
|
|
|
2013-06-23 10:46:24 +00:00
|
|
|
DrawEdge(pixels, left, top, *e++);
|
2011-03-27 03:12:12 +00:00
|
|
|
}
|
|
|
|
while(e < ee);
|
2011-03-09 11:52:53 +00:00
|
|
|
}
|
2011-03-08 01:48:15 +00:00
|
|
|
|
2011-03-09 11:52:53 +00:00
|
|
|
m_edge.count = 0;
|
|
|
|
}
|
2009-03-09 01:42:56 +00:00
|
|
|
}
|
|
|
|
|
2013-06-23 10:46:24 +00:00
|
|
|
#if _M_SSE >= 0x501
|
|
|
|
#define PIXELS_PER_LOOP 8
|
|
|
|
#else
|
|
|
|
#define PIXELS_PER_LOOP 4
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void GSRasterizer::DrawScanline(int pixels, int left, int top, const GSVertexSW& scan)
|
|
|
|
{
|
|
|
|
m_pixels.actual += pixels;
|
|
|
|
m_pixels.total += ((left + pixels + (PIXELS_PER_LOOP - 1)) & ~(PIXELS_PER_LOOP - 1)) - (left & (PIXELS_PER_LOOP - 1));
|
|
|
|
//m_pixels.total += ((left + pixels + (PIXELS_PER_LOOP - 1)) & ~(PIXELS_PER_LOOP - 1)) - left;
|
|
|
|
|
|
|
|
ASSERT(m_pixels.actual <= m_pixels.total);
|
|
|
|
|
|
|
|
m_ds->DrawScanline(pixels, left, top, scan);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GSRasterizer::DrawEdge(int pixels, int left, int top, const GSVertexSW& scan)
|
|
|
|
{
|
|
|
|
m_pixels.actual += 1;
|
|
|
|
m_pixels.total += PIXELS_PER_LOOP - 1;
|
|
|
|
|
|
|
|
ASSERT(m_pixels.actual <= m_pixels.total);
|
|
|
|
|
|
|
|
m_ds->DrawEdge(pixels, left, top, scan);
|
|
|
|
}
|
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
//
|
|
|
|
|
2012-01-18 11:47:31 +00:00
|
|
|
GSRasterizerList::GSRasterizerList(int threads, GSPerfMon* perfmon)
|
|
|
|
: m_perfmon(perfmon)
|
2011-12-18 08:13:20 +00:00
|
|
|
{
|
2016-07-10 15:44:56 +00:00
|
|
|
m_thread_height = compute_best_thread_height(threads);
|
|
|
|
|
2017-02-08 18:30:53 +00:00
|
|
|
int rows = (2048 >> m_thread_height) + 16;
|
|
|
|
m_scanline = (uint8*)_aligned_malloc(rows, 64);
|
2012-01-18 11:47:31 +00:00
|
|
|
|
|
|
|
int row = 0;
|
|
|
|
|
2017-02-08 18:30:53 +00:00
|
|
|
while(row < rows)
|
2012-01-18 11:47:31 +00:00
|
|
|
{
|
|
|
|
for(int i = 0; i < threads; i++, row++)
|
|
|
|
{
|
2013-06-20 05:07:52 +00:00
|
|
|
m_scanline[row] = (uint8)i;
|
2012-01-18 11:47:31 +00:00
|
|
|
}
|
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2011-12-22 14:36:54 +00:00
|
|
|
GSRasterizerList::~GSRasterizerList()
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2012-01-18 11:47:31 +00:00
|
|
|
_aligned_free(m_scanline);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2015-03-21 14:09:58 +00:00
|
|
|
void GSRasterizerList::Queue(const shared_ptr<GSRasterizerData>& data)
|
2011-12-22 01:48:16 +00:00
|
|
|
{
|
2012-01-18 11:47:31 +00:00
|
|
|
GSVector4i r = data->bbox.rintersect(data->scissor);
|
|
|
|
|
|
|
|
ASSERT(r.top >= 0 && r.top < 2048 && r.bottom >= 0 && r.bottom < 2048);
|
2011-12-23 15:53:53 +00:00
|
|
|
|
2016-07-10 15:44:56 +00:00
|
|
|
int top = r.top >> m_thread_height;
|
|
|
|
int bottom = std::min<int>((r.bottom + (1 << m_thread_height) - 1) >> m_thread_height, top + m_workers.size());
|
2011-12-23 15:53:53 +00:00
|
|
|
|
2012-01-18 11:47:31 +00:00
|
|
|
while(top < bottom)
|
|
|
|
{
|
|
|
|
m_workers[m_scanline[top++]]->Push(data);
|
|
|
|
}
|
2011-12-22 01:48:16 +00:00
|
|
|
}
|
|
|
|
|
2011-12-22 14:36:54 +00:00
|
|
|
void GSRasterizerList::Sync()
|
2011-12-22 01:48:16 +00:00
|
|
|
{
|
2012-01-18 11:47:31 +00:00
|
|
|
if(!IsSynced())
|
|
|
|
{
|
|
|
|
for(size_t i = 0; i < m_workers.size(); i++)
|
|
|
|
{
|
|
|
|
m_workers[i]->Wait();
|
|
|
|
}
|
2011-12-22 01:48:16 +00:00
|
|
|
|
2012-01-18 11:47:31 +00:00
|
|
|
m_perfmon->Put(GSPerfMon::SyncPoint, 1);
|
|
|
|
}
|
|
|
|
}
|
2011-12-22 01:48:16 +00:00
|
|
|
|
2012-01-18 11:47:31 +00:00
|
|
|
bool GSRasterizerList::IsSynced() const
|
|
|
|
{
|
2011-12-22 14:36:54 +00:00
|
|
|
for(size_t i = 0; i < m_workers.size(); i++)
|
2011-12-22 01:48:16 +00:00
|
|
|
{
|
2012-01-18 11:47:31 +00:00
|
|
|
if(!m_workers[i]->IsEmpty())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2011-12-22 01:48:16 +00:00
|
|
|
}
|
|
|
|
|
2012-01-18 11:47:31 +00:00
|
|
|
return true;
|
2011-12-22 01:48:16 +00:00
|
|
|
}
|
|
|
|
|
2016-07-10 15:44:56 +00:00
|
|
|
int GSRasterizerList::GetPixels(bool reset)
|
2012-01-08 17:10:00 +00:00
|
|
|
{
|
|
|
|
int pixels = 0;
|
2016-07-10 15:44:56 +00:00
|
|
|
|
2012-01-08 17:10:00 +00:00
|
|
|
for(size_t i = 0; i < m_workers.size(); i++)
|
|
|
|
{
|
gsdx: Make GSJobQueue non-inheritable
In the previous code, the threads were created and destroyed in the base
class constructor and destructor, so the threads could potentially be
active while the object is in a partially constructed or destroyed state.
The thread however, relies on a virtual function to process the queue
items, and the vtable might not be in the desired state when the object
is partially constructed or destroyed.
This probably only matters during object destruction - no items are in
the queue during object construction so the virtual function won't be
called, but items may still be queued up when the destructor is called,
so the virtual function can be called. It wasn't an issue because all
uses of the thread explicitly waited for the queues to be empty before
invoking the destructor.
Adjust the constructor to take a std::function parameter, which the
thread will use instead to process queue items, and avoid inheriting
from the GSJobQueue class. This will also eliminate the need to
explicitly wait for all jobs to finish (unless there are other external
factors, of course), which would probably make future code safer.
2016-11-09 01:34:48 +00:00
|
|
|
pixels += m_r[i]->GetPixels(reset);
|
2012-01-08 17:10:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return pixels;
|
|
|
|
}
|