PK çl‘Kí­KÂ<Â< diff.patchdiff -ur --binary model3emu/Src/Graphics/New3D/Texture.cpp model3emu-patch/Src/Graphics/New3D/Texture.cpp --- model3emu/Src/Graphics/New3D/Texture.cpp 2017-12-17 13:37:30.000000000 +0100 +++ model3emu-patch/Src/Graphics/New3D/Texture.cpp 2017-12-17 12:53:39.000000000 +0100 @@ -306,8 +306,8 @@ int page = y / 1024; 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,10 +375,8 @@ int minD = std::min(width, height); int count = 0; - while (minD > 8) { - minD /= 2; - count++; - } + count = std::log2(minD); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, count); diff -ur --binary model3emu/Src/Model3/Real3D.cpp model3emu-patch/Src/Model3/Real3D.cpp --- model3emu/Src/Model3/Real3D.cpp 2017-12-17 13:37:29.000000000 +0100 +++ model3emu-patch/Src/Model3/Real3D.cpp 2017-12-17 12:53:30.000000000 +0100 @@ -262,12 +262,12 @@ // If multi-threaded, perform now any queued texture uploads to renderer before rendering begins if (m_gpuMultiThreaded) { - for (const auto &it : queuedUploadTexturesRO) { + for (const auto &it : queuedUploadTexturesRO) { Render3D->UploadTextures(it.level, it.x, it.y, it.width, it.height); - } + } - // done syncing data - queuedUploadTexturesRO.clear(); + // done syncing data + queuedUploadTexturesRO.clear(); } Render3D->BeginFrame(); @@ -290,50 +290,88 @@ ******************************************************************************/ // Mipmap coordinates for each reduction level (within a single 2048x1024 page) -static const int mipXBase[11] = -{ +static const int mipXBase[12] = +{ + 0, 1024, // 1024/2 1536, // 512/2 1792, // 256/2 1920, // ... - 1984, - 2016, - 2032, - 2040, - 2044, - 2046, - 2047 + 1984, + 2016, + 2032, + 2040, + 2044, + 2046, + 2047 }; static const int mipYBase[11] = { - 512, - 768, - 896, - 960, - 992, + 0, + 512, + 768, + 896, + 960, + 992, 1008, - 1016, - 1020, - 1022, - 1023, - 0 + 1016, + 1020, + 1022, + 1023 }; // Mipmap reduction factors -static const int mipDivisor[9] = { 2, 4, 8, 16, 32, 64, 128, 256, 512 }; +static const int mipDivisor[11] = { 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] = +{ + 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 unsigned decode8x4[32] = +{ + 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 +}; + +static const unsigned decode8x2[16] = +{ + 1, 0, + 3, 2, + 5, 4, + 7, 6, + 9, 8, + 11, 10, + 13, 12, + 15, 14 +}; -// Table of texel offsets corresponding to an 8x8 texel texture tile -static const unsigned decode[64] = +static const unsigned decode8x1[8] = { - 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, + 3, + 0, + 2, + 5, + 7, + 4, + 6 }; static void StoreTexelByte(uint16_t *texel, uint32_t byteSelect, uint8_t byte) @@ -342,31 +380,43 @@ *texel = (*texel & 0xFF00) | byte; if ((byteSelect & 2)) // write to MSB *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 texelFormat, uint32_t byteSelect, uint32_t &texDataOffset) { - if ((header & 0x00800000)) // 16-bit textures + uint32_t tileX = std::min(8u, width); + uint32_t tileY = std::min(8u, height); + + if (texelFormat) // 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,23 +428,39 @@ * swapped. */ - uint32_t byteSelect = (header>>21)&3; // which byte to unpack to if (byteSelect == 3) // 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); @@ -404,9 +470,11 @@ StoreTexelByte(&textureRAM[destOffset], byteSelect, 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 } } } @@ -417,7 +485,7 @@ { // If multi-threaded, then queue calls to UploadTextures for render thread to perform at beginning of next frame QueuedUploadTextures upl; - upl.level = level; + upl.level = level; upl.x = xPos; upl.y = yPos; upl.width = width; @@ -431,94 +499,88 @@ // 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) - - // 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); - + uint8_t texture_map_address_x, texture_map_address_y, map_size_x, map_size_y, spare; + bool even_bank, write_lower_byte, write_upper_byte, texel_format, reserved; + + // SDK Reference: , class "PCI_Texture_Data" + texture_map_address_x = header & 0x7F; + texture_map_address_y = (header >> 7) & 0x7F; + map_size_x = (header >> 14) & 7; + map_size_y = (header >> 17) & 7; + even_bank = ((header >> 20) & 1) > 0; + write_lower_byte = ((header >> 21) & 1) > 0; + write_upper_byte = ((header >> 22) & 1) > 0; + texel_format = ((header >> 23) & 1) > 0; + spare = (header >> 24) & 0x7F; // SDK strangely defines the upload mode as "spare" bits + reserved = ((header >> 31) & 1) > 0; // What is it for? + + texture_map_address_x &= 63; + texture_map_address_y &= 31; + + uint32_t x, y, width, height, page, pageOffset, byteSelect, bytesPerTexel; + enum uplMode { BOTH, BASE, MIPS }; + + x = 32 * texture_map_address_x; + y = 32 * texture_map_address_y; + width = 32 << map_size_x; + height = 32 << map_size_y; + page = (uint32_t)even_bank; + pageOffset = page * 1024; + byteSelect = (header >> 21) & 3; + bytesPerTexel = texel_format ? 2 : 1; // 16 or 8 bits textures + + // Treat page as additional Y bit (one 2048x2048 sheet) + y += pageOffset; + // 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) - { - 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 (0) // DEBUG + if (reserved) // MAME thinks these might be a gamma table, SDK says "reserved" + { + DebugLog("Real3D: Special texture format: mip=%d pos=(%d,%d) size=(%d,%d), %d-bit\n\n", lodNum, x, y, width, height, bytesPerTexel*8); + for (int i = 0; i < width*height; i++) { - 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); + printf(" %04d=%04x\n", i, texData[i]); } - break; + printf("\n"); + } + #endif + + uint32_t lodNum = 0; + uint32_t texDataOffset; + + if (spare == uplMode::BOTH || spare == uplMode::BASE) + { + texDataOffset = 0; + StoreTexture(lodNum, x, y, width, height, (uint16_t *)texData, texel_format, byteSelect, texDataOffset); + + texData += texDataOffset; } - case 0x01: // texture w/out mipmaps - StoreTexture(0, x, y, width, height, texData, header); - break; - case 0x02: // mipmaps only + + if (spare == uplMode::BOTH || spare == uplMode::MIPS) { - uint32_t mipWidth = width; - uint32_t mipHeight = height; - uint32_t mipNum = 0; - while((mipHeight>8) && (mipWidth>8)) + uint32_t mipX, mipY, mipWidth, mipHeight; + + mipX = 0; + mipY = 0; + mipWidth = width; + mipHeight = height; + y -= pageOffset; + + while (std::min(mipWidth, mipHeight) > 1) { + texDataOffset = 0; + lodNum++; + mipX = mipXBase[lodNum] + (x / mipDivisor[lodNum]); + mipY = mipYBase[lodNum] + (y / mipDivisor[lodNum]); 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); - } - 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]); + + StoreTexture(lodNum, mipX, mipY + pageOffset, mipWidth, mipHeight, (uint16_t *)texData, texel_format, byteSelect, texDataOffset); + + texData += texDataOffset; } - */ - break; - default: // unknown - DebugLog("Unknown texture format %02X\n", header>>24); - //printf("unknown texture format %02X\n", header>>24); - break; } } diff -ur --binary model3emu/Src/Model3/Real3D.h model3emu-patch/Src/Model3/Real3D.h --- model3emu/Src/Model3/Real3D.h 2017-12-17 13:37:29.000000000 +0100 +++ model3emu-patch/Src/Model3/Real3D.h 2017-12-17 12:53:30.000000000 +0100 @@ -406,7 +406,8 @@ 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 texelFormat, uint32_t byteSelect, 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); PK çl‘Kí­KÂ<Â< $ diff.patch † 4wÓ† 4wÓcöü3wÓPK\ê<