thug/Code/Gfx/NGPS/NX/texturemem.cpp

1251 lines
35 KiB
C++
Raw Normal View History

2016-02-13 21:39:12 +00:00
#include <core/defines.h>
#include "texture.h"
#include "texturemem.h"
#include "dma.h"
#include "vif.h"
#include "vu1.h"
#include "gif.h"
#include "gs.h"
#include <core/math/math.h>
#define min(x, y) (((x) > (y))? (y): (x))
#define max(x, y) (((x) < (y))? (y): (x))
namespace NxPs2
{
const TextureMemoryLayout::PixelFormatLayout TextureMemoryLayout::pixelFormat[NUM_PIXEL_TYPES] = {
// PIXEL_32
{ { 64, 32 }, // page size
{ 8, 8 }, // block size
true }, // adjacentBlockWidth
// PIXEL_16
{ { 64, 64 }, // page size
{ 16, 8 }, // block size
false }, // adjacentBlockWidth
// PIXEL_8
{ { 128, 64 }, // page size
{ 16, 16 }, // block size
true }, // adjacentBlockWidth
// PIXEL_4
{ { 128, 128 }, // page size
{ 32, 16 }, // block size
false }, // adjacentBlockWidth
};
const int TextureMemoryLayout::blockArrangement[4][8] = {
{ 0, 1, 4, 5, 16, 17, 20, 21 },
{ 2, 3, 6, 7, 18, 19, 22, 23 },
{ 8, 9, 12, 13, 24, 25, 28, 29 },
{ 10, 11, 14, 15, 26, 27, 30, 31 }
};
//----------------------------------------------------------------------------
//
TextureMemoryLayout::TextureMemoryLayout()
{
for (int i = PIXEL_32; i < NUM_PIXEL_TYPES; i++)
initMinSize(minSize[i], PixelType(i));
}
//----------------------------------------------------------------------------
//
void
TextureMemoryLayout::initMinSize(MinSizeArray& mArray, PixelType pType)
{
int tw, th;
for (th = 0; th < MAX_PIXEL_SIZE_BITS; th++) {
for (tw = 0; tw < MAX_PIXEL_SIZE_BITS; tw++) {
mArray[tw][th].width = 1 << tw;
mArray[tw][th].height = 1 << th;
setMinSize(mArray[tw][th].width, mArray[tw][th].height, pType);
}
}
}
//----------------------------------------------------------------------------
//
void
TextureMemoryLayout::setMinSize(int& width, int& height, PixelType pType)
{
const PixelFormatLayout &pf = pixelFormat[pType];
// All widths and heights are powers of 2
// If texture dimension is bigger than a page dimension, then
// make sure whole pages are allocated and exit.
if (width > pf.pageSize.width) {
height = Mth::Max(height, pf.pageSize.height);
return;
} else if (height > pf.pageSize.height) {
width = Mth::Max(width, pf.pageSize.width);
return;
}
// Make sure width and height are at least block size
if (width < pf.blockSize.width)
width = pf.blockSize.width;
if (height < pf.blockSize.height)
height = pf.blockSize.height;
#if 0
// Now we are only dealing with sub-pages. Make sure
// sizes don't go beyond allowable aspect ratios
TexSize twoBlock;
if (pf.adjacentBlockWidth) { // width
twoBlock.width = pf.blockSize.width * 2;
twoBlock.height = pf.blockSize.height;
} else { // height
twoBlock.width = pf.blockSize.width;
twoBlock.height = pf.blockSize.height * 2;
}
#endif
// It just happens that, given a sub-page,
// the height cannot be bigger than the
// width and the width cannot be more than
// double the height
if (height > width)
width = height;
if (width > (height * 2))
height = width / 2;
}
//----------------------------------------------------------------------------
//
TextureMemoryLayout::PixelType
TextureMemoryLayout::modeToPixelType(int pixMode)
{
switch(pixMode) {
case PSMCT32:
case PSMCT24:
return PIXEL_32;
case PSMCT16:
return PIXEL_16;
case PSMT8:
return PIXEL_8;
case PSMT4:
return PIXEL_4;
default:
Dbg_MsgAssert(0, ("TextureMemoryLayout: PixelMode %d not supported.", pixMode));
return PIXEL_INVALID;
}
}
//----------------------------------------------------------------------------
//
void
TextureMemoryLayout::getMinSize(int& width, int& height, int pixMode)
{
PixelType pType = modeToPixelType(pixMode);
// Now get the minimum size
int tw = numBits(width) - 1;
int th = numBits(height) - 1;
width = minSize[pType][tw][th].width;
height = minSize[pType][tw][th].height;
}
//----------------------------------------------------------------------------
// Returns size in blocks. Must calculate the minimum width and height first.
int
TextureMemoryLayout::getImageSize(int width, int height, int pixMode)
{
PixelType pType = modeToPixelType(pixMode);
const PixelFormatLayout &pf = pixelFormat[pType];
int bw, bh;
bw = width / pf.blockSize.width;
bh = height / pf.blockSize.height;
return bw * bh;
}
//----------------------------------------------------------------------------
//
int
TextureMemoryLayout::getBlockNumber(int blockX, int blockY, int pixMode)
{
switch (pixMode) {
case PSMCT32:
case PSMCT24:
case PSMT8:
return blockArrangement[blockY][blockX];
case PSMCT16:
case PSMT4:
return blockArrangement[blockX][blockY];
default:
Dbg_MsgAssert(0, ("TextureMemoryLayout: getBlockNumber %d not supported.", pixMode));
return -1;
}
}
//----------------------------------------------------------------------------
//
void
TextureMemoryLayout::getPosFromBlockNumber(int& posX, int& posY, int blockNumber, int pixMode)
{
int blockRow = -1, blockCol = -1;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 8; j++)
if (blockArrangement[i][j] == blockNumber) {
blockRow = i;
blockCol = j;
break;
}
if (blockRow < 0)
Dbg_MsgAssert(0, ("TextureMemoryLayout: getPosFromBlockNumber"));
PixelType pType = modeToPixelType(pixMode);
const PixelFormatLayout &pf = pixelFormat[pType];
switch (pixMode) {
case PSMCT32:
case PSMCT24:
case PSMT8:
posX = blockCol * pf.blockSize.width;
posY = blockRow * pf.blockSize.height;
break;
case PSMCT16:
case PSMT4:
posX = blockRow * pf.blockSize.width;
posY = blockCol * pf.blockSize.height;
break;
default:
Dbg_MsgAssert(0, ("TextureMemoryLayout: getPosFromBlockNumber %d not supported.", pixMode));
}
}
//----------------------------------------------------------------------------
//
int
TextureMemoryLayout::getBlockOffset(int bufferWidth, int posX, int posY, int pixMode)
{
int horizPages, vertPages;
int numPages = 0;
int blockNumber = 0;
PixelType pType = modeToPixelType(pixMode);
const PixelFormatLayout &pf = pixelFormat[pType];
// First figure out how many pages are above
vertPages = posY / pf.pageSize.height;
if (vertPages) {
horizPages = bufferWidth / pf.pageSize.width;
posY -= vertPages * pf.pageSize.height;
numPages += vertPages * horizPages;
}
// Now how many are to the left
horizPages = posX / pf.pageSize.width;
if (horizPages) {
posX -= horizPages * pf.pageSize.width;
numPages += horizPages;
}
// Now figure out where we are within the page
int horizBlocks, vertBlocks;
horizBlocks = posX / pf.blockSize.width;
vertBlocks = posY / pf.blockSize.height;
blockNumber = getBlockNumber(horizBlocks, vertBlocks, pixMode);
return (numPages * 32) + blockNumber;
}
//----------------------------------------------------------------------------
//
void
TextureMemoryLayout::getPosFromBlockOffset(int& posX, int& posY, int blockOffset, int bufferWidth, int pixMode)
{
int horizPages, vertPages;
PixelType pType = modeToPixelType(pixMode);
const PixelFormatLayout &pf = pixelFormat[pType];
posX = posY = 0;
// First figure out how many pages are above
int horizPageWidth = bufferWidth / pf.pageSize.width;
if (horizPageWidth) {
vertPages = blockOffset / (horizPageWidth * 32);
if (vertPages) {
posY += vertPages * pf.pageSize.height;
blockOffset -= vertPages * horizPageWidth * 32;
}
}
// Now how many are to the left
horizPages = blockOffset / 32;
if (horizPages) {
posX += horizPages * pf.pageSize.width;
blockOffset -= horizPages * 32;
}
// Now figure out where we are within the page
int blockPosX, blockPosY;
getPosFromBlockNumber(blockPosX, blockPosY, blockOffset, pixMode);
posX += blockPosX;
posY += blockPosY;
}
//----------------------------------------------------------------------------
//
bool
TextureMemoryLayout::isPageSize(int width, int height, int pixMode)
{
PixelType pType = modeToPixelType(pixMode);
const PixelFormatLayout &pf = pixelFormat[pType];
return !(width % pf.pageSize.width) && !(height % pf.pageSize.height);
}
//----------------------------------------------------------------------------
//
bool
TextureMemoryLayout::isBlockSize(int width, int height, int pixMode)
{
PixelType pType = modeToPixelType(pixMode);
const PixelFormatLayout &pf = pixelFormat[pType];
return !(width % pf.blockSize.width) && !(height % pf.blockSize.height);
}
//----------------------------------------------------------------------------
//
bool
TextureMemoryLayout::isMinPageSize(int width, int height, int pixMode)
{
PixelType pType = modeToPixelType(pixMode);
const PixelFormatLayout &pf = pixelFormat[pType];
getMinSize(width, height, pixMode);
return (width >= pf.pageSize.width) && (height >= pf.pageSize.height);
}
//----------------------------------------------------------------------------
//
bool
TextureMemoryLayout::isMinBlockSize(int width, int height, int pixMode)
{
PixelType pType = modeToPixelType(pixMode);
const PixelFormatLayout &pf = pixelFormat[pType];
getMinSize(width, height, pixMode);
return (width >= pf.blockSize.width) && (height >= pf.blockSize.height);
}
//----------------------------------------------------------------------------
//
int
TextureMemoryLayout::numBits(unsigned int size)
{
int bits = 0;
while (size > 0) {
size >>= 1;
bits++;
}
return bits;
}
/////////////////////////////////////////////////////////////
// GS Simulator code
//
uint32 *p_gsmem;
int gsmem_size = 0;
int block16[32] =
{
0, 2, 8, 10,
1, 3, 9, 11,
4, 6, 12, 14,
5, 7, 13, 15,
16, 18, 24, 26,
17, 19, 25, 27,
20, 22, 28, 30,
21, 23, 29, 31
};
int columnWord16[32] =
{
0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13,
2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15
};
int columnHalf16[32] =
{
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1
};
void readTexPSMCT16(int dbp, int dbw, int dsax, int dsay, int rrw, int rrh, void *data)
{
//dbw >>= 1;
unsigned short *src = (unsigned short *)data;
int startBlockPos = dbp * 64;
for(int y = dsay; y < dsay + rrh; y++)
{
int pageY = y / 64;
int py = y - (pageY * 64);
int blockY = py / 8;
int by = py - blockY * 8;
int column = by / 2;
int cy = by - column * 2;
for(int x = dsax; x < dsax + rrw; x++)
{
int pageX = x / 64;
int page = pageX + pageY * dbw;
int px = x - (pageX * 64);
int blockX = px / 16;
int block = block16[blockX + blockY * 4];
int bx = px - blockX * 16;
int cx = bx;
int cw = columnWord16[cx + cy * 16];
int ch = columnHalf16[cx + cy * 16];
int gs_index = startBlockPos + page * 2048 + block * 64 + column * 16 + cw;
Dbg_MsgAssert(gs_index < gsmem_size, ("GS simulator memory size: %d; addressing: %d", gsmem_size, gs_index));
unsigned short *dst = (unsigned short *)&p_gsmem[gs_index];
*src = dst[ch];
src++;
}
}
}
int block4[32] =
{
0, 2, 8, 10,
1, 3, 9, 11,
4, 6, 12, 14,
5, 7, 13, 15,
16, 18, 24, 26,
17, 19, 25, 27,
20, 22, 28, 30,
21, 23, 29, 31
};
int columnWord4[2][128] =
{
{
0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13,
2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15,
8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5,
10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7
},
{
8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5,
10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7,
0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13,
2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15
}
};
int columnByte4[128] =
{
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6,
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6,
1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7,
1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7
};
void writeTexPSMT4(int dbp, int dbw, int dsax, int dsay, int rrw, int rrh, void *data)
{
dbw >>= 1;
unsigned char *src = (unsigned char *)data;
int startBlockPos = dbp * 64;
bool odd = false;
for(int y = dsay; y < dsay + rrh; y++)
{
int pageY = y / 128;
int py = y - (pageY * 128);
int blockY = py / 16;
int by = py - blockY * 16;
int column = by / 4;
int cy = by - column * 4;
for(int x = dsax; x < dsax + rrw; x++)
{
int pageX = x / 128;
int page = pageX + pageY * dbw;
int px = x - (pageX * 128);
int blockX = px / 32;
int block = block4[blockX + blockY * 4];
int bx = px - blockX * 32;
int cx = bx;
int cw = columnWord4[column & 1][cx + cy * 32];
int cb = columnByte4[cx + cy * 32];
int gs_index = startBlockPos + page * 2048 + block * 64 + column * 16 + cw;
Dbg_MsgAssert(gs_index < gsmem_size, ("GS simulator memory size: %d; addressing: %d", gsmem_size, gs_index));
unsigned char *dst = (unsigned char *)&p_gsmem[gs_index];
if(cb & 1)
{
if(odd)
dst[cb >> 1] = (dst[cb >> 1] & 0x0f) | ((*src) & 0xf0);
else
dst[cb >> 1] = (dst[cb >> 1] & 0x0f) | (((*src) << 4) & 0xf0);
}
else
{
if(odd)
dst[cb >> 1] = (dst[cb >> 1] & 0xf0) | (((*src) >> 4) & 0x0f);
else
dst[cb >> 1] = (dst[cb >> 1] & 0xf0) | ((*src) & 0x0f);
}
if(odd)
src++;
odd = !odd;
}
}
}
// -------------------------------------------------------------------------------------------
//
//
int TextureMemoryLayout::BlockConv4to32(u_char *p_input, u_char *p_output) {
static int lut[] = {
// even column
0, 68, 8, 76, 16, 84, 24, 92,
1, 69, 9, 77, 17, 85, 25, 93,
2, 70, 10, 78, 18, 86, 26, 94,
3, 71, 11, 79, 19, 87, 27, 95,
4, 64, 12, 72, 20, 80, 28, 88,
5, 65, 13, 73, 21, 81, 29, 89,
6, 66, 14, 74, 22, 82, 30, 90,
7, 67, 15, 75, 23, 83, 31, 91,
32, 100, 40, 108, 48, 116, 56, 124,
33, 101, 41, 109, 49, 117, 57, 125,
34, 102, 42, 110, 50, 118, 58, 126,
35, 103, 43, 111, 51, 119, 59, 127,
36, 96, 44, 104, 52, 112, 60, 120,
37, 97, 45, 105, 53, 113, 61, 121,
38, 98, 46, 106, 54, 114, 62, 122,
39, 99, 47, 107, 55, 115, 63, 123,
// odd column
4, 64, 12, 72, 20, 80, 28, 88,
5, 65, 13, 73, 21, 81, 29, 89,
6, 66, 14, 74, 22, 82, 30, 90,
7, 67, 15, 75, 23, 83, 31, 91,
0, 68, 8, 76, 16, 84, 24, 92,
1, 69, 9, 77, 17, 85, 25, 93,
2, 70, 10, 78, 18, 86, 26, 94,
3, 71, 11, 79, 19, 87, 27, 95,
36, 96, 44, 104, 52, 112, 60, 120,
37, 97, 45, 105, 53, 113, 61, 121,
38, 98, 46, 106, 54, 114, 62, 122,
39, 99, 47, 107, 55, 115, 63, 123,
32, 100, 40, 108, 48, 116, 56, 124,
33, 101, 41, 109, 49, 117, 57, 125,
34, 102, 42, 110, 50, 118, 58, 126,
35, 103, 43, 111, 51, 119, 59, 127
};
unsigned int i, j, k, i0, i1, i2;
unsigned int index0, index1;
unsigned char c_in, c_out, *pIn;
pIn = p_input;
// for first step, we only think for a single block. (4bits, 32x16)
index1 = 0;
for(k = 0; k < 4; k++) {
index0 = (k % 2) * 128;
for(i = 0; i < 16; i++) {
for(j = 0; j < 4; j++) {
c_out = 0x00;
// lower 4bit.
i0 = lut[index0++];
i1 = i0 / 2;
i2 = (i0 & 0x1) * 4;
c_in = (pIn[i1] & (0x0f << i2)) >> i2;
c_out = c_out | c_in;
// uppper 4bit
i0 = lut[index0++];
i1 = i0 / 2;
i2 = (i0 & 0x1) * 4;
c_in = (pIn[i1] & (0x0f << i2)) >> i2;
c_out = c_out | ((c_in << 4) & 0xf0);
p_output[index1++] = c_out;
}
}
pIn += 64;
}
return 0;
}
// -------------------------------------------------------------------------------------------
//
//
int TextureMemoryLayout::BlockConv8to32(u_char *p_input, u_char *p_output) {
static int lut[] = {
// even column
0, 36, 8, 44,
1, 37, 9, 45,
2, 38, 10, 46,
3, 39, 11, 47,
4, 32, 12, 40,
5, 33, 13, 41,
6, 34, 14, 42,
7, 35, 15, 43,
16, 52, 24, 60,
17, 53, 25, 61,
18, 54, 26, 62,
19, 55, 27, 63,
20, 48, 28, 56,
21, 49, 29, 57,
22, 50, 30, 58,
23, 51, 31, 59,
// odd column
4, 32, 12, 40,
5, 33, 13, 41,
6, 34, 14, 42,
7, 35, 15, 43,
0, 36, 8, 44,
1, 37, 9, 45,
2, 38, 10, 46,
3, 39, 11, 47,
20, 48, 28, 56,
21, 49, 29, 57,
22, 50, 30, 58,
23, 51, 31, 59,
16, 52, 24, 60,
17, 53, 25, 61,
18, 54, 26, 62,
19, 55, 27, 63
};
unsigned int i, j, k, i0;
unsigned int index0, index1;
unsigned char *pIn;
pIn = p_input;
// for first step, we only think for a single block. (4bits, 32x16)
index1 = 0;
for(k = 0; k < 4; k++) {
index0 = (k % 2) * 64;
for(i = 0; i < 16; i++) {
for(j = 0; j < 4; j++) {
i0 = lut[index0++];
p_output[index1++] = pIn[i0];
}
}
pIn += 64;
}
return 0;
}
// -------------------------------------------------------------------------------
// send page size 4bit texture and get each block
//
//
//
#define PSMT4_BLOCK_WIDTH 32
#define PSMT4_BLOCK_HEIGHT 16
#define PSMCT32_BLOCK_WIDTH 8
#define PSMCT32_BLOCK_HEIGHT 8
int TextureMemoryLayout::PageConv4to32(int width, int height, u_char *p_input, u_char *p_output) {
static u_int block_table4[] = {
0, 2, 8, 10,
1, 3, 9, 11,
4, 6, 12, 14,
5, 7, 13, 15,
16, 18, 24, 26,
17, 19, 25, 27,
20, 22, 28, 30,
21, 23, 29, 31
};
static u_int block_table32[] = {
0, 1, 4, 5, 16, 17, 20, 21,
2, 3, 6, 7, 18, 19, 22, 23,
8, 9, 12, 13, 24, 25, 28, 29,
10, 11, 14, 15, 26, 27, 30, 31
};
u_int *index32_h, *index32_v, in_block_nb;
u_char input_block[16 * 16], output_block[16 * 16];
u_char *pi0, *pi1, *po0, *po1;
int index0, index1, i, j, k;
int n_width, n_height, input_page_line_size;
int output_page_line_size;
// --- create table for output 32bit buffer ---
index32_h = (u_int*) malloc(8 * 4 * sizeof(u_int));
index32_v = (u_int*) malloc(8 * 4 * sizeof(u_int));
index0 = 0;
for(i = 0; i < 4; i++) {
for(j = 0; j < 8; j++) {
index1 = block_table32[index0];
index32_h[index1] = j;
index32_v[index1] = i;
index0++;
}
}
n_width = width / 32;
n_height = height / 16;
memset(input_block, 0, 16 *16);
memset(output_block, 0, 16 * 16);
input_page_line_size = 128 / 2; // PSMT4 page width (byte)
output_page_line_size = 256; // PSMCT32 page width (byte)
// now assume copying from page top.
for(i = 0; i < n_height; i++) {
for(j = 0; j < n_width; j++) {
pi0 = input_block;
pi1 = p_input + 16 * i * input_page_line_size + j * 16;
in_block_nb = block_table4[i * n_width + j];
for(k = 0; k < PSMT4_BLOCK_HEIGHT; k++) {
memcpy(pi0, pi1, PSMT4_BLOCK_WIDTH / 2); // copy full 1 line of 1 block.
pi0 += PSMT4_BLOCK_WIDTH / 2;
pi1 += input_page_line_size;
}
BlockConv4to32(input_block, output_block);
po0 = output_block;
po1 = p_output + 8 * index32_v[in_block_nb] * output_page_line_size + index32_h[in_block_nb] * 32;
for(k = 0; k < PSMCT32_BLOCK_HEIGHT; k++) {
memcpy(po1, po0, PSMCT32_BLOCK_WIDTH * 4);
po0 += PSMCT32_BLOCK_WIDTH * 4;
po1 += output_page_line_size;
}
}
}
free(index32_h);
free(index32_v);
return 0;
}
// -------------------------------------------------------------------------------
// send page size 8bit texture and get each block
//
//
//
#define PSMT8_BLOCK_WIDTH 16
#define PSMT8_BLOCK_HEIGHT 16
int TextureMemoryLayout::PageConv8to32(int width, int height, u_char *p_input, u_char *p_output) {
static u_int block_table8[] = {
0, 1, 4, 5, 16, 17, 20, 21,
2, 3, 6, 7, 18, 19, 22, 23,
8, 9, 12, 13, 24, 25, 28, 29,
10, 11, 14, 15, 26, 27, 30, 31
};
static u_int block_table32[] = {
0, 1, 4, 5, 16, 17, 20, 21,
2, 3, 6, 7, 18, 19, 22, 23,
8, 9, 12, 13, 24, 25, 28, 29,
10, 11, 14, 15, 26, 27, 30, 31
};
u_int *index32_h, *index32_v, in_block_nb;
u_char input_block[16 * 16], output_block[16 * 16];
u_char *pi0, *pi1, *po0, *po1;
int index0, index1, i, j, k;
int n_width, n_height, input_page_line_size;
int output_page_line_size;
// --- create table for output 32bit buffer ---
index32_h = (u_int*) malloc(8 * 4 * sizeof(u_int));
index32_v = (u_int*) malloc(8 * 4 * sizeof(u_int));
index0 = 0;
for(i = 0; i < 4; i++) {
for(j = 0; j < 8; j++) {
index1 = block_table32[index0];
index32_h[index1] = j;
index32_v[index1] = i;
index0++;
}
}
// how many blocks we should calc (width/height)
n_width = width / PSMT8_BLOCK_WIDTH;
n_height = height / PSMT8_BLOCK_HEIGHT;
memset(input_block, 0, 16 *16);
memset(output_block, 0, 16 * 16);
input_page_line_size = 128; // PSMT8 page width (byte)
output_page_line_size = 256; // PSMCT32 page width (byte)
// now assume copying from page top.
for(i = 0; i < n_height; i++) {
for(j = 0; j < n_width; j++) {
pi0 = input_block;
pi1 = p_input + PSMT8_BLOCK_HEIGHT * i * input_page_line_size + j * PSMT8_BLOCK_WIDTH; // byte
in_block_nb = block_table8[i * n_width + j];
for(k = 0; k < PSMT8_BLOCK_HEIGHT; k++) {
memcpy(pi0, pi1, PSMT8_BLOCK_WIDTH); // copy full 1 line of 1 block.
pi0 += PSMT8_BLOCK_WIDTH;
pi1 += input_page_line_size;
}
BlockConv8to32(input_block, output_block);
po0 = output_block;
po1 = p_output + 8 * index32_v[in_block_nb] * output_page_line_size + index32_h[in_block_nb] * 32;
for(k = 0; k < PSMCT32_BLOCK_HEIGHT; k++) {
memcpy(po1, po0, PSMCT32_BLOCK_WIDTH * 4);
po0 += PSMCT32_BLOCK_WIDTH * 4;
po1 += output_page_line_size;
}
}
}
free(index32_h);
free(index32_v);
return 0;
}
// -------------------------------------------------------------
//
//
#define PSMT4_PAGE_WIDTH 128
#define PSMT4_PAGE_HEIGHT 128
#define PSMCT32_PAGE_WIDTH 64
#define PSMCT32_PAGE_HEIGHT 32
static bool sCanConvert4to32[10][10] =
{
#if 1 // This one only allows for dimensions that are easy to calculate the 32-bit dimensions
// 1 2 4 8 16 32 64 128 256 512
{ false, false, false, false, false, false, false, false, false, false }, // 1
{ false, false, false, false, false, false, false, false, false, false }, // 2
{ false, false, false, false, false, false, false, false, false, false }, // 4
{ false, false, false, false, false, false , false, false, false, false }, // 8
{ false, false, false, false, false, false , false, false, false, false }, // 16
{ false, false, false, false, false, true , false, false, false, false }, // 32
{ false, false, false, false, false, false, true , false, false, false }, // 64
{ false, false, false, false, false, false, false, true , true , true }, // 128
{ false, false, false, false, false, false, false, true , true , true }, // 256
{ false, false, false, false, false, false, false, true , true , true }, // 512
#else
// 1 2 4 8 16 32 64 128 256 512
{ false, false, false, false, false, false, false, false, false, false }, // 1
{ false, false, false, false, false, false, false, false, false, false }, // 2
{ false, false, false, false, false, false, false, false, false, false }, // 4
{ false, false, false, false, false, true , false, false, false, false }, // 8
{ false, false, false, false, false, true , false, false, false, false }, // 16
{ false, false, false, false, false, true , true , false, false, false }, // 32
{ false, false, false, false, false, true , true , true , false, false }, // 64
{ false, false, false, false, false, false, true , true , true , true }, // 128
{ false, false, false, false, false, false, false, true , true , true }, // 256
{ false, false, false, false, false, false, false, true , true , true }, // 512
#endif
};
bool TextureMemoryLayout::CanConv4to32(int width, int height)
{
int tw = numBits(width) - 1;
int th = numBits(height) - 1;
return sCanConvert4to32[th][tw];
}
bool TextureMemoryLayout::Conv4to32(int width, int height, u_char *p_input, u_char *p_output) {
int i, j, k;
int n_page_h, n_page_w, n_page4_width_byte, n_page32_width_byte;
u_char *pi0, *pi1, *po0, *po1;
int n_input_width_byte, n_output_width_byte, n_input_height, n_output_height;
u_char input_page[PSMT4_PAGE_WIDTH / 2 * PSMT4_PAGE_HEIGHT];
u_char output_page[PSMCT32_PAGE_WIDTH * 4 * PSMCT32_PAGE_HEIGHT];
#ifdef __NOPT_ASSERT__
int output_buffer_size = width * height / 2;
#endif
// ----- check width -----
for(i = 0; i < 11; i++) {
if(width == (0x400 >> i)) break;
}
if(i == 11) {
fprintf(stderr, "Error : width is not 2^n\n");
return false;
}
//printf("input_page: %d\n", PSMT4_PAGE_WIDTH / 2 * PSMT4_PAGE_HEIGHT);
//printf("output_page: %d\n", PSMCT32_PAGE_WIDTH * 4 * PSMCT32_PAGE_HEIGHT);
memset(input_page, 0, PSMT4_PAGE_WIDTH / 2 * PSMT4_PAGE_HEIGHT);
memset(output_page, 0, PSMCT32_PAGE_WIDTH * 4 * PSMCT32_PAGE_HEIGHT);
// ----- check height -----
for(i = 0; i < 11; i++) {
if(height == (0x400 >> i)) break;
}
if(i == 11) {
fprintf(stderr, "Error : width is not 2^n\n");
return false;
}
n_page_w = (width - 1) / PSMT4_PAGE_WIDTH + 1;
n_page_h = (height - 1) / PSMT4_PAGE_HEIGHT + 1;
n_page4_width_byte = PSMT4_PAGE_WIDTH / 2;
n_page32_width_byte = PSMCT32_PAGE_WIDTH * 4;
//printf("n_page_w : %d\n", n_page_w );
//printf("n_page_h : %d\n", n_page_h );
//printf("n_page4_width_byte : %d\n", n_page4_width_byte );
//printf("n_page32_width_byte : %d\n", n_page32_width_byte );
// --- set in/out buffer size (for image smaller than one page) ---
if(n_page_w == 1) {
n_input_width_byte = width / 2;
n_output_height = width / 4;
} else {
n_input_width_byte = n_page4_width_byte;
n_output_height = PSMCT32_PAGE_HEIGHT;
}
if(n_page_h == 1) {
n_input_height = height;
n_output_width_byte = height * 2;
} else {
n_input_height = PSMT4_PAGE_HEIGHT;
n_output_width_byte = n_page32_width_byte;
}
for(i = 0; i < n_page_h; i++) {
for(j = 0; j < n_page_w; j++) {
pi0 = p_input + (n_input_width_byte * PSMT4_PAGE_HEIGHT) * n_page_w * i
+ n_input_width_byte * j;
pi1 = input_page;
for(k = 0; k < n_input_height; k++) {
memcpy(pi1, pi0, n_input_width_byte);
pi0 += n_input_width_byte * n_page_w;
pi1 += n_page4_width_byte;
}
PageConv4to32(PSMT4_PAGE_WIDTH, PSMT4_PAGE_HEIGHT, input_page, output_page);
po0 = p_output + (n_output_width_byte * PSMCT32_PAGE_HEIGHT) * n_page_w * i
+ n_output_width_byte * j;
po1 = output_page;
for(k = 0; k < n_output_height; k++) {
Dbg_MsgAssert(((int) (po0 - p_output) + n_output_width_byte) <= output_buffer_size, ("Went outside output buffer for texture of size (%d, %d)", width, height));
memcpy(po0, po1, n_output_width_byte);
po0 += n_output_width_byte * n_page_w;
po1 += n_page32_width_byte;
}
}
}
return CanConv4to32(width, height);
}
// -------------------------------------------------------------
//
//
#define PSMT8_PAGE_WIDTH 128
#define PSMT8_PAGE_HEIGHT 64
static bool sCanConvert8to32[10][10] =
{
// 1 2 4 8 16 32 64 128 256 512
{ false, false, false, false, false, false, false, false, false, false }, // 1
{ false, false, false, false, false, false, false, false, false, false }, // 2
{ false, false, false, false, true , true , true , true , true , false }, // 4
{ false, false, false, false, true , true , true , true , true , false }, // 8
{ false, false, false, false, true , true , true , true , true , false }, // 16
{ false, false, false, false, true , true , true , true , true , false }, // 32
{ false, false, false, false, true , true , true , true , true , true }, // 64
{ false, false, false, false, false, false, false, true , true , true }, // 128
{ false, false, false, false, false, false, false, true , true , true }, // 256
{ false, false, false, false, false, false, false, true , true , false }, // 512
};
bool TextureMemoryLayout::CanConv8to32(int width, int height)
{
int tw = numBits(width) - 1;
int th = numBits(height) - 1;
return sCanConvert8to32[th][tw];
}
bool TextureMemoryLayout::Conv8to32(int width, int height, u_char *p_input, u_char *p_output) {
int i, j, k;
int n_page_h, n_page_w, n_page8_width_byte, n_page32_width_byte;
int n_input_width_byte, n_output_width_byte, n_input_height, n_output_height;
u_char *pi0, *pi1, *po0, *po1;
u_char input_page[PSMT8_PAGE_WIDTH * PSMT8_PAGE_HEIGHT];
u_char output_page[PSMCT32_PAGE_WIDTH * 4 * PSMCT32_PAGE_HEIGHT];
#ifdef __NOPT_ASSERT__
int output_buffer_size = width * height;
#endif
// ----- check width -----
for(i = 0; i < 11; i++) {
if(width == (0x400 >> i)) break;
}
if(i == 11) {
fprintf(stderr, "Error : width is not 2^n\n");
return false;
}
// ----- check height -----
for(i = 0; i < 11; i++) {
if(height == (0x400 >> i)) break;
}
if(i == 11) {
fprintf(stderr, "Error : width is not 2^n\n");
return false;
}
memset(input_page, 0, PSMT8_PAGE_WIDTH * PSMT8_PAGE_HEIGHT);
memset(output_page, 0, PSMCT32_PAGE_WIDTH * 4 * PSMCT32_PAGE_HEIGHT);
n_page_w = (width - 1) / PSMT8_PAGE_WIDTH + 1;
n_page_h = (height - 1) / PSMT8_PAGE_HEIGHT + 1;
n_page8_width_byte = PSMT8_PAGE_WIDTH;
n_page32_width_byte = PSMCT32_PAGE_WIDTH * 4;
// --- set in/out buffer size (for image smaller than one page) ---
if(n_page_w == 1) {
n_input_width_byte = width;
n_output_width_byte = width * 2;
} else {
n_input_width_byte = n_page8_width_byte;
n_output_width_byte = n_page32_width_byte;
}
if(n_page_h == 1) {
n_input_height = height;
n_output_height = height / 2;
} else {
n_input_height = PSMT8_PAGE_HEIGHT;
n_output_height = PSMCT32_PAGE_HEIGHT;
}
// --- conversion ---
for(i = 0; i < n_page_h; i++) {
for(j = 0; j < n_page_w; j++) {
pi0 = p_input + (n_input_width_byte * PSMT8_PAGE_HEIGHT) * n_page_w * i
+ n_input_width_byte * j;
pi1 = input_page;
for(k = 0; k < n_input_height; k++) {
memcpy(pi1, pi0, n_input_width_byte);
pi0 += n_input_width_byte * n_page_w;
pi1 += n_page8_width_byte;
}
// --- convert a page ---
PageConv8to32(PSMT8_PAGE_WIDTH, PSMT8_PAGE_HEIGHT, input_page, output_page);
po0 = p_output + (n_output_width_byte * n_output_height) * n_page_w * i
+ n_output_width_byte * j;
po1 = output_page;
for(k = 0; k < n_output_height; k++) {
Dbg_MsgAssert(((int) (po0 - p_output) + n_output_width_byte) <= output_buffer_size, ("Went outside output buffer for texture of size (%d, %d)", width, height));
memcpy(po0, po1, n_output_width_byte);
po0 += n_output_width_byte * n_page_w;
po1 += n_page32_width_byte;
}
}
}
return CanConv4to16(width, height);
}
// -------------------------------------------------------------
//
//
static bool sCanConvert4to16[10][10] =
{
// 1 2 4 8 16 32 64 128 256 512
{ false, false, false, false, false, false, false, false, false, false }, // 1
{ false, false, false, false, false, false, false, false, false, false }, // 2
{ false, false, false, false, false, false, false, false, false, false }, // 4
{ false, false, false, false, true , true , true , true , true , false }, // 8
{ false, false, false, false, true , true , true , true , true , false }, // 16
{ false, false, false, false, true , true , true , true , true , false }, // 32
{ false, false, false, false, true , true , true , true , true , false }, // 64
{ false, false, false, false, true , true , true , true , true , true }, // 128
{ false, false, false, false, false, false, false, true , true , true }, // 256
{ false, false, false, false, false, false, false, true , true , true }, // 512
};
bool TextureMemoryLayout::CanConv4to16(int width, int height)
{
int tw = numBits(width) - 1;
int th = numBits(height) - 1;
return sCanConvert4to16[th][tw];
}
bool TextureMemoryLayout::Conv4to16(int width, int height, u_char *p_input, u_char *p_output) {
int i;
// ----- check width -----
for(i = 0; i < 11; i++) {
if(width == (0x400 >> i)) break;
}
if(i == 11) {
fprintf(stderr, "Error : width is not 2^n\n");
return false;
}
// ----- check height -----
for(i = 0; i < 11; i++) {
if(height == (0x400 >> i)) break;
}
if(i == 11) {
fprintf(stderr, "Error : width is not 2^n\n");
return false;
}
// Find size needed for buffers
int min_4_width = width;
int min_4_height = height;
int min_16_width = width / 2;
int min_16_height = height / 2;
getMinSize(min_4_width, min_4_height, PSMT4);
getMinSize(min_16_width, min_16_height, PSMCT16);
int blocks_needed = max(getImageSize(min_4_width, min_4_height, PSMT4), getImageSize(min_16_width, min_16_height, PSMCT16));
int words_needed = blocks_needed * 64;
// Allocate memory
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
p_gsmem = new uint32[words_needed];
gsmem_size = words_needed;
Mem::Manager::sHandle().PopContext();
// Swizzle through GS simulator code
writeTexPSMT4(0, max(width / 128, 1) * 2, 0, 0, width, height, p_input);
readTexPSMCT16(0, max(width / 2 / 128, 1) * 2, 0, 0, width / 2, height / 2, p_output);
// Free memory
delete [] p_gsmem;
p_gsmem = NULL;
gsmem_size = 0;
return CanConv4to16(width, height);
}
} // namespace NxPs2