Files
pcsx2/plugins/GSdx/GSLocalMemory.cpp
T
Pseudonym a0629587be gsdx memory: implement read texture of PS GPU24
convert the swizzled block as tightly packed 24 bits RGB

Then convert scanline to standard 32 bits RGBA

The HW renderer requires the preload data hack
2016-10-05 21:59:42 +02:00

2174 lines
58 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
*
* Special Notes:
*
* Based on Page.c from GSSoft
* Copyright (C) 2002-2004 GSsoft Team
*
*/
#include "stdafx.h"
#include "GSLocalMemory.h"
#define ASSERT_BLOCK(r, w, h) \
ASSERT((r).width() >= (w) && (r).height() >= (h) && !((r).left & ((w) - 1)) && !((r).top & ((h) - 1)) && !((r).right & ((w) - 1)) && !((r).bottom & ((h) - 1))); \
#define FOREACH_BLOCK_START(r, w, h, bpp) \
ASSERT_BLOCK(r, w, h); \
GSVector4i _r = (r) >> 3; \
uint8* _dst = dst - _r.left * (bpp); \
int _offset = dstpitch * (h); \
for(int y = _r.top; y < _r.bottom; y += (h) >> 3, _dst += _offset) \
{ \
uint32 _base = off->block.row[y]; \
for(int x = _r.left; x < _r.right; x += (w) >> 3) \
{ \
const uint8* src = BlockPtr(_base + off->block.col[x]); \
uint8* read_dst = &_dst[x * (bpp)]; \
#define FOREACH_BLOCK_END }}
//
uint32 GSLocalMemory::pageOffset32[32][32][64];
uint32 GSLocalMemory::pageOffset32Z[32][32][64];
uint32 GSLocalMemory::pageOffset16[32][64][64];
uint32 GSLocalMemory::pageOffset16S[32][64][64];
uint32 GSLocalMemory::pageOffset16Z[32][64][64];
uint32 GSLocalMemory::pageOffset16SZ[32][64][64];
uint32 GSLocalMemory::pageOffset8[32][64][128];
uint32 GSLocalMemory::pageOffset4[32][128][128];
int GSLocalMemory::rowOffset32[4096];
int GSLocalMemory::rowOffset32Z[4096];
int GSLocalMemory::rowOffset16[4096];
int GSLocalMemory::rowOffset16S[4096];
int GSLocalMemory::rowOffset16Z[4096];
int GSLocalMemory::rowOffset16SZ[4096];
int GSLocalMemory::rowOffset8[2][4096];
int GSLocalMemory::rowOffset4[2][4096];
short GSLocalMemory::blockOffset32[256];
short GSLocalMemory::blockOffset32Z[256];
short GSLocalMemory::blockOffset16[256];
short GSLocalMemory::blockOffset16S[256];
short GSLocalMemory::blockOffset16Z[256];
short GSLocalMemory::blockOffset16SZ[256];
short GSLocalMemory::blockOffset8[256];
short GSLocalMemory::blockOffset4[256];
//
GSLocalMemory::psm_t GSLocalMemory::m_psm[64];
//
GSLocalMemory::GSLocalMemory()
: m_clut(this)
{
m_vm8 = (uint8*)vmalloc(m_vmsize * 4, false);
m_vm16 = (uint16*)m_vm8;
m_vm32 = (uint32*)m_vm8;
memset(m_vm8, 0, m_vmsize);
for(int bp = 0; bp < 32; bp++)
{
for(int y = 0; y < 32; y++) for(int x = 0; x < 64; x++)
{
pageOffset32[bp][y][x] = PixelAddressOrg32(x, y, bp, 0);
pageOffset32Z[bp][y][x] = PixelAddressOrg32Z(x, y, bp, 0);
}
for(int y = 0; y < 64; y++) for(int x = 0; x < 64; x++)
{
pageOffset16[bp][y][x] = PixelAddressOrg16(x, y, bp, 0);
pageOffset16S[bp][y][x] = PixelAddressOrg16S(x, y, bp, 0);
pageOffset16Z[bp][y][x] = PixelAddressOrg16Z(x, y, bp, 0);
pageOffset16SZ[bp][y][x] = PixelAddressOrg16SZ(x, y, bp, 0);
}
for(int y = 0; y < 64; y++) for(int x = 0; x < 128; x++)
{
pageOffset8[bp][y][x] = PixelAddressOrg8(x, y, bp, 0);
}
for(int y = 0; y < 128; y++) for(int x = 0; x < 128; x++)
{
pageOffset4[bp][y][x] = PixelAddressOrg4(x, y, bp, 0);
}
}
for(size_t x = 0; x < countof(rowOffset32); x++)
{
rowOffset32[x] = (int)PixelAddress32(x & 0x7ff, 0, 0, 32) - (int)PixelAddress32(0, 0, 0, 32);
}
for(size_t x = 0; x < countof(rowOffset32Z); x++)
{
rowOffset32Z[x] = (int)PixelAddress32Z(x & 0x7ff, 0, 0, 32) - (int)PixelAddress32Z(0, 0, 0, 32);
}
for(size_t x = 0; x < countof(rowOffset16); x++)
{
rowOffset16[x] = (int)PixelAddress16(x & 0x7ff, 0, 0, 32) - (int)PixelAddress16(0, 0, 0, 32);
}
for(size_t x = 0; x < countof(rowOffset16S); x++)
{
rowOffset16S[x] = (int)PixelAddress16S(x & 0x7ff, 0, 0, 32) - (int)PixelAddress16S(0, 0, 0, 32);
}
for(size_t x = 0; x < countof(rowOffset16Z); x++)
{
rowOffset16Z[x] = (int)PixelAddress16Z(x & 0x7ff, 0, 0, 32) - (int)PixelAddress16Z(0, 0, 0, 32);
}
for(size_t x = 0; x < countof(rowOffset16SZ); x++)
{
rowOffset16SZ[x] = (int)PixelAddress16SZ(x & 0x7ff, 0, 0, 32) - (int)PixelAddress16SZ(0, 0, 0, 32);
}
for(size_t x = 0; x < countof(rowOffset8[0]); x++)
{
rowOffset8[0][x] = (int)PixelAddress8(x & 0x7ff, 0, 0, 32) - (int)PixelAddress8(0, 0, 0, 32);
rowOffset8[1][x] = (int)PixelAddress8(x & 0x7ff, 2, 0, 32) - (int)PixelAddress8(0, 2, 0, 32);
}
for(size_t x = 0; x < countof(rowOffset4[0]); x++)
{
rowOffset4[0][x] = (int)PixelAddress4(x & 0x7ff, 0, 0, 32) - (int)PixelAddress4(0, 0, 0, 32);
rowOffset4[1][x] = (int)PixelAddress4(x & 0x7ff, 2, 0, 32) - (int)PixelAddress4(0, 2, 0, 32);
}
for(size_t x = 0; x < countof(blockOffset32); x++)
{
blockOffset32[x] = (short)((int)BlockNumber32(x << 3, 0, 0, 32) - (int)BlockNumber32(0, 0, 0, 32));
}
for(size_t x = 0; x < countof(blockOffset32Z); x++)
{
blockOffset32Z[x] = (short)((int)BlockNumber32Z(x << 3, 0, 0, 32) - (int)BlockNumber32Z(0, 0, 0, 32));
}
for(size_t x = 0; x < countof(blockOffset16); x++)
{
blockOffset16[x] = (short)((int)BlockNumber16(x << 3, 0, 0, 32) - (int)BlockNumber16(0, 0, 0, 32));
}
for(size_t x = 0; x < countof(blockOffset16S); x++)
{
blockOffset16S[x] = (short)((int)BlockNumber16S(x << 3, 0, 0, 32) - (int)BlockNumber16S(0, 0, 0, 32));
}
for(size_t x = 0; x < countof(blockOffset16Z); x++)
{
blockOffset16Z[x] = (short)((int)BlockNumber16Z(x << 3, 0, 0, 32) - (int)BlockNumber16Z(0, 0, 0, 32));
}
for(size_t x = 0; x < countof(blockOffset16SZ); x++)
{
blockOffset16SZ[x] = (short)((int)BlockNumber16SZ(x << 3, 0, 0, 32) - (int)BlockNumber16SZ(0, 0, 0, 32));
}
for(size_t x = 0; x < countof(blockOffset8); x++)
{
blockOffset8[x] = (short)((int)BlockNumber8(x << 3, 0, 0, 32) - (int)BlockNumber8(0, 0, 0, 32));
}
for(size_t x = 0; x < countof(blockOffset4); x++)
{
blockOffset4[x] = (short)((int)BlockNumber4(x << 3, 0, 0, 32) - (int)BlockNumber4(0, 0, 0, 32));
}
for(size_t i = 0; i < countof(m_psm); i++)
{
m_psm[i].pa = &GSLocalMemory::PixelAddress32;
m_psm[i].bn = &GSLocalMemory::BlockNumber32;
m_psm[i].rp = &GSLocalMemory::ReadPixel32;
m_psm[i].rpa = &GSLocalMemory::ReadPixel32;
m_psm[i].wp = &GSLocalMemory::WritePixel32;
m_psm[i].wpa = &GSLocalMemory::WritePixel32;
m_psm[i].rt = &GSLocalMemory::ReadTexel32;
m_psm[i].rta = &GSLocalMemory::ReadTexel32;
m_psm[i].wfa = &GSLocalMemory::WritePixel32;
m_psm[i].wi = &GSLocalMemory::WriteImage<PSM_PSMCT32, 8, 8, 32>;
m_psm[i].ri = &GSLocalMemory::ReadImageX; // TODO
m_psm[i].rtx = &GSLocalMemory::ReadTexture32;
m_psm[i].rtxP = &GSLocalMemory::ReadTexture32;
m_psm[i].rtxb = &GSLocalMemory::ReadTextureBlock32;
m_psm[i].rtxbP = &GSLocalMemory::ReadTextureBlock32;
m_psm[i].bpp = m_psm[i].trbpp = 32;
m_psm[i].pal = 0;
m_psm[i].bs = GSVector2i(8, 8);
m_psm[i].pgs = GSVector2i(64, 32);
for(int j = 0; j < 8; j++) m_psm[i].rowOffset[j] = rowOffset32;
m_psm[i].blockOffset = blockOffset32;
m_psm[i].msk = 0xff;
m_psm[i].depth = 0;
}
m_psm[PSM_PSGPU24].pa = &GSLocalMemory::PixelAddress16;
m_psm[PSM_PSMCT16].pa = &GSLocalMemory::PixelAddress16;
m_psm[PSM_PSMCT16S].pa = &GSLocalMemory::PixelAddress16S;
m_psm[PSM_PSMT8].pa = &GSLocalMemory::PixelAddress8;
m_psm[PSM_PSMT4].pa = &GSLocalMemory::PixelAddress4;
m_psm[PSM_PSMZ32].pa = &GSLocalMemory::PixelAddress32Z;
m_psm[PSM_PSMZ24].pa = &GSLocalMemory::PixelAddress32Z;
m_psm[PSM_PSMZ16].pa = &GSLocalMemory::PixelAddress16Z;
m_psm[PSM_PSMZ16S].pa = &GSLocalMemory::PixelAddress16SZ;
m_psm[PSM_PSGPU24].bn = &GSLocalMemory::BlockNumber16;
m_psm[PSM_PSMCT16].bn = &GSLocalMemory::BlockNumber16;
m_psm[PSM_PSMCT16S].bn = &GSLocalMemory::BlockNumber16S;
m_psm[PSM_PSMT8].bn = &GSLocalMemory::BlockNumber8;
m_psm[PSM_PSMT4].bn = &GSLocalMemory::BlockNumber4;
m_psm[PSM_PSMZ32].bn = &GSLocalMemory::BlockNumber32Z;
m_psm[PSM_PSMZ24].bn = &GSLocalMemory::BlockNumber32Z;
m_psm[PSM_PSMZ16].bn = &GSLocalMemory::BlockNumber16Z;
m_psm[PSM_PSMZ16S].bn = &GSLocalMemory::BlockNumber16SZ;
m_psm[PSM_PSMCT24].rp = &GSLocalMemory::ReadPixel24;
m_psm[PSM_PSMCT16].rp = &GSLocalMemory::ReadPixel16;
m_psm[PSM_PSMCT16S].rp = &GSLocalMemory::ReadPixel16S;
m_psm[PSM_PSMT8].rp = &GSLocalMemory::ReadPixel8;
m_psm[PSM_PSMT4].rp = &GSLocalMemory::ReadPixel4;
m_psm[PSM_PSMT8H].rp = &GSLocalMemory::ReadPixel8H;
m_psm[PSM_PSMT4HL].rp = &GSLocalMemory::ReadPixel4HL;
m_psm[PSM_PSMT4HH].rp = &GSLocalMemory::ReadPixel4HH;
m_psm[PSM_PSMZ32].rp = &GSLocalMemory::ReadPixel32Z;
m_psm[PSM_PSMZ24].rp = &GSLocalMemory::ReadPixel24Z;
m_psm[PSM_PSMZ16].rp = &GSLocalMemory::ReadPixel16Z;
m_psm[PSM_PSMZ16S].rp = &GSLocalMemory::ReadPixel16SZ;
m_psm[PSM_PSMCT24].rpa = &GSLocalMemory::ReadPixel24;
m_psm[PSM_PSMCT16].rpa = &GSLocalMemory::ReadPixel16;
m_psm[PSM_PSMCT16S].rpa = &GSLocalMemory::ReadPixel16;
m_psm[PSM_PSMT8].rpa = &GSLocalMemory::ReadPixel8;
m_psm[PSM_PSMT4].rpa = &GSLocalMemory::ReadPixel4;
m_psm[PSM_PSMT8H].rpa = &GSLocalMemory::ReadPixel8H;
m_psm[PSM_PSMT4HL].rpa = &GSLocalMemory::ReadPixel4HL;
m_psm[PSM_PSMT4HH].rpa = &GSLocalMemory::ReadPixel4HH;
m_psm[PSM_PSMZ32].rpa = &GSLocalMemory::ReadPixel32;
m_psm[PSM_PSMZ24].rpa = &GSLocalMemory::ReadPixel24;
m_psm[PSM_PSMZ16].rpa = &GSLocalMemory::ReadPixel16;
m_psm[PSM_PSMZ16S].rpa = &GSLocalMemory::ReadPixel16;
m_psm[PSM_PSMCT32].wp = &GSLocalMemory::WritePixel32;
m_psm[PSM_PSMCT24].wp = &GSLocalMemory::WritePixel24;
m_psm[PSM_PSMCT16].wp = &GSLocalMemory::WritePixel16;
m_psm[PSM_PSMCT16S].wp = &GSLocalMemory::WritePixel16S;
m_psm[PSM_PSMT8].wp = &GSLocalMemory::WritePixel8;
m_psm[PSM_PSMT4].wp = &GSLocalMemory::WritePixel4;
m_psm[PSM_PSMT8H].wp = &GSLocalMemory::WritePixel8H;
m_psm[PSM_PSMT4HL].wp = &GSLocalMemory::WritePixel4HL;
m_psm[PSM_PSMT4HH].wp = &GSLocalMemory::WritePixel4HH;
m_psm[PSM_PSMZ32].wp = &GSLocalMemory::WritePixel32Z;
m_psm[PSM_PSMZ24].wp = &GSLocalMemory::WritePixel24Z;
m_psm[PSM_PSMZ16].wp = &GSLocalMemory::WritePixel16Z;
m_psm[PSM_PSMZ16S].wp = &GSLocalMemory::WritePixel16SZ;
m_psm[PSM_PSMCT32].wpa = &GSLocalMemory::WritePixel32;
m_psm[PSM_PSMCT24].wpa = &GSLocalMemory::WritePixel24;
m_psm[PSM_PSMCT16].wpa = &GSLocalMemory::WritePixel16;
m_psm[PSM_PSMCT16S].wpa = &GSLocalMemory::WritePixel16;
m_psm[PSM_PSMT8].wpa = &GSLocalMemory::WritePixel8;
m_psm[PSM_PSMT4].wpa = &GSLocalMemory::WritePixel4;
m_psm[PSM_PSMT8H].wpa = &GSLocalMemory::WritePixel8H;
m_psm[PSM_PSMT4HL].wpa = &GSLocalMemory::WritePixel4HL;
m_psm[PSM_PSMT4HH].wpa = &GSLocalMemory::WritePixel4HH;
m_psm[PSM_PSMZ32].wpa = &GSLocalMemory::WritePixel32;
m_psm[PSM_PSMZ24].wpa = &GSLocalMemory::WritePixel24;
m_psm[PSM_PSMZ16].wpa = &GSLocalMemory::WritePixel16;
m_psm[PSM_PSMZ16S].wpa = &GSLocalMemory::WritePixel16;
m_psm[PSM_PSMCT24].rt = &GSLocalMemory::ReadTexel24;
m_psm[PSM_PSMCT16].rt = &GSLocalMemory::ReadTexel16;
m_psm[PSM_PSMCT16S].rt = &GSLocalMemory::ReadTexel16S;
m_psm[PSM_PSMT8].rt = &GSLocalMemory::ReadTexel8;
m_psm[PSM_PSMT4].rt = &GSLocalMemory::ReadTexel4;
m_psm[PSM_PSMT8H].rt = &GSLocalMemory::ReadTexel8H;
m_psm[PSM_PSMT4HL].rt = &GSLocalMemory::ReadTexel4HL;
m_psm[PSM_PSMT4HH].rt = &GSLocalMemory::ReadTexel4HH;
m_psm[PSM_PSMZ32].rt = &GSLocalMemory::ReadTexel32Z;
m_psm[PSM_PSMZ24].rt = &GSLocalMemory::ReadTexel24Z;
m_psm[PSM_PSMZ16].rt = &GSLocalMemory::ReadTexel16Z;
m_psm[PSM_PSMZ16S].rt = &GSLocalMemory::ReadTexel16SZ;
m_psm[PSM_PSMCT24].rta = &GSLocalMemory::ReadTexel24;
m_psm[PSM_PSMCT16].rta = &GSLocalMemory::ReadTexel16;
m_psm[PSM_PSMCT16S].rta = &GSLocalMemory::ReadTexel16;
m_psm[PSM_PSMT8].rta = &GSLocalMemory::ReadTexel8;
m_psm[PSM_PSMT4].rta = &GSLocalMemory::ReadTexel4;
m_psm[PSM_PSMT8H].rta = &GSLocalMemory::ReadTexel8H;
m_psm[PSM_PSMT4HL].rta = &GSLocalMemory::ReadTexel4HL;
m_psm[PSM_PSMT4HH].rta = &GSLocalMemory::ReadTexel4HH;
m_psm[PSM_PSMZ24].rta = &GSLocalMemory::ReadTexel24;
m_psm[PSM_PSMZ16].rta = &GSLocalMemory::ReadTexel16;
m_psm[PSM_PSMZ16S].rta = &GSLocalMemory::ReadTexel16;
m_psm[PSM_PSMCT24].wfa = &GSLocalMemory::WritePixel24;
m_psm[PSM_PSMCT16].wfa = &GSLocalMemory::WriteFrame16;
m_psm[PSM_PSMCT16S].wfa = &GSLocalMemory::WriteFrame16;
m_psm[PSM_PSMZ24].wfa = &GSLocalMemory::WritePixel24;
m_psm[PSM_PSMZ16].wfa = &GSLocalMemory::WriteFrame16;
m_psm[PSM_PSMZ16S].wfa = &GSLocalMemory::WriteFrame16;
m_psm[PSM_PSMCT24].wi = &GSLocalMemory::WriteImage24; // TODO
m_psm[PSM_PSMCT16].wi = &GSLocalMemory::WriteImage<PSM_PSMCT16, 16, 8, 16>;
m_psm[PSM_PSMCT16S].wi = &GSLocalMemory::WriteImage<PSM_PSMCT16S, 16, 8, 16>;
m_psm[PSM_PSMT8].wi = &GSLocalMemory::WriteImage<PSM_PSMT8, 16, 16, 8>;
m_psm[PSM_PSMT4].wi = &GSLocalMemory::WriteImage<PSM_PSMT4, 32, 16, 4>;
m_psm[PSM_PSMT8H].wi = &GSLocalMemory::WriteImage8H; // TODO
m_psm[PSM_PSMT4HL].wi = &GSLocalMemory::WriteImage4HL; // TODO
m_psm[PSM_PSMT4HH].wi = &GSLocalMemory::WriteImage4HH; // TODO
m_psm[PSM_PSMZ32].wi = &GSLocalMemory::WriteImage<PSM_PSMZ32, 8, 8, 32>;
m_psm[PSM_PSMZ24].wi = &GSLocalMemory::WriteImage24Z; // TODO
m_psm[PSM_PSMZ16].wi = &GSLocalMemory::WriteImage<PSM_PSMZ16, 16, 8, 16>;
m_psm[PSM_PSMZ16S].wi = &GSLocalMemory::WriteImage<PSM_PSMZ16S, 16, 8, 16>;
m_psm[PSM_PSMCT24].rtx = &GSLocalMemory::ReadTexture24;
m_psm[PSM_PSGPU24].rtx = &GSLocalMemory::ReadTextureGPU24;
m_psm[PSM_PSMCT16].rtx = &GSLocalMemory::ReadTexture16;
m_psm[PSM_PSMCT16S].rtx = &GSLocalMemory::ReadTexture16;
m_psm[PSM_PSMT8].rtx = &GSLocalMemory::ReadTexture8;
m_psm[PSM_PSMT4].rtx = &GSLocalMemory::ReadTexture4;
m_psm[PSM_PSMT8H].rtx = &GSLocalMemory::ReadTexture8H;
m_psm[PSM_PSMT4HL].rtx = &GSLocalMemory::ReadTexture4HL;
m_psm[PSM_PSMT4HH].rtx = &GSLocalMemory::ReadTexture4HH;
m_psm[PSM_PSMZ32].rtx = &GSLocalMemory::ReadTexture32;
m_psm[PSM_PSMZ24].rtx = &GSLocalMemory::ReadTexture24;
m_psm[PSM_PSMZ16].rtx = &GSLocalMemory::ReadTexture16;
m_psm[PSM_PSMZ16S].rtx = &GSLocalMemory::ReadTexture16;
m_psm[PSM_PSMCT24].rtxP = &GSLocalMemory::ReadTexture24;
m_psm[PSM_PSMCT16].rtxP = &GSLocalMemory::ReadTexture16;
m_psm[PSM_PSMCT16S].rtxP = &GSLocalMemory::ReadTexture16;
m_psm[PSM_PSMT8].rtxP = &GSLocalMemory::ReadTexture8P;
m_psm[PSM_PSMT4].rtxP = &GSLocalMemory::ReadTexture4P;
m_psm[PSM_PSMT8H].rtxP = &GSLocalMemory::ReadTexture8HP;
m_psm[PSM_PSMT4HL].rtxP = &GSLocalMemory::ReadTexture4HLP;
m_psm[PSM_PSMT4HH].rtxP = &GSLocalMemory::ReadTexture4HHP;
m_psm[PSM_PSMZ32].rtxP = &GSLocalMemory::ReadTexture32;
m_psm[PSM_PSMZ24].rtxP = &GSLocalMemory::ReadTexture24;
m_psm[PSM_PSMZ16].rtxP = &GSLocalMemory::ReadTexture16;
m_psm[PSM_PSMZ16S].rtxP = &GSLocalMemory::ReadTexture16;
m_psm[PSM_PSMCT24].rtxb = &GSLocalMemory::ReadTextureBlock24;
m_psm[PSM_PSMCT16].rtxb = &GSLocalMemory::ReadTextureBlock16;
m_psm[PSM_PSMCT16S].rtxb = &GSLocalMemory::ReadTextureBlock16;
m_psm[PSM_PSMT8].rtxb = &GSLocalMemory::ReadTextureBlock8;
m_psm[PSM_PSMT4].rtxb = &GSLocalMemory::ReadTextureBlock4;
m_psm[PSM_PSMT8H].rtxb = &GSLocalMemory::ReadTextureBlock8H;
m_psm[PSM_PSMT4HL].rtxb = &GSLocalMemory::ReadTextureBlock4HL;
m_psm[PSM_PSMT4HH].rtxb = &GSLocalMemory::ReadTextureBlock4HH;
m_psm[PSM_PSMZ32].rtxb = &GSLocalMemory::ReadTextureBlock32;
m_psm[PSM_PSMZ24].rtxb = &GSLocalMemory::ReadTextureBlock24;
m_psm[PSM_PSMZ16].rtxb = &GSLocalMemory::ReadTextureBlock16;
m_psm[PSM_PSMZ16S].rtxb = &GSLocalMemory::ReadTextureBlock16;
m_psm[PSM_PSMCT24].rtxbP = &GSLocalMemory::ReadTextureBlock24;
m_psm[PSM_PSMCT16].rtxbP = &GSLocalMemory::ReadTextureBlock16;
m_psm[PSM_PSMCT16S].rtxbP = &GSLocalMemory::ReadTextureBlock16;
m_psm[PSM_PSMT8].rtxbP = &GSLocalMemory::ReadTextureBlock8P;
m_psm[PSM_PSMT4].rtxbP = &GSLocalMemory::ReadTextureBlock4P;
m_psm[PSM_PSMT8H].rtxbP = &GSLocalMemory::ReadTextureBlock8HP;
m_psm[PSM_PSMT4HL].rtxbP = &GSLocalMemory::ReadTextureBlock4HLP;
m_psm[PSM_PSMT4HH].rtxbP = &GSLocalMemory::ReadTextureBlock4HHP;
m_psm[PSM_PSMZ32].rtxbP = &GSLocalMemory::ReadTextureBlock32;
m_psm[PSM_PSMZ24].rtxbP = &GSLocalMemory::ReadTextureBlock24;
m_psm[PSM_PSMZ16].rtxbP = &GSLocalMemory::ReadTextureBlock16;
m_psm[PSM_PSMZ16S].rtxbP = &GSLocalMemory::ReadTextureBlock16;
m_psm[PSM_PSGPU24].bpp = 16;
m_psm[PSM_PSMCT16].bpp = m_psm[PSM_PSMCT16S].bpp = 16;
m_psm[PSM_PSMT8].bpp = 8;
m_psm[PSM_PSMT4].bpp = 4;
m_psm[PSM_PSMZ16].bpp = m_psm[PSM_PSMZ16S].bpp = 16;
m_psm[PSM_PSMCT24].trbpp = 24;
m_psm[PSM_PSGPU24].trbpp = 16;
m_psm[PSM_PSMCT16].trbpp = m_psm[PSM_PSMCT16S].trbpp = 16;
m_psm[PSM_PSMT8].trbpp = m_psm[PSM_PSMT8H].trbpp = 8;
m_psm[PSM_PSMT4].trbpp = m_psm[PSM_PSMT4HL].trbpp = m_psm[PSM_PSMT4HH].trbpp = 4;
m_psm[PSM_PSMZ24].trbpp = 24;
m_psm[PSM_PSMZ16].trbpp = m_psm[PSM_PSMZ16S].trbpp = 16;
m_psm[PSM_PSMT8].pal = m_psm[PSM_PSMT8H].pal = 256;
m_psm[PSM_PSMT4].pal = m_psm[PSM_PSMT4HL].pal = m_psm[PSM_PSMT4HH].pal = 16;
for(size_t i = 0; i < countof(m_psm); i++) m_psm[i].fmt = 3;
m_psm[PSM_PSMCT32].fmt = m_psm[PSM_PSMZ32].fmt = 0;
m_psm[PSM_PSMCT24].fmt = m_psm[PSM_PSMZ24].fmt = 1;
m_psm[PSM_PSMCT16].fmt = m_psm[PSM_PSMZ16].fmt = 2;
m_psm[PSM_PSMCT16S].fmt = m_psm[PSM_PSMZ16S].fmt = 2;
m_psm[PSM_PSGPU24].bs = GSVector2i(16, 8);
m_psm[PSM_PSMCT16].bs = m_psm[PSM_PSMCT16S].bs = GSVector2i(16, 8);
m_psm[PSM_PSMT8].bs = GSVector2i(16, 16);
m_psm[PSM_PSMT4].bs = GSVector2i(32, 16);
m_psm[PSM_PSMZ16].bs = m_psm[PSM_PSMZ16S].bs = GSVector2i(16, 8);
m_psm[PSM_PSGPU24].pgs = GSVector2i(64, 64);
m_psm[PSM_PSMCT16].pgs = m_psm[PSM_PSMCT16S].pgs = GSVector2i(64, 64);
m_psm[PSM_PSMT8].pgs = GSVector2i(128, 64);
m_psm[PSM_PSMT4].pgs = GSVector2i(128, 128);
m_psm[PSM_PSMZ16].pgs = m_psm[PSM_PSMZ16S].pgs = GSVector2i(64, 64);
for(int i = 0; i < 8; i++) m_psm[PSM_PSGPU24].rowOffset[i] = rowOffset16;
for(int i = 0; i < 8; i++) m_psm[PSM_PSMCT16].rowOffset[i] = rowOffset16;
for(int i = 0; i < 8; i++) m_psm[PSM_PSMCT16S].rowOffset[i] = rowOffset16S;
for(int i = 0; i < 8; i++) m_psm[PSM_PSMT8].rowOffset[i] = rowOffset8[((i + 2) >> 2) & 1];
for(int i = 0; i < 8; i++) m_psm[PSM_PSMT4].rowOffset[i] = rowOffset4[((i + 2) >> 2) & 1];
for(int i = 0; i < 8; i++) m_psm[PSM_PSMZ32].rowOffset[i] = rowOffset32Z;
for(int i = 0; i < 8; i++) m_psm[PSM_PSMZ24].rowOffset[i] = rowOffset32Z;
for(int i = 0; i < 8; i++) m_psm[PSM_PSMZ16].rowOffset[i] = rowOffset16Z;
for(int i = 0; i < 8; i++) m_psm[PSM_PSMZ16S].rowOffset[i] = rowOffset16SZ;
m_psm[PSM_PSGPU24].blockOffset = blockOffset16;
m_psm[PSM_PSMCT16].blockOffset = blockOffset16;
m_psm[PSM_PSMCT16S].blockOffset = blockOffset16S;
m_psm[PSM_PSMT8].blockOffset = blockOffset8;
m_psm[PSM_PSMT4].blockOffset = blockOffset4;
m_psm[PSM_PSMZ32].blockOffset = blockOffset32Z;
m_psm[PSM_PSMZ24].blockOffset = blockOffset32Z;
m_psm[PSM_PSMZ16].blockOffset = blockOffset16Z;
m_psm[PSM_PSMZ16S].blockOffset = blockOffset16SZ;
m_psm[PSM_PSMCT24].msk = 0x3f;
m_psm[PSM_PSMZ24].msk = 0x3f;
m_psm[PSM_PSMT8H].msk = 0xc0;
m_psm[PSM_PSMT4HL].msk = 0x40;
m_psm[PSM_PSMT4HH].msk = 0x80;
m_psm[PSM_PSMZ32].depth = 1;
m_psm[PSM_PSMZ24].depth = 1;
m_psm[PSM_PSMZ16].depth = 1;
m_psm[PSM_PSMZ16S].depth = 1;
}
GSLocalMemory::~GSLocalMemory()
{
vmfree(m_vm8, m_vmsize * 4);
for_each(m_omap.begin(), m_omap.end(), aligned_free_second());
for_each(m_pomap.begin(), m_pomap.end(), aligned_free_second());
for_each(m_po4map.begin(), m_po4map.end(), aligned_free_second());
for(hash_map<uint64, vector<GSVector2i>*>::iterator i = m_p2tmap.begin(); i != m_p2tmap.end(); ++i)
{
delete [] i->second;
}
}
GSOffset* GSLocalMemory::GetOffset(uint32 bp, uint32 bw, uint32 psm)
{
uint32 hash = bp | (bw << 14) | (psm << 20);
hash_map<uint32, GSOffset*>::iterator i = m_omap.find(hash);
if(i != m_omap.end())
{
return i->second;
}
GSOffset* off = new GSOffset(bp, bw, psm);
m_omap[hash] = off;
return off;
}
GSPixelOffset* GSLocalMemory::GetPixelOffset(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF)
{
uint32 fbp = FRAME.Block();
uint32 zbp = ZBUF.Block();
uint32 fpsm = FRAME.PSM;
uint32 zpsm = ZBUF.PSM;
uint32 bw = FRAME.FBW;
ASSERT(m_psm[fpsm].trbpp > 8 || m_psm[zpsm].trbpp > 8);
// "(psm & 0x0f) ^ ((psm & 0xf0) >> 2)" creates 4 bit unique identifiers for render target formats (only)
uint32 fpsm_hash = (fpsm & 0x0f) ^ ((fpsm & 0x30) >> 2);
uint32 zpsm_hash = (zpsm & 0x0f) ^ ((zpsm & 0x30) >> 2);
uint32 hash = (FRAME.FBP << 0) | (ZBUF.ZBP << 9) | (bw << 18) | (fpsm_hash << 24) | (zpsm_hash << 28);
hash_map<uint32, GSPixelOffset*>::iterator i = m_pomap.find(hash);
if(i != m_pomap.end())
{
return i->second;
}
GSPixelOffset* off = (GSPixelOffset*)_aligned_malloc(sizeof(GSPixelOffset), 32);
off->hash = hash;
off->fbp = fbp;
off->zbp = zbp;
off->fpsm = fpsm;
off->zpsm = zpsm;
off->bw = bw;
pixelAddress fpa = m_psm[fpsm].pa;
pixelAddress zpa = m_psm[zpsm].pa;
int fs = m_psm[fpsm].bpp >> 5;
int zs = m_psm[zpsm].bpp >> 5;
for(int i = 0; i < 2048; i++)
{
off->row[i].x = (int)fpa(0, i, fbp, bw) << fs;
off->row[i].y = (int)zpa(0, i, zbp, bw) << zs;
}
for(int i = 0; i < 2048; i++)
{
off->col[i].x = m_psm[fpsm].rowOffset[0][i] << fs;
off->col[i].y = m_psm[zpsm].rowOffset[0][i] << zs;
}
m_pomap[hash] = off;
return off;
}
GSPixelOffset4* GSLocalMemory::GetPixelOffset4(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF)
{
uint32 fbp = FRAME.Block();
uint32 zbp = ZBUF.Block();
uint32 fpsm = FRAME.PSM;
uint32 zpsm = ZBUF.PSM;
uint32 bw = FRAME.FBW;
ASSERT(m_psm[fpsm].trbpp > 8 || m_psm[zpsm].trbpp > 8);
// "(psm & 0x0f) ^ ((psm & 0xf0) >> 2)" creates 4 bit unique identifiers for render target formats (only)
uint32 fpsm_hash = (fpsm & 0x0f) ^ ((fpsm & 0x30) >> 2);
uint32 zpsm_hash = (zpsm & 0x0f) ^ ((zpsm & 0x30) >> 2);
uint32 hash = (FRAME.FBP << 0) | (ZBUF.ZBP << 9) | (bw << 18) | (fpsm_hash << 24) | (zpsm_hash << 28);
hash_map<uint32, GSPixelOffset4*>::iterator i = m_po4map.find(hash);
if(i != m_po4map.end())
{
return i->second;
}
GSPixelOffset4* off = (GSPixelOffset4*)_aligned_malloc(sizeof(GSPixelOffset4), 32);
off->hash = hash;
off->fbp = fbp;
off->zbp = zbp;
off->fpsm = fpsm;
off->zpsm = zpsm;
off->bw = bw;
pixelAddress fpa = m_psm[fpsm].pa;
pixelAddress zpa = m_psm[zpsm].pa;
int fs = m_psm[fpsm].bpp >> 5;
int zs = m_psm[zpsm].bpp >> 5;
for(int i = 0; i < 2048; i++)
{
off->row[i].x = (int)fpa(0, i, fbp, bw) << fs;
off->row[i].y = (int)zpa(0, i, zbp, bw) << zs;
}
for(int i = 0; i < 512; i++)
{
off->col[i].x = m_psm[fpsm].rowOffset[0][i * 4] << fs;
off->col[i].y = m_psm[zpsm].rowOffset[0][i * 4] << zs;
}
m_po4map[hash] = off;
return off;
}
static bool cmp_vec2x(const GSVector2i& a, const GSVector2i& b) {return a.x < b.x;}
vector<GSVector2i>* GSLocalMemory::GetPage2TileMap(const GIFRegTEX0& TEX0)
{
uint64 hash = TEX0.u64 & 0x3ffffffffull; // TBP0 TBW PSM TW TH
hash_map<uint64, vector<GSVector2i>*>::iterator i = m_p2tmap.find(hash);
if(i != m_p2tmap.end())
{
return i->second;
}
GSVector2i bs = m_psm[TEX0.PSM].bs;
int tw = std::max<int>(1 << TEX0.TW, bs.x);
int th = std::max<int>(1 << TEX0.TH, bs.y);
const GSOffset* off = GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
hash_map<uint32, hash_set<uint32> > tmp; // key = page, value = y:x, 7 bits each, max 128x128 tiles for the worst case (1024x1024 32bpp 8x8 blocks)
for(int y = 0; y < th; y += bs.y)
{
uint32 base = off->block.row[y >> 3];
for(int x = 0, i = y << 7; x < tw; x += bs.x, i += bs.x)
{
uint32 page = (base + off->block.col[x >> 3]) >> 5;
if(page < MAX_PAGES)
{
tmp[page].insert(i >> 3); // ((y << 7) | x) >> 3
}
}
}
// combine the lower 5 bits of the address into a 9:5 pointer:mask form, so the "valid bits" can be tested against an uint32 array
vector<GSVector2i>* p2t = new vector<GSVector2i>[MAX_PAGES];
for(hash_map<uint32, hash_set<uint32> >::iterator i = tmp.begin(); i != tmp.end(); ++i)
{
uint32 page = i->first;
hash_set<uint32>& tiles = i->second;
hash_map<uint32, uint32> m;
for(hash_set<uint32>::iterator j = tiles.begin(); j != tiles.end(); ++j)
{
uint32 addr = *j;
uint32 row = addr >> 5;
uint32 col = 1 << (addr & 31);
hash_map<uint32, uint32>::iterator k = m.find(row);
if(k != m.end())
{
k->second |= col;
}
else
{
m[row] = col;
}
}
// sort by x and flip the mask (it will be used to erase a lot of bits in a loop, [x] &= ~y)
for(hash_map<uint32, uint32>::iterator j = m.begin(); j != m.end(); ++j)
{
p2t[page].push_back(GSVector2i(j->first, ~j->second));
}
std::sort(p2t[page].begin(), p2t[page].end(), cmp_vec2x);
}
m_p2tmap[hash] = p2t;
return p2t;
}
////////////////////
template<int psm, int bsx, int bsy, int alignment>
void GSLocalMemory::WriteImageColumn(int l, int r, int y, int h, const uint8* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF)
{
uint32 bp = BITBLTBUF.DBP;
uint32 bw = BITBLTBUF.DBW;
const int csy = bsy / 4;
for(int offset = srcpitch * csy; h >= csy; h -= csy, y += csy, src += offset)
{
for(int x = l; x < r; x += bsx)
{
switch(psm)
{
case PSM_PSMCT32: GSBlock::WriteColumn32<alignment, 0xffffffff>(y, BlockPtr32(x, y, bp, bw), &src[x * 4], srcpitch); break;
case PSM_PSMCT16: GSBlock::WriteColumn16<alignment>(y, BlockPtr16(x, y, bp, bw), &src[x * 2], srcpitch); break;
case PSM_PSMCT16S: GSBlock::WriteColumn16<alignment>(y, BlockPtr16S(x, y, bp, bw), &src[x * 2], srcpitch); break;
case PSM_PSMT8: GSBlock::WriteColumn8<alignment>(y, BlockPtr8(x, y, bp, bw), &src[x], srcpitch); break;
case PSM_PSMT4: GSBlock::WriteColumn4<alignment>(y, BlockPtr4(x, y, bp, bw), &src[x >> 1], srcpitch); break;
case PSM_PSMZ32: GSBlock::WriteColumn32<alignment, 0xffffffff>(y, BlockPtr32Z(x, y, bp, bw), &src[x * 4], srcpitch); break;
case PSM_PSMZ16: GSBlock::WriteColumn16<alignment>(y, BlockPtr16Z(x, y, bp, bw), &src[x * 2], srcpitch); break;
case PSM_PSMZ16S: GSBlock::WriteColumn16<alignment>(y, BlockPtr16SZ(x, y, bp, bw), &src[x * 2], srcpitch); break;
// TODO
default: __assume(0);
}
}
}
}
template<int psm, int bsx, int bsy, int alignment>
void GSLocalMemory::WriteImageBlock(int l, int r, int y, int h, const uint8* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF)
{
uint32 bp = BITBLTBUF.DBP;
uint32 bw = BITBLTBUF.DBW;
for(int offset = srcpitch * bsy; h >= bsy; h -= bsy, y += bsy, src += offset)
{
for(int x = l; x < r; x += bsx)
{
switch(psm)
{
case PSM_PSMCT32: GSBlock::WriteBlock32<alignment, 0xffffffff>(BlockPtr32(x, y, bp, bw), &src[x * 4], srcpitch); break;
case PSM_PSMCT16: GSBlock::WriteBlock16<alignment>(BlockPtr16(x, y, bp, bw), &src[x * 2], srcpitch); break;
case PSM_PSMCT16S: GSBlock::WriteBlock16<alignment>(BlockPtr16S(x, y, bp, bw), &src[x * 2], srcpitch); break;
case PSM_PSMT8: GSBlock::WriteBlock8<alignment>(BlockPtr8(x, y, bp, bw), &src[x], srcpitch); break;
case PSM_PSMT4: GSBlock::WriteBlock4<alignment>(BlockPtr4(x, y, bp, bw), &src[x >> 1], srcpitch); break;
case PSM_PSMZ32: GSBlock::WriteBlock32<alignment, 0xffffffff>(BlockPtr32Z(x, y, bp, bw), &src[x * 4], srcpitch); break;
case PSM_PSMZ16: GSBlock::WriteBlock16<alignment>(BlockPtr16Z(x, y, bp, bw), &src[x * 2], srcpitch); break;
case PSM_PSMZ16S: GSBlock::WriteBlock16<alignment>(BlockPtr16SZ(x, y, bp, bw), &src[x * 2], srcpitch); break;
// TODO
default: __assume(0);
}
}
}
}
template<int psm, int bsx, int bsy>
void GSLocalMemory::WriteImageLeftRight(int l, int r, int y, int h, const uint8* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF)
{
uint32 bp = BITBLTBUF.DBP;
uint32 bw = BITBLTBUF.DBW;
for(; h > 0; y++, h--, src += srcpitch)
{
for(int x = l; x < r; x++)
{
switch(psm)
{
case PSM_PSMCT32: WritePixel32(x, y, *(uint32*)&src[x * 4], bp, bw); break;
case PSM_PSMCT16: WritePixel16(x, y, *(uint16*)&src[x * 2], bp, bw); break;
case PSM_PSMCT16S: WritePixel16S(x, y, *(uint16*)&src[x * 2], bp, bw); break;
case PSM_PSMT8: WritePixel8(x, y, src[x], bp, bw); break;
case PSM_PSMT4: WritePixel4(x, y, src[x >> 1] >> ((x & 1) << 2), bp, bw); break;
case PSM_PSMZ32: WritePixel32Z(x, y, *(uint32*)&src[x * 4], bp, bw); break;
case PSM_PSMZ16: WritePixel16Z(x, y, *(uint16*)&src[x * 2], bp, bw); break;
case PSM_PSMZ16S: WritePixel16SZ(x, y, *(uint16*)&src[x * 2], bp, bw); break;
// TODO
default: __assume(0);
}
}
}
}
template<int psm, int bsx, int bsy, int trbpp>
void GSLocalMemory::WriteImageTopBottom(int l, int r, int y, int h, const uint8* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF)
{
alignas(32) uint8 buff[64]; // merge buffer for one column
uint32 bp = BITBLTBUF.DBP;
uint32 bw = BITBLTBUF.DBW;
const int csy = bsy / 4;
// merge incomplete column
int y2 = y & (csy - 1);
if(y2 > 0)
{
int h2 = min(h, csy - y2);
for(int x = l; x < r; x += bsx)
{
uint8* dst = NULL;
switch(psm)
{
case PSM_PSMCT32: dst = BlockPtr32(x, y, bp, bw); break;
case PSM_PSMCT16: dst = BlockPtr16(x, y, bp, bw); break;
case PSM_PSMCT16S: dst = BlockPtr16S(x, y, bp, bw); break;
case PSM_PSMT8: dst = BlockPtr8(x, y, bp, bw); break;
case PSM_PSMT4: dst = BlockPtr4(x, y, bp, bw); break;
case PSM_PSMZ32: dst = BlockPtr32Z(x, y, bp, bw); break;
case PSM_PSMZ16: dst = BlockPtr16Z(x, y, bp, bw); break;
case PSM_PSMZ16S: dst = BlockPtr16SZ(x, y, bp, bw); break;
// TODO
default: __assume(0);
}
switch(psm)
{
case PSM_PSMCT32:
case PSM_PSMZ32:
GSBlock::ReadColumn32(y, dst, buff, 32);
memcpy(&buff[32], &src[x * 4], 32);
GSBlock::WriteColumn32<32, 0xffffffff>(y, dst, buff, 32);
break;
case PSM_PSMCT16:
case PSM_PSMCT16S:
case PSM_PSMZ16:
case PSM_PSMZ16S:
GSBlock::ReadColumn16(y, dst, buff, 32);
memcpy(&buff[32], &src[x * 2], 32);
GSBlock::WriteColumn16<32>(y, dst, buff, 32);
break;
case PSM_PSMT8:
GSBlock::ReadColumn8(y, dst, buff, 16);
for(int i = 0, j = y2; i < h2; i++, j++) memcpy(&buff[j * 16], &src[i * srcpitch + x], 16);
GSBlock::WriteColumn8<32>(y, dst, buff, 16);
break;
case PSM_PSMT4:
GSBlock::ReadColumn4(y, dst, buff, 16);
for(int i = 0, j = y2; i < h2; i++, j++) memcpy(&buff[j * 16], &src[i * srcpitch + (x >> 1)], 16);
GSBlock::WriteColumn4<32>(y, dst, buff, 16);
break;
// TODO
default:
__assume(0);
}
}
src += srcpitch * h2;
y += h2;
h -= h2;
}
// write whole columns
{
int h2 = h & ~(csy - 1);
if(h2 > 0)
{
size_t addr = (size_t)&src[l * trbpp >> 3];
if((addr & 31) == 0 && (srcpitch & 31) == 0)
{
WriteImageColumn<psm, bsx, bsy, 32>(l, r, y, h2, src, srcpitch, BITBLTBUF);
}
else if((addr & 15) == 0 && (srcpitch & 15) == 0)
{
WriteImageColumn<psm, bsx, bsy, 16>(l, r, y, h2, src, srcpitch, BITBLTBUF);
}
else
{
WriteImageColumn<psm, bsx, bsy, 0>(l, r, y, h2, src, srcpitch, BITBLTBUF);
}
src += srcpitch * h2;
y += h2;
h -= h2;
}
}
// merge incomplete column
if(h >= 1)
{
for(int x = l; x < r; x += bsx)
{
uint8* dst = NULL;
switch(psm)
{
case PSM_PSMCT32: dst = BlockPtr32(x, y, bp, bw); break;
case PSM_PSMCT16: dst = BlockPtr16(x, y, bp, bw); break;
case PSM_PSMCT16S: dst = BlockPtr16S(x, y, bp, bw); break;
case PSM_PSMT8: dst = BlockPtr8(x, y, bp, bw); break;
case PSM_PSMT4: dst = BlockPtr4(x, y, bp, bw); break;
case PSM_PSMZ32: dst = BlockPtr32Z(x, y, bp, bw); break;
case PSM_PSMZ16: dst = BlockPtr16Z(x, y, bp, bw); break;
case PSM_PSMZ16S: dst = BlockPtr16SZ(x, y, bp, bw); break;
// TODO
default: __assume(0);
}
switch(psm)
{
case PSM_PSMCT32:
case PSM_PSMZ32:
GSBlock::ReadColumn32(y, dst, buff, 32);
memcpy(&buff[0], &src[x * 4], 32);
GSBlock::WriteColumn32<32, 0xffffffff>(y, dst, buff, 32);
break;
case PSM_PSMCT16:
case PSM_PSMCT16S:
case PSM_PSMZ16:
case PSM_PSMZ16S:
GSBlock::ReadColumn16(y, dst, buff, 32);
memcpy(&buff[0], &src[x * 2], 32);
GSBlock::WriteColumn16<32>(y, dst, buff, 32);
break;
case PSM_PSMT8:
GSBlock::ReadColumn8(y, dst, buff, 16);
for(int i = 0; i < h; i++) memcpy(&buff[i * 16], &src[i * srcpitch + x], 16);
GSBlock::WriteColumn8<32>(y, dst, buff, 16);
break;
case PSM_PSMT4:
GSBlock::ReadColumn4(y, dst, buff, 16);
for(int i = 0; i < h; i++) memcpy(&buff[i * 16], &src[i * srcpitch + (x >> 1)], 16);
GSBlock::WriteColumn4<32>(y, dst, buff, 16);
break;
// TODO
default:
__assume(0);
}
}
}
}
template<int psm, int bsx, int bsy, int trbpp>
void GSLocalMemory::WriteImage(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG)
{
if(TRXREG.RRW == 0) return;
int l = (int)TRXPOS.DSAX;
int r = l + (int)TRXREG.RRW;
// finish the incomplete row first
if(tx != l)
{
int n = min(len, (r - tx) * trbpp >> 3);
WriteImageX(tx, ty, src, n, BITBLTBUF, TRXPOS, TRXREG);
src += n;
len -= n;
}
int la = (l + (bsx - 1)) & ~(bsx - 1);
int ra = r & ~(bsx - 1);
int srcpitch = (r - l) * trbpp >> 3;
int h = len / srcpitch;
if(ra - la >= bsx && h > 0) // "transfer width" >= "block width" && there is at least one full row
{
const uint8* s = &src[-l * trbpp >> 3];
src += srcpitch * h;
len -= srcpitch * h;
// left part
if(l < la)
{
WriteImageLeftRight<psm, bsx, bsy>(l, la, ty, h, s, srcpitch, BITBLTBUF);
}
// right part
if(ra < r)
{
WriteImageLeftRight<psm, bsx, bsy>(ra, r, ty, h, s, srcpitch, BITBLTBUF);
}
// horizontally aligned part
if(la < ra)
{
// top part
{
int h2 = min(h, bsy - (ty & (bsy - 1)));
if(h2 < bsy)
{
WriteImageTopBottom<psm, bsx, bsy, trbpp>(la, ra, ty, h2, s, srcpitch, BITBLTBUF);
s += srcpitch * h2;
ty += h2;
h -= h2;
}
}
// horizontally and vertically aligned part
{
int h2 = h & ~(bsy - 1);
if(h2 > 0)
{
size_t addr = (size_t)&s[la * trbpp >> 3];
if((addr & 31) == 0 && (srcpitch & 31) == 0)
{
WriteImageBlock<psm, bsx, bsy, 32>(la, ra, ty, h2, s, srcpitch, BITBLTBUF);
}
else if((addr & 15) == 0 && (srcpitch & 15) == 0)
{
WriteImageBlock<psm, bsx, bsy, 16>(la, ra, ty, h2, s, srcpitch, BITBLTBUF);
}
else
{
WriteImageBlock<psm, bsx, bsy, 0>(la, ra, ty, h2, s, srcpitch, BITBLTBUF);
}
s += srcpitch * h2;
ty += h2;
h -= h2;
}
}
// bottom part
if(h > 0)
{
WriteImageTopBottom<psm, bsx, bsy, trbpp>(la, ra, ty, h, s, srcpitch, BITBLTBUF);
// s += srcpitch * h;
ty += h;
// h -= h;
}
}
}
// the rest
if(len > 0)
{
WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG);
}
}
static bool IsTopLeftAligned(int dsax, int tx, int ty, int bw, int bh)
{
return ((dsax & (bw-1)) == 0 && (tx & (bw-1)) == 0 && dsax == tx && (ty & (bh-1)) == 0);
}
void GSLocalMemory::WriteImage24(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG)
{
if(TRXREG.RRW == 0) return;
uint32 bp = BITBLTBUF.DBP;
uint32 bw = BITBLTBUF.DBW;
int tw = TRXPOS.DSAX + TRXREG.RRW, srcpitch = TRXREG.RRW * 3;
int th = len / srcpitch;
bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8);
if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch))
{
// TODO
WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG);
}
else
{
th += ty;
for(int y = ty; y < th; y += 8, src += srcpitch * 8)
{
for(int x = tx; x < tw; x += 8)
{
GSBlock::UnpackAndWriteBlock24(src + (x - tx) * 3, srcpitch, BlockPtr32(x, y, bp, bw));
}
}
ty = th;
}
}
void GSLocalMemory::WriteImage8H(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG)
{
if(TRXREG.RRW == 0) return;
uint32 bp = BITBLTBUF.DBP;
uint32 bw = BITBLTBUF.DBW;
int tw = TRXPOS.DSAX + TRXREG.RRW, srcpitch = TRXREG.RRW;
int th = len / srcpitch;
bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8);
if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch))
{
// TODO
WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG);
}
else
{
th += ty;
for(int y = ty; y < th; y += 8, src += srcpitch * 8)
{
for(int x = tx; x < tw; x += 8)
{
GSBlock::UnpackAndWriteBlock8H(src + (x - tx), srcpitch, BlockPtr32(x, y, bp, bw));
}
}
ty = th;
}
}
void GSLocalMemory::WriteImage4HL(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG)
{
if(TRXREG.RRW == 0) return;
uint32 bp = BITBLTBUF.DBP;
uint32 bw = BITBLTBUF.DBW;
int tw = TRXPOS.DSAX + TRXREG.RRW, srcpitch = TRXREG.RRW / 2;
int th = len / srcpitch;
bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8);
if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch))
{
// TODO
WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG);
}
else
{
th += ty;
for(int y = ty; y < th; y += 8, src += srcpitch * 8)
{
for(int x = tx; x < tw; x += 8)
{
GSBlock::UnpackAndWriteBlock4HL(src + (x - tx) / 2, srcpitch, BlockPtr32(x, y, bp, bw));
}
}
ty = th;
}
}
void GSLocalMemory::WriteImage4HH(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG)
{
if(TRXREG.RRW == 0) return;
uint32 bp = BITBLTBUF.DBP;
uint32 bw = BITBLTBUF.DBW;
int tw = TRXPOS.DSAX + TRXREG.RRW, srcpitch = TRXREG.RRW / 2;
int th = len / srcpitch;
bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8);
if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch))
{
// TODO
WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG);
}
else
{
th += ty;
for(int y = ty; y < th; y += 8, src += srcpitch * 8)
{
for(int x = tx; x < tw; x += 8)
{
GSBlock::UnpackAndWriteBlock4HH(src + (x - tx) / 2, srcpitch, BlockPtr32(x, y, bp, bw));
}
}
ty = th;
}
}
void GSLocalMemory::WriteImage24Z(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG)
{
if(TRXREG.RRW == 0) return;
uint32 bp = BITBLTBUF.DBP;
uint32 bw = BITBLTBUF.DBW;
int tw = TRXPOS.DSAX + TRXREG.RRW, srcpitch = TRXREG.RRW * 3;
int th = len / srcpitch;
bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8);
if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch))
{
// TODO
WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG);
}
else
{
th += ty;
for(int y = ty; y < th; y += 8, src += srcpitch * 8)
{
for(int x = tx; x < tw; x += 8)
{
GSBlock::UnpackAndWriteBlock24(src + (x - tx) * 3, srcpitch, BlockPtr32Z(x, y, bp, bw));
}
}
ty = th;
}
}
void GSLocalMemory::WriteImageX(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG)
{
if(len <= 0) return;
const uint8* pb = (uint8*)src;
const uint16* pw = (uint16*)src;
const uint32* pd = (uint32*)src;
uint32 bp = BITBLTBUF.DBP;
uint32 bw = BITBLTBUF.DBW;
psm_t* psm = &m_psm[BITBLTBUF.DPSM];
int x = tx;
int y = ty;
int sx = (int)TRXPOS.DSAX;
int ex = sx + (int)TRXREG.RRW;
switch(BITBLTBUF.DPSM)
{
case PSM_PSMCT32:
case PSM_PSMZ32:
len /= 4;
while(len > 0)
{
uint32 addr = psm->pa(0, y, bp, bw);
int* offset = psm->rowOffset[y & 7];
for(; len > 0 && x < ex; len--, x++, pd++)
{
WritePixel32(addr + offset[x], *pd);
}
if(x >= ex) {x = sx; y++;}
}
break;
case PSM_PSMCT24:
case PSM_PSMZ24:
len /= 3;
while(len > 0)
{
uint32 addr = psm->pa(0, y, bp, bw);
int* offset = psm->rowOffset[y & 7];
for(; len > 0 && x < ex; len--, x++, pb += 3)
{
WritePixel24(addr + offset[x], *(uint32*)pb);
}
if(x >= ex) {x = sx; y++;}
}
break;
case PSM_PSMCT16:
case PSM_PSMCT16S:
case PSM_PSMZ16:
case PSM_PSMZ16S:
len /= 2;
while(len > 0)
{
uint32 addr = psm->pa(0, y, bp, bw);
int* offset = psm->rowOffset[y & 7];
for(; len > 0 && x < ex; len--, x++, pw++)
{
WritePixel16(addr + offset[x], *pw);
}
if(x >= ex) {x = sx; y++;}
}
break;
case PSM_PSMT8:
while(len > 0)
{
uint32 addr = psm->pa(0, y, bp, bw);
int* offset = psm->rowOffset[y & 7];
for(; len > 0 && x < ex; len--, x++, pb++)
{
WritePixel8(addr + offset[x], *pb);
}
if(x >= ex) {x = sx; y++;}
}
break;
case PSM_PSMT4:
while(len > 0)
{
uint32 addr = psm->pa(0, y, bp, bw);
int* offset = psm->rowOffset[y & 7];
for(; len > 0 && x < ex; len--, x += 2, pb++)
{
WritePixel4(addr + offset[x + 0], *pb & 0xf);
WritePixel4(addr + offset[x + 1], *pb >> 4);
}
if(x >= ex) {x = sx; y++;}
}
break;
case PSM_PSMT8H:
while(len > 0)
{
uint32 addr = psm->pa(0, y, bp, bw);
int* offset = psm->rowOffset[y & 7];
for(; len > 0 && x < ex; len--, x++, pb++)
{
WritePixel8H(addr + offset[x], *pb);
}
if(x >= ex) {x = sx; y++;}
}
break;
case PSM_PSMT4HL:
while(len > 0)
{
uint32 addr = psm->pa(0, y, bp, bw);
int* offset = psm->rowOffset[y & 7];
for(; len > 0 && x < ex; len--, x += 2, pb++)
{
WritePixel4HL(addr + offset[x + 0], *pb & 0xf);
WritePixel4HL(addr + offset[x + 1], *pb >> 4);
}
if(x >= ex) {x = sx; y++;}
}
break;
case PSM_PSMT4HH:
while(len > 0)
{
uint32 addr = psm->pa(0, y, bp, bw);
int* offset = psm->rowOffset[y & 7];
for(; len > 0 && x < ex; len--, x += 2, pb++)
{
WritePixel4HH(addr + offset[x + 0], *pb & 0xf);
WritePixel4HH(addr + offset[x + 1], *pb >> 4);
}
if(x >= ex) {x = sx; y++;}
}
break;
}
tx = x;
ty = y;
}
//
void GSLocalMemory::ReadImageX(int& tx, int& ty, uint8* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) const
{
if(len <= 0) return;
uint8* RESTRICT pb = (uint8*)dst;
uint16* RESTRICT pw = (uint16*)dst;
uint32* RESTRICT pd = (uint32*)dst;
uint32 bp = BITBLTBUF.SBP;
uint32 bw = BITBLTBUF.SBW;
psm_t* RESTRICT psm = &m_psm[BITBLTBUF.SPSM];
int x = tx;
int y = ty;
int sx = (int)TRXPOS.SSAX;
int ex = sx + (int)TRXREG.RRW;
// printf("spsm=%d x=%d ex=%d y=%d len=%d\n", BITBLTBUF.SPSM, x, ex, y, len);
switch(BITBLTBUF.SPSM)
{
case PSM_PSMCT32:
case PSM_PSMZ32:
// MGS1 intro, fade effect between two scenes (airplane outside-inside transition)
len /= 4;
while(len > 0)
{
int* RESTRICT offset = psm->rowOffset[y & 7];
uint32* RESTRICT ps = &m_vm32[psm->pa(0, y, bp, bw)];
for(; len > 0 && x < ex && (x & 7); len--, x++, pd++)
{
*pd = ps[offset[x]];
}
// aligned to a column
for(int ex8 = ex - 8; len >= 8 && x <= ex8; len -= 8, x += 8, pd += 8)
{
int off = offset[x];
GSVector4i::store<false>(&pd[0], GSVector4i::load(&ps[off + 0], &ps[off + 4]));
GSVector4i::store<false>(&pd[4], GSVector4i::load(&ps[off + 8], &ps[off + 12]));
for(int i = 0; i < 8; i++) ASSERT(pd[i] == ps[offset[x + i]]);
}
for(; len > 0 && x < ex; len--, x++, pd++)
{
*pd = ps[offset[x]];
}
if(x == ex) {x = sx; y++;}
}
break;
case PSM_PSMCT24:
case PSM_PSMZ24:
len /= 3;
while(len > 0)
{
int* RESTRICT offset = psm->rowOffset[y & 7];
uint32* RESTRICT ps = &m_vm32[psm->pa(0, y, bp, bw)];
for(; len > 0 && x < ex; len--, x++, pb += 3)
{
uint32 c = ps[offset[x]];
pb[0] = (uint8)(c);
pb[1] = (uint8)(c >> 8);
pb[2] = (uint8)(c >> 16);
}
if(x == ex) {x = sx; y++;}
}
break;
case PSM_PSMCT16:
case PSM_PSMCT16S:
case PSM_PSMZ16:
case PSM_PSMZ16S:
len /= 2;
while(len > 0)
{
int* RESTRICT offset = psm->rowOffset[y & 7];
uint16* RESTRICT ps = &m_vm16[psm->pa(0, y, bp, bw)];
for(int ex4 = ex - 4; len >= 4 && x <= ex4; len -= 4, x += 4, pw += 4)
{
pw[0] = ps[offset[x + 0]];
pw[1] = ps[offset[x + 1]];
pw[2] = ps[offset[x + 2]];
pw[3] = ps[offset[x + 3]];
}
for(; len > 0 && x < ex; len--, x++, pw++)
{
*pw = ps[offset[x]];
}
if(x == ex) {x = sx; y++;}
}
break;
case PSM_PSMT8:
while(len > 0)
{
int* RESTRICT offset = psm->rowOffset[y & 7];
uint8* RESTRICT ps = &m_vm8[psm->pa(0, y, bp, bw)];
for(int ex4 = ex - 4; len >= 4 && x <= ex4; len -= 4, x += 4, pb += 4)
{
pb[0] = ps[offset[x + 0]];
pb[1] = ps[offset[x + 1]];
pb[2] = ps[offset[x + 2]];
pb[3] = ps[offset[x + 3]];
}
for(; len > 0 && x < ex; len--, x++, pb++)
{
*pb = ps[offset[x]];
}
if(x == ex) {x = sx; y++;}
}
break;
case PSM_PSMT4:
while(len > 0)
{
uint32 addr = psm->pa(0, y, bp, bw);
int* RESTRICT offset = psm->rowOffset[y & 7];
for(; len > 0 && x < ex; len--, x += 2, pb++)
{
*pb = (uint8)(ReadPixel4(addr + offset[x + 0]) | (ReadPixel4(addr + offset[x + 1]) << 4));
}
if(x == ex) {x = sx; y++;}
}
break;
case PSM_PSMT8H:
while(len > 0)
{
int* RESTRICT offset = psm->rowOffset[y & 7];
uint32* RESTRICT ps = &m_vm32[psm->pa(0, y, bp, bw)];
for(int ex4 = ex - 4; len >= 4 && x <= ex4; len -= 4, x += 4, pb += 4)
{
pb[0] = (uint8)(ps[offset[x + 0]] >> 24);
pb[1] = (uint8)(ps[offset[x + 1]] >> 24);
pb[2] = (uint8)(ps[offset[x + 2]] >> 24);
pb[3] = (uint8)(ps[offset[x + 3]] >> 24);
}
for(; len > 0 && x < ex; len--, x++, pb++)
{
*pb = (uint8)(ps[offset[x]] >> 24);
}
if(x == ex) {x = sx; y++;}
}
break;
case PSM_PSMT4HL:
while(len > 0)
{
int* offset = psm->rowOffset[y & 7];
uint32* RESTRICT ps = &m_vm32[psm->pa(0, y, bp, bw)];
for(; len > 0 && x < ex; len--, x += 2, pb++)
{
uint32 c0 = (ps[offset[x + 0]] >> 24) & 0x0f;
uint32 c1 = (ps[offset[x + 1]] >> 20) & 0xf0;
*pb = (uint8)(c0 | c1);
}
if(x == ex) {x = sx; y++;}
}
break;
case PSM_PSMT4HH:
while(len > 0)
{
int* RESTRICT offset = psm->rowOffset[y & 7];
uint32* RESTRICT ps = &m_vm32[psm->pa(0, y, bp, bw)];
for(; len > 0 && x < ex; len--, x += 2, pb++)
{
uint32 c0 = (ps[offset[x + 0]] >> 28) & 0x0f;
uint32 c1 = (ps[offset[x + 1]] >> 24) & 0xf0;
*pb = (uint8)(c0 | c1);
}
if(x == ex) {x = sx; y++;}
}
break;
}
tx = x;
ty = y;
}
///////////////////
void GSLocalMemory::ReadTexture32(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
FOREACH_BLOCK_START(r, 8, 8, 32)
{
GSBlock::ReadBlock32(src, read_dst, dstpitch);
}
FOREACH_BLOCK_END
}
void GSLocalMemory::ReadTexture24(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
if(TEXA.AEM)
{
FOREACH_BLOCK_START(r, 8, 8, 32)
{
GSBlock::ReadAndExpandBlock24<true>(src, read_dst, dstpitch, TEXA);
}
FOREACH_BLOCK_END
}
else
{
FOREACH_BLOCK_START(r, 8, 8, 32)
{
GSBlock::ReadAndExpandBlock24<false>(src, read_dst, dstpitch, TEXA);
}
FOREACH_BLOCK_END
}
}
void GSLocalMemory::ReadTextureGPU24(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
FOREACH_BLOCK_START(r, 16, 8, 16)
{
GSBlock::ReadBlock16(src, read_dst, dstpitch);
}
FOREACH_BLOCK_END
// Convert packed RGB scanline to 32 bits RGBA
ASSERT(dstpitch >= r.width() * 4);
for(int y = r.top; y < r.bottom; y ++) {
uint8* line = dst + y * dstpitch;
for(int x = r.right; x >= r.left; x--) {
*(uint32*)&line[x * 4] = *(uint32*)&line[x * 3] & 0xFFFFFF;
}
}
}
void GSLocalMemory::ReadTexture16(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
if(TEXA.AEM)
{
FOREACH_BLOCK_START(r, 16, 8, 32)
{
GSBlock::ReadAndExpandBlock16<true>(src, read_dst, dstpitch, TEXA);
}
FOREACH_BLOCK_END
}
else
{
FOREACH_BLOCK_START(r, 16, 8, 32)
{
GSBlock::ReadAndExpandBlock16<false>(src, read_dst, dstpitch, TEXA);
}
FOREACH_BLOCK_END
}
}
void GSLocalMemory::ReadTexture8(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
const uint32* pal = m_clut;
FOREACH_BLOCK_START(r, 16, 16, 32)
{
GSBlock::ReadAndExpandBlock8_32(src, read_dst, dstpitch, pal);
}
FOREACH_BLOCK_END
}
void GSLocalMemory::ReadTexture4(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
const uint64* pal = m_clut;
FOREACH_BLOCK_START(r, 32, 16, 32)
{
GSBlock::ReadAndExpandBlock4_32(src, read_dst, dstpitch, pal);
}
FOREACH_BLOCK_END
}
void GSLocalMemory::ReadTexture8H(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
const uint32* pal = m_clut;
FOREACH_BLOCK_START(r, 8, 8, 32)
{
GSBlock::ReadAndExpandBlock8H_32(src, read_dst, dstpitch, pal);
}
FOREACH_BLOCK_END
}
void GSLocalMemory::ReadTexture4HL(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
const uint32* pal = m_clut;
FOREACH_BLOCK_START(r, 8, 8, 32)
{
GSBlock::ReadAndExpandBlock4HL_32(src, read_dst, dstpitch, pal);
}
FOREACH_BLOCK_END
}
void GSLocalMemory::ReadTexture4HH(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
const uint32* pal = m_clut;
FOREACH_BLOCK_START(r, 8, 8, 32)
{
GSBlock::ReadAndExpandBlock4HH_32(src, read_dst, dstpitch, pal);
}
FOREACH_BLOCK_END
}
///////////////////
void GSLocalMemory::ReadTextureBlock32(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(32);
GSBlock::ReadBlock32(BlockPtr(bp), dst, dstpitch);
}
void GSLocalMemory::ReadTextureBlock24(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(32);
if(TEXA.AEM)
{
GSBlock::ReadAndExpandBlock24<true>(BlockPtr(bp), dst, dstpitch, TEXA);
}
else
{
GSBlock::ReadAndExpandBlock24<false>(BlockPtr(bp), dst, dstpitch, TEXA);
}
}
void GSLocalMemory::ReadTextureBlock16(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(32);
if(TEXA.AEM)
{
GSBlock::ReadAndExpandBlock16<true>(BlockPtr(bp), dst, dstpitch, TEXA);
}
else
{
GSBlock::ReadAndExpandBlock16<false>(BlockPtr(bp), dst, dstpitch, TEXA);
}
}
void GSLocalMemory::ReadTextureBlock8(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(32);
GSBlock::ReadAndExpandBlock8_32(BlockPtr(bp), dst, dstpitch, m_clut);
}
void GSLocalMemory::ReadTextureBlock4(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(32);
GSBlock::ReadAndExpandBlock4_32(BlockPtr(bp), dst, dstpitch, m_clut);
}
void GSLocalMemory::ReadTextureBlock8H(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(32);
GSBlock::ReadAndExpandBlock8H_32(BlockPtr(bp), dst, dstpitch, m_clut);
}
void GSLocalMemory::ReadTextureBlock4HL(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(32);
GSBlock::ReadAndExpandBlock4HL_32(BlockPtr(bp), dst, dstpitch, m_clut);
}
void GSLocalMemory::ReadTextureBlock4HH(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(32);
GSBlock::ReadAndExpandBlock4HH_32(BlockPtr(bp), dst, dstpitch, m_clut);
}
///////////////////
void GSLocalMemory::ReadTexture(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
const psm_t& psm = m_psm[off->psm];
readTexel rt = psm.rt;
readTexture rtx = psm.rtx;
if(r.width() < psm.bs.x || r.height() < psm.bs.y
|| (r.left & (psm.bs.x - 1)) || (r.top & (psm.bs.y - 1))
|| (r.right & (psm.bs.x - 1)) || (r.bottom & (psm.bs.y - 1)))
{
GIFRegTEX0 TEX0;
TEX0.TBP0 = off->bp;
TEX0.TBW = off->bw;
TEX0.PSM = off->psm;
GSVector4i cr = r.ralign<Align_Inside>(psm.bs);
bool aligned = ((size_t)(dst + (cr.left - r.left) * sizeof(uint32)) & 0xf) == 0;
if(cr.rempty() || !aligned)
{
// TODO: expand r to block size, read into temp buffer
if(!aligned) printf("unaligned memory pointer passed to ReadTexture\n");
for(int y = r.top; y < r.bottom; y++, dst += dstpitch)
{
for(int x = r.left, i = 0; x < r.right; x++, i++)
{
((uint32*)dst)[i] = (this->*rt)(x, y, TEX0, TEXA);
}
}
}
else
{
for(int y = r.top; y < cr.top; y++, dst += dstpitch)
{
for(int x = r.left, i = 0; x < r.right; x++, i++)
{
((uint32*)dst)[i] = (this->*rt)(x, y, TEX0, TEXA);
}
}
for(int y = cr.bottom; y < r.bottom; y++, dst += dstpitch)
{
for(int x = r.left, i = 0; x < r.right; x++, i++)
{
((uint32*)dst)[i] = (this->*rt)(x, y, TEX0, TEXA);
}
}
for(int y = cr.top; y < cr.bottom; y++, dst += dstpitch)
{
for(int x = r.left, i = 0; x < cr.left; x++, i++)
{
((uint32*)dst)[i] = (this->*rt)(x, y, TEX0, TEXA);
}
for(int x = cr.right, i = x - r.left; x < r.right; x++, i++)
{
((uint32*)dst)[i] = (this->*rt)(x, y, TEX0, TEXA);
}
}
if(!cr.rempty())
{
(this->*rtx)(off, cr, dst + (cr.left - r.left) * sizeof(uint32), dstpitch, TEXA);
}
}
}
else
{
(this->*rtx)(off, r, dst, dstpitch, TEXA);
}
}
// 32/8
void GSLocalMemory::ReadTexture8P(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
FOREACH_BLOCK_START(r, 16, 16, 8)
{
GSBlock::ReadBlock8(src, read_dst, dstpitch);
}
FOREACH_BLOCK_END
}
void GSLocalMemory::ReadTexture4P(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
FOREACH_BLOCK_START(r, 32, 16, 8)
{
GSBlock::ReadBlock4P(src, read_dst, dstpitch);
}
FOREACH_BLOCK_END
}
void GSLocalMemory::ReadTexture8HP(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
FOREACH_BLOCK_START(r, 8, 8, 8)
{
GSBlock::ReadBlock8HP(src, read_dst, dstpitch);
}
FOREACH_BLOCK_END
}
void GSLocalMemory::ReadTexture4HLP(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
FOREACH_BLOCK_START(r, 8, 8, 8)
{
GSBlock::ReadBlock4HLP(src, read_dst, dstpitch);
}
FOREACH_BLOCK_END
}
void GSLocalMemory::ReadTexture4HHP(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA)
{
FOREACH_BLOCK_START(r, 8, 8, 8)
{
GSBlock::ReadBlock4HHP(src, read_dst, dstpitch);
}
FOREACH_BLOCK_END
}
//
void GSLocalMemory::ReadTextureBlock8P(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
GSBlock::ReadBlock8(BlockPtr(bp), dst, dstpitch);
}
void GSLocalMemory::ReadTextureBlock4P(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(32);
GSBlock::ReadBlock4P(BlockPtr(bp), dst, dstpitch);
}
void GSLocalMemory::ReadTextureBlock8HP(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(32);
GSBlock::ReadBlock8HP(BlockPtr(bp), dst, dstpitch);
}
void GSLocalMemory::ReadTextureBlock4HLP(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(32);
GSBlock::ReadBlock4HLP(BlockPtr(bp), dst, dstpitch);
}
void GSLocalMemory::ReadTextureBlock4HHP(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(32);
GSBlock::ReadBlock4HHP(BlockPtr(bp), dst, dstpitch);
}
//
#include "GSTextureSW.h"
void GSLocalMemory::SaveBMP(const string& fn, uint32 bp, uint32 bw, uint32 psm, int w, int h)
{
int pitch = w * 4;
int size = pitch * h;
void* bits = _aligned_malloc(size, 32);
GIFRegTEX0 TEX0;
TEX0.TBP0 = bp;
TEX0.TBW = bw;
TEX0.PSM = psm;
readPixel rp = m_psm[psm].rp;
uint8* p = (uint8*)bits;
for(int j = 0; j < h; j++, p += pitch)
{
for(int i = 0; i < w; i++)
{
((uint32*)p)[i] = (this->*rp)(i, j, TEX0.TBP0, TEX0.TBW);
}
}
GSTextureSW t(GSTexture::Offscreen, w, h);
if(t.Update(GSVector4i(0, 0, w, h), bits, pitch))
{
t.Save(fn);
}
_aligned_free(bits);
}
// GSOffset
GSOffset::GSOffset(uint32 _bp, uint32 _bw, uint32 _psm)
{
hash = _bp | (_bw << 14) | (_psm << 20);
GSLocalMemory::pixelAddress bn = GSLocalMemory::m_psm[_psm].bn;
for(int i = 0; i < 256; i++)
{
block.row[i] = (short)bn(0, i << 3, _bp, _bw);
}
block.col = GSLocalMemory::m_psm[_psm].blockOffset;
GSLocalMemory::pixelAddress pa = GSLocalMemory::m_psm[_psm].pa;
for(int i = 0; i < 4096; i++)
{
pixel.row[i] = (int)pa(0, i & 0x7ff, _bp, _bw);
}
for(int i = 0; i < 8; i++)
{
pixel.col[i] = GSLocalMemory::m_psm[_psm].rowOffset[i];
}
for(int i = 0; i < 256; i++)
{
coverages[i] = nullptr;
}
}
GSOffset::~GSOffset()
{
for(int i = 0; i < 256; i++)
{
_aligned_free(coverages[i]);
}
}
uint32* GSOffset::GetPages(const GSVector4i& rect, uint32* pages, GSVector4i* bbox)
{
GSVector2i bs = (bp & 31) == 0 ? GSLocalMemory::m_psm[psm].pgs : GSLocalMemory::m_psm[psm].bs;
GSVector4i r = rect.ralign<Align_Outside>(bs);
if(bbox != NULL) *bbox = r;
// worst case:
// bp page-aligned: (w * h) / (64 * 32)
// bp block-aligned: (w * h) / (8 * 8)
int size = r.width() * r.height();
int limit = MAX_PAGES + 1;
if(pages == NULL)
{
limit = std::min<int>((size >> ((bp & 31) != 0 ? 6 : 11)) + 2, MAX_PAGES) + 1;
pages = new uint32[limit];
}
alignas(16) uint32 tmp[16];
((GSVector4i*)tmp)[0] = GSVector4i::zero();
((GSVector4i*)tmp)[1] = GSVector4i::zero();
((GSVector4i*)tmp)[2] = GSVector4i::zero();
((GSVector4i*)tmp)[3] = GSVector4i::zero();
r = r.sra32(3);
bs.x >>= 3;
bs.y >>= 3;
uint32* RESTRICT p = pages;
for(int y = r.top; y < r.bottom; y += bs.y)
{
uint32 base = block.row[y];
for(int x = r.left; x < r.right; x += bs.x)
{
uint32 n = (base + block.col[x]) >> 5;
if(n < MAX_PAGES)
{
uint32& row = tmp[n >> 5];
uint32 col = 1 << (n & 31);
if((row & col) == 0)
{
row |= col;
*p++ = n;
}
}
}
}
*p++ = (uint32)EOP;
ASSERT(p - pages <= limit);
return pages;
}
GSVector4i* GSOffset::GetPagesAsBits(const GSVector4i& rect, GSVector4i* pages, GSVector4i* bbox)
{
if(pages == NULL)
{
pages = (GSVector4i*)_aligned_malloc(sizeof(GSVector4i) * 4, 16);
}
pages[0] = GSVector4i::zero();
pages[1] = GSVector4i::zero();
pages[2] = GSVector4i::zero();
pages[3] = GSVector4i::zero();
GSVector2i bs = (bp & 31) == 0 ? GSLocalMemory::m_psm[psm].pgs : GSLocalMemory::m_psm[psm].bs;
GSVector4i r = rect.ralign<Align_Outside>(bs);
if(bbox != NULL) *bbox = r;
r = r.sra32(3);
bs.x >>= 3;
bs.y >>= 3;
for(int y = r.top; y < r.bottom; y += bs.y)
{
uint32 base = block.row[y];
for(int x = r.left; x < r.right; x += bs.x)
{
uint32 n = (base + block.col[x]) >> 5;
if(n < MAX_PAGES)
{
((uint32*)pages)[n >> 5] |= 1 << (n & 31);
}
}
}
return pages;
}