mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-04-10 19:15:14 +00:00
Implement sub 8x8 tile encoding. Fixes incomplete mipmap chains which previously only went down to 8x8 pixels before. It wasn't known these textures existed before. (Harry Tuttle)
This commit is contained in:
parent
cede67468c
commit
cc28d5f00e
Src
|
@ -307,7 +307,7 @@ UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, boo
|
|||
|
||||
y -= (page * 1024); // remove page from tex y
|
||||
|
||||
for (int i = 0; width >= 8 && height >= 8; i++) {
|
||||
for (int i = 0; width > 0 && height > 0; i++) {
|
||||
|
||||
int xPos = mipXBase[i] + (x / mipDivisor[i]);
|
||||
int yPos = mipYBase[i] + (y / mipDivisor[i]);
|
||||
|
@ -375,7 +375,7 @@ void Texture::CreateTextureObject(int format, bool mirrorU, bool mirrorV, int x,
|
|||
int minD = std::min(width, height);
|
||||
int count = 0;
|
||||
|
||||
while (minD > 8) {
|
||||
while (minD > 1) {
|
||||
minD /= 2;
|
||||
count++;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "Model3/JTAG.h"
|
||||
#include "Util/BMPFile.h"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
// Macros that divide memory regions into pages and mark them as dirty when they are written to
|
||||
#define PAGE_WIDTH 12
|
||||
|
@ -290,83 +291,106 @@ void CReal3D::EndFrame(void)
|
|||
******************************************************************************/
|
||||
|
||||
// Mipmap coordinates for each reduction level (within a single 2048x1024 page)
|
||||
static const int mipXBase[11] =
|
||||
|
||||
const int mipXBase[] = { 0, 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047 };
|
||||
const int mipYBase[] = { 0, 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023 };
|
||||
const int mipDivisor[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 };
|
||||
|
||||
// Tables of texel offsets corresponding to an NxN texel texture tile
|
||||
|
||||
static const unsigned decode8x8[64] =
|
||||
{
|
||||
1024, // 1024/2
|
||||
1536, // 512/2
|
||||
1792, // 256/2
|
||||
1920, // ...
|
||||
1984,
|
||||
2016,
|
||||
2032,
|
||||
2040,
|
||||
2044,
|
||||
2046,
|
||||
2047
|
||||
1, 0, 5, 4, 9, 8,13,12,
|
||||
3, 2, 7, 6,11,10,15,14,
|
||||
17,16,21,20,25,24,29,28,
|
||||
19,18,23,22,27,26,31,30,
|
||||
33,32,37,36,41,40,45,44,
|
||||
35,34,39,38,43,42,47,46,
|
||||
49,48,53,52,57,56,61,60,
|
||||
51,50,55,54,59,58,63,62
|
||||
};
|
||||
|
||||
static const int mipYBase[11] =
|
||||
static const unsigned decode8x4[32] =
|
||||
{
|
||||
512,
|
||||
768,
|
||||
896,
|
||||
960,
|
||||
992,
|
||||
1008,
|
||||
1016,
|
||||
1020,
|
||||
1022,
|
||||
1023,
|
||||
0
|
||||
1, 0, 5, 4,
|
||||
3, 2, 7, 6,
|
||||
9, 8,13,12,
|
||||
11,10,15,14,
|
||||
17,16,21,20,
|
||||
19,18,23,22,
|
||||
25,24,29,28,
|
||||
27,26,31,30
|
||||
};
|
||||
|
||||
// Mipmap reduction factors
|
||||
static const int mipDivisor[9] = { 2, 4, 8, 16, 32, 64, 128, 256, 512 };
|
||||
|
||||
// Table of texel offsets corresponding to an 8x8 texel texture tile
|
||||
static const unsigned decode[64] =
|
||||
static const unsigned decode8x2[16] =
|
||||
{
|
||||
0, 1, 4, 5, 8, 9,12,13,
|
||||
2, 3, 6, 7,10,11,14,15,
|
||||
16,17,20,21,24,25,28,29,
|
||||
18,19,22,23,26,27,30,31,
|
||||
32,33,36,37,40,41,44,45,
|
||||
34,35,38,39,42,43,46,47,
|
||||
48,49,52,53,56,57,60,61,
|
||||
50,51,54,55,58,59,62,63
|
||||
1, 0,
|
||||
3, 2,
|
||||
5, 4,
|
||||
7, 6,
|
||||
9, 8,
|
||||
11, 10,
|
||||
13, 12,
|
||||
15, 14
|
||||
};
|
||||
|
||||
static void StoreTexelByte(uint16_t *texel, uint32_t byteSelect, uint8_t byte)
|
||||
static const unsigned decode8x1[8] =
|
||||
{
|
||||
if ((byteSelect & 1)) // write to LSB
|
||||
1,
|
||||
3,
|
||||
0,
|
||||
2,
|
||||
5,
|
||||
7,
|
||||
4,
|
||||
6
|
||||
};
|
||||
|
||||
static void StoreTexelByte(uint16_t *texel, bool writeLSB, bool writeMSB, uint8_t byte)
|
||||
{
|
||||
if (writeLSB) // write to least significant byte
|
||||
*texel = (*texel & 0xFF00) | byte;
|
||||
if ((byteSelect & 2)) // write to MSB
|
||||
if (writeMSB) // write to most significant byte
|
||||
*texel = (*texel & 0x00FF) | (uint16_t(byte) << 8);
|
||||
}
|
||||
|
||||
void CReal3D::StoreTexture(unsigned level, unsigned xPos, unsigned yPos, unsigned width, unsigned height, const uint16_t *texData, uint32_t header)
|
||||
void CReal3D::StoreTexture(unsigned level, unsigned xPos, unsigned yPos, unsigned width, unsigned height, const uint16_t *texData, bool sixteenBit, bool writeLSB, bool writeMSB, uint32_t &texDataOffset)
|
||||
{
|
||||
if ((header & 0x00800000)) // 16-bit textures
|
||||
uint32_t tileX = std::min(8u, width);
|
||||
uint32_t tileY = std::min(8u, height);
|
||||
|
||||
texDataOffset = 0;
|
||||
|
||||
if (sixteenBit) // 16-bit textures
|
||||
{
|
||||
// Outer 2 loops: 8x8 tiles
|
||||
for (uint32_t y = yPos; y < (yPos+height); y += 8)
|
||||
// Outer 2 loops: NxN tiles
|
||||
for (uint32_t y = yPos; y < (yPos + height); y += tileY)
|
||||
{
|
||||
for (uint32_t x = xPos; x < (xPos+width); x += 8)
|
||||
for (uint32_t x = xPos; x < (xPos + width); x += tileX)
|
||||
{
|
||||
// Inner 2 loops: 8x8 texels for the current tile
|
||||
uint32_t destOffset = y*2048+x;
|
||||
for (uint32_t yy = 0; yy < 8; yy++)
|
||||
// Inner 2 loops: NxN texels for the current tile
|
||||
uint32_t destOffset = y * 2048 + x;
|
||||
for (uint32_t yy = 0; yy < tileY; yy++)
|
||||
{
|
||||
for (uint32_t xx = 0; xx < 8; xx++)
|
||||
for (uint32_t xx = 0; xx < tileX; xx++)
|
||||
{
|
||||
if (m_gpuMultiThreaded)
|
||||
MARK_DIRTY(textureRAMDirty, destOffset * 2);
|
||||
textureRAM[destOffset++] = texData[decode[(yy*8+xx)^1]];
|
||||
if (tileX == 1) texData -= tileY;
|
||||
if (tileY == 1) texData -= tileX;
|
||||
if (tileX == 8)
|
||||
textureRAM[destOffset++] = texData[decode8x8[yy * tileX + xx]];
|
||||
else if (tileX == 4)
|
||||
textureRAM[destOffset++] = texData[decode8x4[yy * tileX + xx]];
|
||||
else if (tileX == 2)
|
||||
textureRAM[destOffset++] = texData[decode8x2[yy * tileX + xx]];
|
||||
else if (tileX == 1)
|
||||
textureRAM[destOffset++] = texData[decode8x1[yy * tileX + xx]];
|
||||
texDataOffset++;
|
||||
}
|
||||
|
||||
destOffset += 2048-8; // next line
|
||||
destOffset += 2048 - tileX; // next line
|
||||
}
|
||||
texData += 8*8; // next tile
|
||||
texData += tileY * tileX; // next tile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -378,35 +402,53 @@ void CReal3D::StoreTexture(unsigned level, unsigned xPos, unsigned yPos, unsigne
|
|||
* swapped.
|
||||
*/
|
||||
|
||||
uint32_t byteSelect = (header>>21)&3; // which byte to unpack to
|
||||
if (byteSelect == 3) // write to both?
|
||||
if (writeLSB && writeMSB) // write to both?
|
||||
DebugLog("Observed 8-bit texture with byte_select=3!");
|
||||
|
||||
// Outer 2 loops: 8x8 tiles
|
||||
for (uint32_t y = yPos; y < (yPos+height); y += 8)
|
||||
// Outer 2 loops: NxN tiles
|
||||
uint8_t byte1, byte2;
|
||||
for (uint32_t y = yPos; y < (yPos + height); y += tileY)
|
||||
{
|
||||
for (uint32_t x = xPos; x < (xPos+width); x += 8)
|
||||
for (uint32_t x = xPos; x < (xPos + width); x += tileX)
|
||||
{
|
||||
// Inner 2 loops: 8x8 texels for the current tile
|
||||
uint32_t destOffset = y*2048+x;
|
||||
for (uint32_t yy = 0; yy < 8; yy++)
|
||||
// Inner 2 loops: NxN texels for the current tile
|
||||
uint32_t destOffset = y * 2048 + x;
|
||||
for (uint32_t yy = 0; yy < tileY; yy++)
|
||||
{
|
||||
for (uint32_t xx = 0; xx < 8; xx += 2)
|
||||
for (uint32_t xx = 0; xx < tileX; xx += 2)
|
||||
{
|
||||
uint8_t byte1 = texData[decode[(yy^1)*8+((xx+0)^1)]/2]>>8;
|
||||
uint8_t byte2 = texData[decode[(yy^1)*8+((xx+1)^1)]/2]&0xFF;
|
||||
if (tileX == 1) texData -= std::max(1u, tileY / 2);
|
||||
if (tileY == 1) texData -= std::max(1u, tileX / 2);
|
||||
if (tileX == 8) {
|
||||
byte1 = texData[decode8x8[(yy^1) * tileX + ((xx + 0)^1)] / 2] >> 8;
|
||||
byte2 = texData[decode8x8[(yy^1) * tileX + ((xx + 1)^1)] / 2] & 0xFF;
|
||||
}
|
||||
if (tileX == 4) {
|
||||
byte1 = texData[decode8x4[(yy^1) * tileX + ((xx + 0)^1)] / 2] >> 8;
|
||||
byte2 = texData[decode8x4[(yy^1) * tileX + ((xx + 1)^1)] / 2] & 0xFF;
|
||||
}
|
||||
if (tileX == 2) {
|
||||
byte1 = texData[decode8x2[(yy^1) * tileX + ((xx + 0)^1)] / 2] >> 8;
|
||||
byte2 = texData[decode8x2[(yy^1) * tileX + ((xx + 1)^1)] / 2] & 0xFF;
|
||||
}
|
||||
if (tileX == 1) {
|
||||
byte1 = texData[decode8x1[(yy^1) * tileX + ((xx + 0)^1)] / 2] >> 8;
|
||||
byte2 = texData[decode8x1[(yy^1) * tileX + ((xx + 0)^1)] / 2] & 0xFF;
|
||||
}
|
||||
if (m_gpuMultiThreaded)
|
||||
MARK_DIRTY(textureRAMDirty, destOffset * 2);
|
||||
StoreTexelByte(&textureRAM[destOffset], byteSelect, byte1);
|
||||
StoreTexelByte(&textureRAM[destOffset], writeLSB, writeMSB, byte1);
|
||||
++destOffset;
|
||||
if (m_gpuMultiThreaded)
|
||||
MARK_DIRTY(textureRAMDirty, destOffset * 2);
|
||||
StoreTexelByte(&textureRAM[destOffset], byteSelect, byte2);
|
||||
StoreTexelByte(&textureRAM[destOffset], writeLSB, writeMSB, byte2);
|
||||
++destOffset;
|
||||
}
|
||||
destOffset += 2048-8;
|
||||
destOffset += 2048 - tileX; // next line
|
||||
}
|
||||
texData += 8*8/2; // next tile
|
||||
uint32_t offset = std::max(1u, (tileY * tileX) / 2);
|
||||
texData += offset; // next tile
|
||||
texDataOffset += offset; // next tile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -428,96 +470,66 @@ void CReal3D::StoreTexture(unsigned level, unsigned xPos, unsigned yPos, unsigne
|
|||
Render3D->UploadTextures(level, xPos, yPos, width, height);
|
||||
}
|
||||
|
||||
/*
|
||||
Texture header:
|
||||
-------- -------- -------- --xxxxxx X-position
|
||||
-------- -------- ----xxxx x------- Y-position
|
||||
-------- -------x xx------ -------- Width
|
||||
-------- ----xxx- -------- -------- Height
|
||||
-------- ---x---- -------- -------- Texture page
|
||||
-------- --x----- -------- -------- Write 8-bit data to the lower byte of texel
|
||||
-------- -x------ -------- -------- Write 8-bit data to the upper byte of texel
|
||||
-------- x------- -------- -------- Bitdepth, 0 = 8-bit, 1 = 16-bit
|
||||
xxxxxxxx -------- -------- -------- Texture type:
|
||||
0x00 = texture with mipmaps
|
||||
0x01 = texture without mipmaps
|
||||
0x02 = only mipmaps
|
||||
0x80 = possibly gamma table
|
||||
*/
|
||||
|
||||
// Texture data will be in little endian format
|
||||
void CReal3D::UploadTexture(uint32_t header, const uint16_t *texData)
|
||||
{
|
||||
// Position: texture RAM is arranged as 2 2048x1024 texel sheets
|
||||
uint32_t x = 32*(header&0x3F);
|
||||
uint32_t y = 32*((header>>7)&0x1F);
|
||||
uint32_t page = (header>>20)&1;
|
||||
y += page*1024; // treat page as additional Y bit (one 2048x2048 sheet)
|
||||
uint32_t x = 32 * (header & 0x3F);
|
||||
uint32_t y = 32 * ((header >> 7) & 0x1F);
|
||||
uint32_t page = (header >> 20) & 1;
|
||||
uint32_t width = 32 << ((header >> 14) & 7);
|
||||
uint32_t height = 32 << ((header >> 17) & 7);
|
||||
uint32_t type = (header >> 24) & 0xFF;
|
||||
bool sixteenBit = (header >> 23) & 0x1;
|
||||
bool writeUpperByte = (header >> 22) & 0x1;
|
||||
bool writeLowerByte = (header >> 21) & 0x1;
|
||||
uint32_t offset = 0;
|
||||
|
||||
// Texture size and bit depth
|
||||
uint32_t width = 32<<((header>>14)&7);
|
||||
uint32_t height = 32<<((header>>17)&7);
|
||||
uint32_t bytesPerTexel;
|
||||
if ((header&0x00800000)) // 16 bits per texel
|
||||
bytesPerTexel = 2;
|
||||
else // 8 bits
|
||||
{
|
||||
bytesPerTexel = 1;
|
||||
//printf("8-bit textures!\n");
|
||||
}
|
||||
|
||||
// Mipmaps
|
||||
uint32_t mipYPos = 32*((header>>7)&0x1F);
|
||||
|
||||
// Process texture data
|
||||
DebugLog("Real3D: Texture upload: pos=(%d,%d) size=(%d,%d), %d-bit\n", x, y, width, height, bytesPerTexel*8);
|
||||
//printf("Real3D: Texture upload: pos=(%d,%d) size=(%d,%d), %d-bit\n", x, y, width, height, bytesPerTexel*8);
|
||||
switch ((header>>24)&0xFF)
|
||||
switch (type)
|
||||
{
|
||||
case 0x00: // texture w/ mipmaps
|
||||
{
|
||||
StoreTexture(0, x, y, width, height, texData, header);
|
||||
uint32_t mipWidth = width;
|
||||
uint32_t mipHeight = height;
|
||||
uint32_t mipNum = 0;
|
||||
|
||||
while((mipHeight>8) && (mipWidth>8))
|
||||
{
|
||||
if (bytesPerTexel == 1)
|
||||
texData += (mipWidth*mipHeight)/2;
|
||||
else
|
||||
texData += (mipWidth*mipHeight);
|
||||
mipWidth /= 2;
|
||||
mipHeight /= 2;
|
||||
uint32_t mipX = mipXBase[mipNum] + (x / mipDivisor[mipNum]);
|
||||
uint32_t mipY = mipYBase[mipNum] + (mipYPos / mipDivisor[mipNum]);
|
||||
if(page)
|
||||
mipY += 1024;
|
||||
mipNum++;
|
||||
StoreTexture(mipNum, mipX, mipY, mipWidth, mipHeight, (uint16_t *)texData, header);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x01: // texture w/out mipmaps
|
||||
StoreTexture(0, x, y, width, height, texData, header);
|
||||
StoreTexture(0, x, y + (page * 1024), width, height, texData, sixteenBit, writeLowerByte, writeUpperByte, offset);
|
||||
texData += offset;
|
||||
if (type == 0x01) {
|
||||
break;
|
||||
}
|
||||
case 0x02: // mipmaps only
|
||||
{
|
||||
uint32_t mipWidth = width;
|
||||
uint32_t mipHeight = height;
|
||||
uint32_t mipNum = 0;
|
||||
while((mipHeight>8) && (mipWidth>8))
|
||||
{
|
||||
mipWidth /= 2;
|
||||
mipHeight /= 2;
|
||||
uint32_t mipX = mipXBase[mipNum] + (x / mipDivisor[mipNum]);
|
||||
uint32_t mipY = mipYBase[mipNum] + (mipYPos / mipDivisor[mipNum]);
|
||||
if(page)
|
||||
mipY += 1024;
|
||||
mipNum++;
|
||||
StoreTexture(mipNum, mipX, mipY, mipWidth, mipHeight, texData, header);
|
||||
if (bytesPerTexel == 1)
|
||||
texData += (mipWidth*mipHeight)/2;
|
||||
else
|
||||
texData += (mipWidth*mipHeight);
|
||||
for (int i = 1; width > 0 && height > 0; i++) {
|
||||
|
||||
int xPos = mipXBase[i] + (x / mipDivisor[i]);
|
||||
int yPos = mipYBase[i] + (y / mipDivisor[i]);
|
||||
|
||||
width /= 2;
|
||||
height /= 2;
|
||||
|
||||
StoreTexture(i, xPos, yPos + (page * 1024), width, height, texData, sixteenBit, writeLowerByte, writeUpperByte, offset);
|
||||
texData += offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x80: // MAME thinks these might be a gamma table
|
||||
/*
|
||||
printf("Special texture format 0x80:\n");
|
||||
for (int i = 0; i < 32*32; i++)
|
||||
{
|
||||
printf(" %02x=%02x\n", i, texData[i]);
|
||||
}
|
||||
*/
|
||||
case 0x80: // MAME thinks these might be a gamma table (vf3 uploads this as the first texture)
|
||||
break;
|
||||
default: // unknown
|
||||
DebugLog("Unknown texture format %02X\n", header>>24);
|
||||
//printf("unknown texture format %02X\n", header>>24);
|
||||
DebugLog("Unknown texture format %02X\n", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -997,7 +1009,7 @@ CReal3D::CReal3D(const Util::Config::Node &config)
|
|||
CReal3D::~CReal3D(void)
|
||||
{
|
||||
// Dump memory
|
||||
#if 0
|
||||
#if 1
|
||||
FILE *fp;
|
||||
fp = fopen("8c000000", "wb");
|
||||
if (NULL != fp)
|
||||
|
|
|
@ -406,7 +406,8 @@ private:
|
|||
void InsertBit(uint8_t *buf, unsigned bitNum, unsigned bit);
|
||||
void InsertID(uint32_t id, unsigned startBit);
|
||||
unsigned Shift(uint8_t *data, unsigned numBits);
|
||||
void StoreTexture(unsigned level, unsigned xPos, unsigned yPos, unsigned width, unsigned height, const uint16_t *texData, uint32_t header);
|
||||
void StoreTexture(unsigned level, unsigned xPos, unsigned yPos, unsigned width, unsigned height, const uint16_t *texData, bool sixteenBit, bool writeLSB, bool writeMSB, uint32_t &texDataOffset);
|
||||
|
||||
void UploadTexture(uint32_t header, const uint16_t *texData);
|
||||
uint32_t UpdateSnapshots(bool copyWhole);
|
||||
uint32_t UpdateSnapshot(bool copyWhole, uint8_t *src, uint8_t *dst, unsigned size, uint8_t *dirty);
|
||||
|
|
Loading…
Reference in a new issue