mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-05-13 15:25:07 +12:00
First Metal cleanup & formatting pass
This commit is contained in:
parent
4cc62d4870
commit
49b65242b9
17 changed files with 1084 additions and 1115 deletions
src/core/renderer_mtl
|
@ -1,124 +1,116 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "colour.hpp"
|
||||
#include "renderer_mtl/renderer_mtl.hpp"
|
||||
#include "renderer_mtl/mtl_texture.hpp"
|
||||
#include "renderer_mtl/renderer_mtl.hpp"
|
||||
|
||||
|
||||
using namespace Helpers;
|
||||
|
||||
namespace Metal {
|
||||
|
||||
static constexpr u32 signExtend3To32(u32 val) {
|
||||
return (u32)(s32(val) << 29 >> 29);
|
||||
}
|
||||
|
||||
u32 Texture::getTexelETC(bool hasAlpha, u32 u, u32 v, u32 width, std::span<const u8> data) {
|
||||
// Pixel offset of the 8x8 tile based on u, v and the width of the texture
|
||||
u32 offs = ((u & ~7) * 8) + ((v & ~7) * width);
|
||||
if (!hasAlpha)
|
||||
offs >>= 1;
|
||||
|
||||
// In-tile offsets for u/v
|
||||
u &= 7;
|
||||
v &= 7;
|
||||
|
||||
// ETC1(A4) also subdivide the 8x8 tile to 4 4x4 tiles
|
||||
// Each tile is 8 bytes for ETC1, but since ETC1A4 has 4 alpha bits per pixel, that becomes 16 bytes
|
||||
const u32 subTileSize = hasAlpha ? 16 : 8;
|
||||
const u32 subTileIndex = (u / 4) + 2 * (v / 4); // Which of the 4 subtiles is this texel in?
|
||||
|
||||
// In-subtile offsets for u/v
|
||||
u &= 3;
|
||||
v &= 3;
|
||||
offs += subTileSize * subTileIndex;
|
||||
|
||||
u32 alpha;
|
||||
const u64* ptr = reinterpret_cast<const u64*>(data.data() + offs); // Cast to u64*
|
||||
|
||||
if (hasAlpha) {
|
||||
// First 64 bits of the 4x4 subtile are alpha data
|
||||
const u64 alphaData = *ptr++;
|
||||
alpha = Colour::convert4To8Bit((alphaData >> (4 * (u * 4 + v))) & 0xf);
|
||||
}
|
||||
else {
|
||||
alpha = 0xff; // ETC1 without alpha uses ff for every pixel
|
||||
static constexpr u32 signExtend3To32(u32 val) {
|
||||
return (u32)(s32(val) << 29 >> 29);
|
||||
}
|
||||
|
||||
// Next 64 bits of the subtile are colour data
|
||||
u64 colourData = *ptr;
|
||||
return decodeETC(alpha, u, v, colourData);
|
||||
}
|
||||
u32 Texture::getTexelETC(bool hasAlpha, u32 u, u32 v, u32 width, std::span<const u8> data) {
|
||||
// Pixel offset of the 8x8 tile based on u, v and the width of the texture
|
||||
u32 offs = ((u & ~7) * 8) + ((v & ~7) * width);
|
||||
if (!hasAlpha) {
|
||||
offs >>= 1;
|
||||
}
|
||||
|
||||
u32 Texture::decodeETC(u32 alpha, u32 u, u32 v, u64 colourData) {
|
||||
static constexpr u32 modifiers[8][2] = {
|
||||
{ 2, 8 },
|
||||
{ 5, 17 },
|
||||
{ 9, 29 },
|
||||
{ 13, 42 },
|
||||
{ 18, 60 },
|
||||
{ 24, 80 },
|
||||
{ 33, 106 },
|
||||
{ 47, 183 },
|
||||
};
|
||||
// In-tile offsets for u/v
|
||||
u &= 7;
|
||||
v &= 7;
|
||||
|
||||
// Parse colour data for 4x4 block
|
||||
const u32 subindices = getBits<0, 16, u32>(colourData);
|
||||
const u32 negationFlags = getBits<16, 16, u32>(colourData);
|
||||
const bool flip = getBit<32>(colourData);
|
||||
const bool diffMode = getBit<33>(colourData);
|
||||
// ETC1(A4) also subdivide the 8x8 tile to 4 4x4 tiles
|
||||
// Each tile is 8 bytes for ETC1, but since ETC1A4 has 4 alpha bits per pixel, that becomes 16 bytes
|
||||
const u32 subTileSize = hasAlpha ? 16 : 8;
|
||||
const u32 subTileIndex = (u / 4) + 2 * (v / 4); // Which of the 4 subtiles is this texel in?
|
||||
|
||||
// Note: index1 is indeed stored on the higher bits, with index2 in the lower bits
|
||||
const u32 tableIndex1 = getBits<37, 3, u32>(colourData);
|
||||
const u32 tableIndex2 = getBits<34, 3, u32>(colourData);
|
||||
const u32 texelIndex = u * 4 + v; // Index of the texel in the block
|
||||
// In-subtile offsets for u/v
|
||||
u &= 3;
|
||||
v &= 3;
|
||||
offs += subTileSize * subTileIndex;
|
||||
|
||||
if (flip)
|
||||
std::swap(u, v);
|
||||
u32 alpha;
|
||||
const u64* ptr = reinterpret_cast<const u64*>(data.data() + offs); // Cast to u64*
|
||||
|
||||
s32 r, g, b;
|
||||
if (diffMode) {
|
||||
r = getBits<59, 5, s32>(colourData);
|
||||
g = getBits<51, 5, s32>(colourData);
|
||||
b = getBits<43, 5, s32>(colourData);
|
||||
if (hasAlpha) {
|
||||
// First 64 bits of the 4x4 subtile are alpha data
|
||||
const u64 alphaData = *ptr++;
|
||||
alpha = Colour::convert4To8Bit((alphaData >> (4 * (u * 4 + v))) & 0xf);
|
||||
} else {
|
||||
alpha = 0xff; // ETC1 without alpha uses ff for every pixel
|
||||
}
|
||||
|
||||
if (u >= 2) {
|
||||
r += signExtend3To32(getBits<56, 3, u32>(colourData));
|
||||
g += signExtend3To32(getBits<48, 3, u32>(colourData));
|
||||
b += signExtend3To32(getBits<40, 3, u32>(colourData));
|
||||
}
|
||||
// Next 64 bits of the subtile are colour data
|
||||
u64 colourData = *ptr;
|
||||
return decodeETC(alpha, u, v, colourData);
|
||||
}
|
||||
|
||||
// Expand from 5 to 8 bits per channel
|
||||
r = Colour::convert5To8Bit(r);
|
||||
g = Colour::convert5To8Bit(g);
|
||||
b = Colour::convert5To8Bit(b);
|
||||
} else {
|
||||
if (u < 2) {
|
||||
r = getBits<60, 4, s32>(colourData);
|
||||
g = getBits<52, 4, s32>(colourData);
|
||||
b = getBits<44, 4, s32>(colourData);
|
||||
} else {
|
||||
r = getBits<56, 4, s32>(colourData);
|
||||
g = getBits<48, 4, s32>(colourData);
|
||||
b = getBits<40, 4, s32>(colourData);
|
||||
}
|
||||
u32 Texture::decodeETC(u32 alpha, u32 u, u32 v, u64 colourData) {
|
||||
static constexpr u32 modifiers[8][2] = {
|
||||
{2, 8}, {5, 17}, {9, 29}, {13, 42}, {18, 60}, {24, 80}, {33, 106}, {47, 183},
|
||||
};
|
||||
|
||||
// Expand from 4 to 8 bits per channel
|
||||
r = Colour::convert4To8Bit(r);
|
||||
g = Colour::convert4To8Bit(g);
|
||||
b = Colour::convert4To8Bit(b);
|
||||
}
|
||||
// Parse colour data for 4x4 block
|
||||
const u32 subindices = getBits<0, 16, u32>(colourData);
|
||||
const u32 negationFlags = getBits<16, 16, u32>(colourData);
|
||||
const bool flip = getBit<32>(colourData);
|
||||
const bool diffMode = getBit<33>(colourData);
|
||||
|
||||
const u32 index = (u < 2) ? tableIndex1 : tableIndex2;
|
||||
s32 modifier = modifiers[index][(subindices >> texelIndex) & 1];
|
||||
// Note: index1 is indeed stored on the higher bits, with index2 in the lower bits
|
||||
const u32 tableIndex1 = getBits<37, 3, u32>(colourData);
|
||||
const u32 tableIndex2 = getBits<34, 3, u32>(colourData);
|
||||
const u32 texelIndex = u * 4 + v; // Index of the texel in the block
|
||||
|
||||
if (((negationFlags >> texelIndex) & 1) != 0) {
|
||||
modifier = -modifier;
|
||||
}
|
||||
if (flip) std::swap(u, v);
|
||||
|
||||
r = std::clamp(r + modifier, 0, 255);
|
||||
g = std::clamp(g + modifier, 0, 255);
|
||||
b = std::clamp(b + modifier, 0, 255);
|
||||
s32 r, g, b;
|
||||
if (diffMode) {
|
||||
r = getBits<59, 5, s32>(colourData);
|
||||
g = getBits<51, 5, s32>(colourData);
|
||||
b = getBits<43, 5, s32>(colourData);
|
||||
|
||||
return (alpha << 24) | (u32(b) << 16) | (u32(g) << 8) | u32(r);
|
||||
}
|
||||
if (u >= 2) {
|
||||
r += signExtend3To32(getBits<56, 3, u32>(colourData));
|
||||
g += signExtend3To32(getBits<48, 3, u32>(colourData));
|
||||
b += signExtend3To32(getBits<40, 3, u32>(colourData));
|
||||
}
|
||||
|
||||
} // namespace Metal
|
||||
// Expand from 5 to 8 bits per channel
|
||||
r = Colour::convert5To8Bit(r);
|
||||
g = Colour::convert5To8Bit(g);
|
||||
b = Colour::convert5To8Bit(b);
|
||||
} else {
|
||||
if (u < 2) {
|
||||
r = getBits<60, 4, s32>(colourData);
|
||||
g = getBits<52, 4, s32>(colourData);
|
||||
b = getBits<44, 4, s32>(colourData);
|
||||
} else {
|
||||
r = getBits<56, 4, s32>(colourData);
|
||||
g = getBits<48, 4, s32>(colourData);
|
||||
b = getBits<40, 4, s32>(colourData);
|
||||
}
|
||||
|
||||
// Expand from 4 to 8 bits per channel
|
||||
r = Colour::convert4To8Bit(r);
|
||||
g = Colour::convert4To8Bit(g);
|
||||
b = Colour::convert4To8Bit(b);
|
||||
}
|
||||
|
||||
const u32 index = (u < 2) ? tableIndex1 : tableIndex2;
|
||||
s32 modifier = modifiers[index][(subindices >> texelIndex) & 1];
|
||||
|
||||
if (((negationFlags >> texelIndex) & 1) != 0) {
|
||||
modifier = -modifier;
|
||||
}
|
||||
|
||||
r = std::clamp(r + modifier, 0, 255);
|
||||
g = std::clamp(g + modifier, 0, 255);
|
||||
b = std::clamp(b + modifier, 0, 255);
|
||||
|
||||
return (alpha << 24) | (u32(b) << 16) | (u32(g) << 8) | u32(r);
|
||||
}
|
||||
} // namespace Metal
|
||||
|
|
|
@ -1,32 +1,27 @@
|
|||
#include "renderer_mtl/renderer_mtl.hpp"
|
||||
|
||||
namespace Metal {
|
||||
static constexpr u32 LAYER_COUNT = 1024;
|
||||
|
||||
constexpr u32 LAYER_COUNT = 1024;
|
||||
LutTexture::LutTexture(MTL::Device* device, MTL::TextureType type, MTL::PixelFormat pixelFormat, u32 width, u32 height, const char* name) {
|
||||
MTL::TextureDescriptor* desc = MTL::TextureDescriptor::alloc()->init();
|
||||
desc->setTextureType(type);
|
||||
desc->setPixelFormat(pixelFormat);
|
||||
desc->setWidth(width);
|
||||
desc->setHeight(height);
|
||||
desc->setArrayLength(LAYER_COUNT);
|
||||
desc->setUsage(MTL::TextureUsageShaderRead /* | MTL::TextureUsageShaderWrite*/);
|
||||
desc->setStorageMode(MTL::StorageModeShared);
|
||||
|
||||
LutTexture::LutTexture(MTL::Device* device, MTL::TextureType type, MTL::PixelFormat pixelFormat, u32 width, u32 height, const char* name) {
|
||||
MTL::TextureDescriptor* desc = MTL::TextureDescriptor::alloc()->init();
|
||||
desc->setTextureType(type);
|
||||
desc->setPixelFormat(pixelFormat);
|
||||
desc->setWidth(width);
|
||||
desc->setHeight(height);
|
||||
desc->setArrayLength(LAYER_COUNT);
|
||||
desc->setUsage(MTL::TextureUsageShaderRead/* | MTL::TextureUsageShaderWrite*/);
|
||||
desc->setStorageMode(MTL::StorageModeShared);
|
||||
texture = device->newTexture(desc);
|
||||
texture->setLabel(toNSString(name));
|
||||
desc->release();
|
||||
}
|
||||
|
||||
texture = device->newTexture(desc);
|
||||
texture->setLabel(toNSString(name));
|
||||
desc->release();
|
||||
}
|
||||
LutTexture::~LutTexture() { texture->release(); }
|
||||
|
||||
LutTexture::~LutTexture() {
|
||||
texture->release();
|
||||
}
|
||||
|
||||
u32 LutTexture::getNextIndex() {
|
||||
currentIndex = (currentIndex + 1) % LAYER_COUNT;
|
||||
|
||||
return currentIndex;
|
||||
}
|
||||
|
||||
} // namespace Metal
|
||||
u32 LutTexture::getNextIndex() {
|
||||
currentIndex = (currentIndex + 1) % LAYER_COUNT;
|
||||
return currentIndex;
|
||||
}
|
||||
} // namespace Metal
|
||||
|
|
|
@ -1,312 +1,308 @@
|
|||
#include "renderer_mtl/mtl_texture.hpp"
|
||||
#include "renderer_mtl/objc_helper.hpp"
|
||||
#include "colour.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "colour.hpp"
|
||||
#include "renderer_mtl/objc_helper.hpp"
|
||||
|
||||
|
||||
using namespace Helpers;
|
||||
|
||||
namespace Metal {
|
||||
void Texture::allocate() {
|
||||
formatInfo = PICA::getPixelFormatInfo(format);
|
||||
|
||||
void Texture::allocate() {
|
||||
formatInfo = PICA::getPixelFormatInfo(format);
|
||||
MTL::TextureDescriptor* descriptor = MTL::TextureDescriptor::alloc()->init();
|
||||
descriptor->setTextureType(MTL::TextureType2D);
|
||||
descriptor->setPixelFormat(formatInfo.pixelFormat);
|
||||
descriptor->setWidth(size.u());
|
||||
descriptor->setHeight(size.v());
|
||||
descriptor->setUsage(MTL::TextureUsageShaderRead);
|
||||
descriptor->setStorageMode(MTL::StorageModeShared); // TODO: use private + staging buffers?
|
||||
texture = device->newTexture(descriptor);
|
||||
texture->setLabel(toNSString(
|
||||
"Texture " + std::string(PICA::textureFormatToString(format)) + " " + std::to_string(size.u()) + "x" + std::to_string(size.v())
|
||||
));
|
||||
descriptor->release();
|
||||
|
||||
MTL::TextureDescriptor* descriptor = MTL::TextureDescriptor::alloc()->init();
|
||||
descriptor->setTextureType(MTL::TextureType2D);
|
||||
descriptor->setPixelFormat(formatInfo.pixelFormat);
|
||||
descriptor->setWidth(size.u());
|
||||
descriptor->setHeight(size.v());
|
||||
descriptor->setUsage(MTL::TextureUsageShaderRead);
|
||||
descriptor->setStorageMode(MTL::StorageModeShared); // TODO: use private + staging buffers?
|
||||
texture = device->newTexture(descriptor);
|
||||
texture->setLabel(toNSString("Texture " + std::string(PICA::textureFormatToString(format)) + " " + std::to_string(size.u()) + "x" + std::to_string(size.v())));
|
||||
descriptor->release();
|
||||
|
||||
setNewConfig(config);
|
||||
}
|
||||
|
||||
// Set the texture's configuration, which includes min/mag filters, wrapping S/T modes, and so on
|
||||
void Texture::setNewConfig(u32 cfg) {
|
||||
config = cfg;
|
||||
|
||||
if (sampler) {
|
||||
sampler->release();
|
||||
}
|
||||
|
||||
const auto magFilter = (cfg & 0x2) != 0 ? MTL::SamplerMinMagFilterLinear : MTL::SamplerMinMagFilterNearest;
|
||||
const auto minFilter = (cfg & 0x4) != 0 ? MTL::SamplerMinMagFilterLinear : MTL::SamplerMinMagFilterNearest;
|
||||
const auto wrapT = PICA::toMTLSamplerAddressMode(getBits<8, 3>(cfg));
|
||||
const auto wrapS = PICA::toMTLSamplerAddressMode(getBits<12, 3>(cfg));
|
||||
|
||||
MTL::SamplerDescriptor* samplerDescriptor = MTL::SamplerDescriptor::alloc()->init();
|
||||
samplerDescriptor->setMinFilter(minFilter);
|
||||
samplerDescriptor->setMagFilter(magFilter);
|
||||
samplerDescriptor->setSAddressMode(wrapS);
|
||||
samplerDescriptor->setTAddressMode(wrapT);
|
||||
|
||||
samplerDescriptor->setLabel(toNSString("Sampler"));
|
||||
sampler = device->newSamplerState(samplerDescriptor);
|
||||
samplerDescriptor->release();
|
||||
}
|
||||
|
||||
void Texture::free() {
|
||||
valid = false;
|
||||
|
||||
if (texture) {
|
||||
texture->release();
|
||||
setNewConfig(config);
|
||||
}
|
||||
if (sampler) {
|
||||
sampler->release();
|
||||
}
|
||||
}
|
||||
|
||||
u64 Texture::sizeInBytes() {
|
||||
u64 pixelCount = u64(size.x()) * u64(size.y());
|
||||
// Set the texture's configuration, which includes min/mag filters, wrapping S/T modes, and so on
|
||||
void Texture::setNewConfig(u32 cfg) {
|
||||
config = cfg;
|
||||
|
||||
switch (format) {
|
||||
case PICA::TextureFmt::RGBA8: // 4 bytes per pixel
|
||||
return pixelCount * 4;
|
||||
if (sampler) {
|
||||
sampler->release();
|
||||
}
|
||||
|
||||
case PICA::TextureFmt::RGB8: // 3 bytes per pixel
|
||||
return pixelCount * 3;
|
||||
const auto magFilter = (cfg & 0x2) != 0 ? MTL::SamplerMinMagFilterLinear : MTL::SamplerMinMagFilterNearest;
|
||||
const auto minFilter = (cfg & 0x4) != 0 ? MTL::SamplerMinMagFilterLinear : MTL::SamplerMinMagFilterNearest;
|
||||
const auto wrapT = PICA::toMTLSamplerAddressMode(getBits<8, 3>(cfg));
|
||||
const auto wrapS = PICA::toMTLSamplerAddressMode(getBits<12, 3>(cfg));
|
||||
|
||||
case PICA::TextureFmt::RGBA5551: // 2 bytes per pixel
|
||||
case PICA::TextureFmt::RGB565:
|
||||
case PICA::TextureFmt::RGBA4:
|
||||
case PICA::TextureFmt::RG8:
|
||||
case PICA::TextureFmt::IA8:
|
||||
return pixelCount * 2;
|
||||
MTL::SamplerDescriptor* samplerDescriptor = MTL::SamplerDescriptor::alloc()->init();
|
||||
samplerDescriptor->setMinFilter(minFilter);
|
||||
samplerDescriptor->setMagFilter(magFilter);
|
||||
samplerDescriptor->setSAddressMode(wrapS);
|
||||
samplerDescriptor->setTAddressMode(wrapT);
|
||||
|
||||
case PICA::TextureFmt::A8: // 1 byte per pixel
|
||||
case PICA::TextureFmt::I8:
|
||||
case PICA::TextureFmt::IA4:
|
||||
return pixelCount;
|
||||
samplerDescriptor->setLabel(toNSString("Sampler"));
|
||||
sampler = device->newSamplerState(samplerDescriptor);
|
||||
samplerDescriptor->release();
|
||||
}
|
||||
|
||||
case PICA::TextureFmt::I4: // 4 bits per pixel
|
||||
case PICA::TextureFmt::A4:
|
||||
return pixelCount / 2;
|
||||
void Texture::free() {
|
||||
valid = false;
|
||||
|
||||
case PICA::TextureFmt::ETC1: // Compressed formats
|
||||
case PICA::TextureFmt::ETC1A4: {
|
||||
// Number of 4x4 tiles
|
||||
const u64 tileCount = pixelCount / 16;
|
||||
// Tiles are 8 bytes each on ETC1 and 16 bytes each on ETC1A4
|
||||
const u64 tileSize = format == PICA::TextureFmt::ETC1 ? 8 : 16;
|
||||
return tileCount * tileSize;
|
||||
}
|
||||
if (texture) {
|
||||
texture->release();
|
||||
}
|
||||
if (sampler) {
|
||||
sampler->release();
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
Helpers::panic("[PICA] Attempted to get size of invalid texture type");
|
||||
}
|
||||
}
|
||||
u64 Texture::sizeInBytes() {
|
||||
u64 pixelCount = u64(size.x()) * u64(size.y());
|
||||
|
||||
// u and v are the UVs of the relevant texel
|
||||
// Texture data is stored interleaved in Morton order, ie in a Z - order curve as shown here
|
||||
// https://en.wikipedia.org/wiki/Z-order_curve
|
||||
// Textures are split into 8x8 tiles.This function returns the in - tile offset depending on the u & v of the texel
|
||||
// The in - tile offset is the sum of 2 offsets, one depending on the value of u % 8 and the other on the value of y % 8
|
||||
// As documented in this picture https ://en.wikipedia.org/wiki/File:Moser%E2%80%93de_Bruijn_addition.svg
|
||||
u32 Texture::mortonInterleave(u32 u, u32 v) {
|
||||
static constexpr u32 xOffsets[] = { 0, 1, 4, 5, 16, 17, 20, 21 };
|
||||
static constexpr u32 yOffsets[] = { 0, 2, 8, 10, 32, 34, 40, 42 };
|
||||
switch (format) {
|
||||
case PICA::TextureFmt::RGBA8: // 4 bytes per pixel
|
||||
return pixelCount * 4;
|
||||
|
||||
return xOffsets[u & 7] + yOffsets[v & 7];
|
||||
}
|
||||
case PICA::TextureFmt::RGB8: // 3 bytes per pixel
|
||||
return pixelCount * 3;
|
||||
|
||||
// Get the byte offset of texel (u, v) in the texture
|
||||
u32 Texture::getSwizzledOffset(u32 u, u32 v, u32 width, u32 bytesPerPixel) {
|
||||
u32 offset = ((u & ~7) * 8) + ((v & ~7) * width); // Offset of the 8x8 tile the texel belongs to
|
||||
offset += mortonInterleave(u, v); // Add the in-tile offset of the texel
|
||||
case PICA::TextureFmt::RGBA5551: // 2 bytes per pixel
|
||||
case PICA::TextureFmt::RGB565:
|
||||
case PICA::TextureFmt::RGBA4:
|
||||
case PICA::TextureFmt::RG8:
|
||||
case PICA::TextureFmt::IA8: return pixelCount * 2;
|
||||
|
||||
return offset * bytesPerPixel;
|
||||
}
|
||||
case PICA::TextureFmt::A8: // 1 byte per pixel
|
||||
case PICA::TextureFmt::I8:
|
||||
case PICA::TextureFmt::IA4: return pixelCount;
|
||||
|
||||
// Same as the above code except we need to divide by 2 because 4 bits is smaller than a byte
|
||||
u32 Texture::getSwizzledOffset_4bpp(u32 u, u32 v, u32 width) {
|
||||
u32 offset = ((u & ~7) * 8) + ((v & ~7) * width); // Offset of the 8x8 tile the texel belongs to
|
||||
offset += mortonInterleave(u, v); // Add the in-tile offset of the texel
|
||||
case PICA::TextureFmt::I4: // 4 bits per pixel
|
||||
case PICA::TextureFmt::A4: return pixelCount / 2;
|
||||
|
||||
return offset / 2;
|
||||
}
|
||||
case PICA::TextureFmt::ETC1: // Compressed formats
|
||||
case PICA::TextureFmt::ETC1A4: {
|
||||
// Number of 4x4 tiles
|
||||
const u64 tileCount = pixelCount / 16;
|
||||
// Tiles are 8 bytes each on ETC1 and 16 bytes each on ETC1A4
|
||||
const u64 tileSize = format == PICA::TextureFmt::ETC1 ? 8 : 16;
|
||||
return tileCount * tileSize;
|
||||
}
|
||||
|
||||
u8 Texture::decodeTexelU8(u32 u, u32 v, PICA::TextureFmt fmt, std::span<const u8> data) {
|
||||
switch (fmt) {
|
||||
case PICA::TextureFmt::A4: {
|
||||
const u32 offset = getSwizzledOffset_4bpp(u, v, size.u());
|
||||
default: Helpers::panic("[PICA] Attempted to get size of invalid texture type");
|
||||
}
|
||||
}
|
||||
|
||||
// For odd U coordinates, grab the top 4 bits, and the low 4 bits for even coordinates
|
||||
u8 alpha = data[offset] >> ((u % 2) ? 4 : 0);
|
||||
alpha = Colour::convert4To8Bit(getBits<0, 4>(alpha));
|
||||
// u and v are the UVs of the relevant texel
|
||||
// Texture data is stored interleaved in Morton order, ie in a Z - order curve as shown here
|
||||
// https://en.wikipedia.org/wiki/Z-order_curve
|
||||
// Textures are split into 8x8 tiles.This function returns the in - tile offset depending on the u & v of the texel
|
||||
// The in - tile offset is the sum of 2 offsets, one depending on the value of u % 8 and the other on the value of y % 8
|
||||
// As documented in this picture https ://en.wikipedia.org/wiki/File:Moser%E2%80%93de_Bruijn_addition.svg
|
||||
u32 Texture::mortonInterleave(u32 u, u32 v) {
|
||||
static constexpr u32 xOffsets[] = {0, 1, 4, 5, 16, 17, 20, 21};
|
||||
static constexpr u32 yOffsets[] = {0, 2, 8, 10, 32, 34, 40, 42};
|
||||
|
||||
// A8
|
||||
return alpha;
|
||||
}
|
||||
return xOffsets[u & 7] + yOffsets[v & 7];
|
||||
}
|
||||
|
||||
case PICA::TextureFmt::A8: {
|
||||
u32 offset = getSwizzledOffset(u, v, size.u(), 1);
|
||||
const u8 alpha = data[offset];
|
||||
// Get the byte offset of texel (u, v) in the texture
|
||||
u32 Texture::getSwizzledOffset(u32 u, u32 v, u32 width, u32 bytesPerPixel) {
|
||||
u32 offset = ((u & ~7) * 8) + ((v & ~7) * width); // Offset of the 8x8 tile the texel belongs to
|
||||
offset += mortonInterleave(u, v); // Add the in-tile offset of the texel
|
||||
|
||||
// A8
|
||||
return alpha;
|
||||
}
|
||||
return offset * bytesPerPixel;
|
||||
}
|
||||
|
||||
default:
|
||||
Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast<int>(fmt));
|
||||
}
|
||||
}
|
||||
// Same as the above code except we need to divide by 2 because 4 bits is smaller than a byte
|
||||
u32 Texture::getSwizzledOffset_4bpp(u32 u, u32 v, u32 width) {
|
||||
u32 offset = ((u & ~7) * 8) + ((v & ~7) * width); // Offset of the 8x8 tile the texel belongs to
|
||||
offset += mortonInterleave(u, v); // Add the in-tile offset of the texel
|
||||
|
||||
u16 Texture::decodeTexelU16(u32 u, u32 v, PICA::TextureFmt fmt, std::span<const u8> data) {
|
||||
switch (fmt) {
|
||||
case PICA::TextureFmt::RG8: {
|
||||
u32 offset = getSwizzledOffset(u, v, size.u(), 2);
|
||||
constexpr u8 b = 0;
|
||||
const u8 g = data[offset];
|
||||
const u8 r = data[offset + 1];
|
||||
return offset / 2;
|
||||
}
|
||||
|
||||
// RG8
|
||||
return (g << 8) | r;
|
||||
}
|
||||
u8 Texture::decodeTexelU8(u32 u, u32 v, PICA::TextureFmt fmt, std::span<const u8> data) {
|
||||
switch (fmt) {
|
||||
case PICA::TextureFmt::A4: {
|
||||
const u32 offset = getSwizzledOffset_4bpp(u, v, size.u());
|
||||
|
||||
case PICA::TextureFmt::RGBA4: {
|
||||
u32 offset = getSwizzledOffset(u, v, size.u(), 2);
|
||||
u16 texel = u16(data[offset]) | (u16(data[offset + 1]) << 8);
|
||||
// For odd U coordinates, grab the top 4 bits, and the low 4 bits for even coordinates
|
||||
u8 alpha = data[offset] >> ((u % 2) ? 4 : 0);
|
||||
alpha = Colour::convert4To8Bit(getBits<0, 4>(alpha));
|
||||
|
||||
u8 alpha = getBits<0, 4, u8>(texel);
|
||||
u8 b = getBits<4, 4, u8>(texel);
|
||||
u8 g = getBits<8, 4, u8>(texel);
|
||||
u8 r = getBits<12, 4, u8>(texel);
|
||||
// A8
|
||||
return alpha;
|
||||
}
|
||||
|
||||
// ABGR4
|
||||
return (r << 12) | (g << 8) | (b << 4) | alpha;
|
||||
}
|
||||
case PICA::TextureFmt::A8: {
|
||||
u32 offset = getSwizzledOffset(u, v, size.u(), 1);
|
||||
const u8 alpha = data[offset];
|
||||
|
||||
case PICA::TextureFmt::RGBA5551: {
|
||||
const u32 offset = getSwizzledOffset(u, v, size.u(), 2);
|
||||
const u16 texel = u16(data[offset]) | (u16(data[offset + 1]) << 8);
|
||||
// A8
|
||||
return alpha;
|
||||
}
|
||||
|
||||
u8 alpha = getBit<0>(texel) ? 0xff : 0;
|
||||
u8 b = getBits<1, 5, u8>(texel);
|
||||
u8 g = getBits<6, 5, u8>(texel);
|
||||
u8 r = getBits<11, 5, u8>(texel);
|
||||
default: Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast<int>(fmt));
|
||||
}
|
||||
}
|
||||
|
||||
// BGR5A1
|
||||
return (alpha << 15) | (r << 10) | (g << 5) | b;
|
||||
}
|
||||
u16 Texture::decodeTexelU16(u32 u, u32 v, PICA::TextureFmt fmt, std::span<const u8> data) {
|
||||
switch (fmt) {
|
||||
case PICA::TextureFmt::RG8: {
|
||||
u32 offset = getSwizzledOffset(u, v, size.u(), 2);
|
||||
constexpr u8 b = 0;
|
||||
const u8 g = data[offset];
|
||||
const u8 r = data[offset + 1];
|
||||
|
||||
case PICA::TextureFmt::RGB565: {
|
||||
const u32 offset = getSwizzledOffset(u, v, size.u(), 2);
|
||||
const u16 texel = u16(data[offset]) | (u16(data[offset + 1]) << 8);
|
||||
// RG8
|
||||
return (g << 8) | r;
|
||||
}
|
||||
|
||||
const u8 b = getBits<0, 5, u8>(texel);
|
||||
const u8 g = getBits<5, 6, u8>(texel);
|
||||
const u8 r = getBits<11, 5, u8>(texel);
|
||||
case PICA::TextureFmt::RGBA4: {
|
||||
u32 offset = getSwizzledOffset(u, v, size.u(), 2);
|
||||
u16 texel = u16(data[offset]) | (u16(data[offset + 1]) << 8);
|
||||
|
||||
// B5G6R5
|
||||
return (r << 11) | (g << 5) | b;
|
||||
}
|
||||
u8 alpha = getBits<0, 4, u8>(texel);
|
||||
u8 b = getBits<4, 4, u8>(texel);
|
||||
u8 g = getBits<8, 4, u8>(texel);
|
||||
u8 r = getBits<12, 4, u8>(texel);
|
||||
|
||||
case PICA::TextureFmt::IA4: {
|
||||
const u32 offset = getSwizzledOffset(u, v, size.u(), 1);
|
||||
const u8 texel = data[offset];
|
||||
const u8 alpha = texel & 0xf;
|
||||
const u8 intensity = texel >> 4;
|
||||
// ABGR4
|
||||
return (r << 12) | (g << 8) | (b << 4) | alpha;
|
||||
}
|
||||
|
||||
// ABGR4
|
||||
return (intensity << 12) | (intensity << 8) | (intensity << 4) | alpha;
|
||||
}
|
||||
case PICA::TextureFmt::RGBA5551: {
|
||||
const u32 offset = getSwizzledOffset(u, v, size.u(), 2);
|
||||
const u16 texel = u16(data[offset]) | (u16(data[offset + 1]) << 8);
|
||||
|
||||
case PICA::TextureFmt::I4: {
|
||||
u32 offset = getSwizzledOffset_4bpp(u, v, size.u());
|
||||
u8 alpha = getBit<0>(texel) ? 0xff : 0;
|
||||
u8 b = getBits<1, 5, u8>(texel);
|
||||
u8 g = getBits<6, 5, u8>(texel);
|
||||
u8 r = getBits<11, 5, u8>(texel);
|
||||
|
||||
// For odd U coordinates, grab the top 4 bits, and the low 4 bits for even coordinates
|
||||
u8 intensity = data[offset] >> ((u % 2) ? 4 : 0);
|
||||
intensity = getBits<0, 4>(intensity);
|
||||
// BGR5A1
|
||||
return (alpha << 15) | (r << 10) | (g << 5) | b;
|
||||
}
|
||||
|
||||
// ABGR4
|
||||
return (intensity << 12) | (intensity << 8) | (intensity << 4) | 0xff;
|
||||
}
|
||||
case PICA::TextureFmt::RGB565: {
|
||||
const u32 offset = getSwizzledOffset(u, v, size.u(), 2);
|
||||
const u16 texel = u16(data[offset]) | (u16(data[offset + 1]) << 8);
|
||||
|
||||
default:
|
||||
Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast<int>(fmt));
|
||||
}
|
||||
}
|
||||
const u8 b = getBits<0, 5, u8>(texel);
|
||||
const u8 g = getBits<5, 6, u8>(texel);
|
||||
const u8 r = getBits<11, 5, u8>(texel);
|
||||
|
||||
u32 Texture::decodeTexelU32(u32 u, u32 v, PICA::TextureFmt fmt, std::span<const u8> data) {
|
||||
switch (fmt) {
|
||||
case PICA::TextureFmt::RGB8: {
|
||||
const u32 offset = getSwizzledOffset(u, v, size.u(), 3);
|
||||
const u8 b = data[offset];
|
||||
const u8 g = data[offset + 1];
|
||||
const u8 r = data[offset + 2];
|
||||
// B5G6R5
|
||||
return (r << 11) | (g << 5) | b;
|
||||
}
|
||||
|
||||
// RGBA8
|
||||
return (0xff << 24) | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
case PICA::TextureFmt::IA4: {
|
||||
const u32 offset = getSwizzledOffset(u, v, size.u(), 1);
|
||||
const u8 texel = data[offset];
|
||||
const u8 alpha = texel & 0xf;
|
||||
const u8 intensity = texel >> 4;
|
||||
|
||||
case PICA::TextureFmt::RGBA8: {
|
||||
const u32 offset = getSwizzledOffset(u, v, size.u(), 4);
|
||||
const u8 alpha = data[offset];
|
||||
const u8 b = data[offset + 1];
|
||||
const u8 g = data[offset + 2];
|
||||
const u8 r = data[offset + 3];
|
||||
// ABGR4
|
||||
return (intensity << 12) | (intensity << 8) | (intensity << 4) | alpha;
|
||||
}
|
||||
|
||||
// RGBA8
|
||||
return (alpha << 24) | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
case PICA::TextureFmt::I4: {
|
||||
u32 offset = getSwizzledOffset_4bpp(u, v, size.u());
|
||||
|
||||
case PICA::TextureFmt::I8: {
|
||||
u32 offset = getSwizzledOffset(u, v, size.u(), 1);
|
||||
const u8 intensity = data[offset];
|
||||
// For odd U coordinates, grab the top 4 bits, and the low 4 bits for even coordinates
|
||||
u8 intensity = data[offset] >> ((u % 2) ? 4 : 0);
|
||||
intensity = getBits<0, 4>(intensity);
|
||||
|
||||
// RGBA8
|
||||
return (0xff << 24) | (intensity << 16) | (intensity << 8) | intensity;
|
||||
}
|
||||
// ABGR4
|
||||
return (intensity << 12) | (intensity << 8) | (intensity << 4) | 0xff;
|
||||
}
|
||||
|
||||
case PICA::TextureFmt::IA8: {
|
||||
u32 offset = getSwizzledOffset(u, v, size.u(), 2);
|
||||
default: Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast<int>(fmt));
|
||||
}
|
||||
}
|
||||
|
||||
// Same as I8 except each pixel gets its own alpha value too
|
||||
const u8 alpha = data[offset];
|
||||
const u8 intensity = data[offset + 1];
|
||||
u32 Texture::decodeTexelU32(u32 u, u32 v, PICA::TextureFmt fmt, std::span<const u8> data) {
|
||||
switch (fmt) {
|
||||
case PICA::TextureFmt::RGB8: {
|
||||
const u32 offset = getSwizzledOffset(u, v, size.u(), 3);
|
||||
const u8 b = data[offset];
|
||||
const u8 g = data[offset + 1];
|
||||
const u8 r = data[offset + 2];
|
||||
|
||||
// RGBA8
|
||||
return (alpha << 24) | (intensity << 16) | (intensity << 8) | intensity;
|
||||
}
|
||||
// RGBA8
|
||||
return (0xff << 24) | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
|
||||
case PICA::TextureFmt::ETC1: return getTexelETC(false, u, v, size.u(), data);
|
||||
case PICA::TextureFmt::ETC1A4: return getTexelETC(true, u, v, size.u(), data);
|
||||
case PICA::TextureFmt::RGBA8: {
|
||||
const u32 offset = getSwizzledOffset(u, v, size.u(), 4);
|
||||
const u8 alpha = data[offset];
|
||||
const u8 b = data[offset + 1];
|
||||
const u8 g = data[offset + 2];
|
||||
const u8 r = data[offset + 3];
|
||||
|
||||
default:
|
||||
Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast<int>(fmt));
|
||||
}
|
||||
}
|
||||
// RGBA8
|
||||
return (alpha << 24) | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
|
||||
void Texture::decodeTexture(std::span<const u8> data) {
|
||||
std::vector<u8> decoded;
|
||||
decoded.reserve(u64(size.u()) * u64(size.v()) * formatInfo.bytesPerTexel);
|
||||
case PICA::TextureFmt::I8: {
|
||||
u32 offset = getSwizzledOffset(u, v, size.u(), 1);
|
||||
const u8 intensity = data[offset];
|
||||
|
||||
// Decode texels line by line
|
||||
for (u32 v = 0; v < size.v(); v++) {
|
||||
for (u32 u = 0; u < size.u(); u++) {
|
||||
if (formatInfo.bytesPerTexel == 1) {
|
||||
u8 texel = decodeTexelU8(u, v, format, data);
|
||||
decoded.push_back(texel);
|
||||
} else if (formatInfo.bytesPerTexel == 2) {
|
||||
u16 texel = decodeTexelU16(u, v, format, data);
|
||||
decoded.push_back((texel & 0x00ff) >> 0);
|
||||
decoded.push_back((texel & 0xff00) >> 8);
|
||||
} else if (formatInfo.bytesPerTexel == 4) {
|
||||
u32 texel = decodeTexelU32(u, v, format, data);
|
||||
decoded.push_back((texel & 0x000000ff) >> 0);
|
||||
decoded.push_back((texel & 0x0000ff00) >> 8);
|
||||
decoded.push_back((texel & 0x00ff0000) >> 16);
|
||||
decoded.push_back((texel & 0xff000000) >> 24);
|
||||
} else {
|
||||
Helpers::panic("[Texture::decodeTexture] Unimplemented bytesPerTexel (%u)", formatInfo.bytesPerTexel);
|
||||
}
|
||||
}
|
||||
}
|
||||
// RGBA8
|
||||
return (0xff << 24) | (intensity << 16) | (intensity << 8) | intensity;
|
||||
}
|
||||
|
||||
texture->replaceRegion(MTL::Region(0, 0, size.u(), size.v()), 0, 0, decoded.data(), formatInfo.bytesPerTexel * size.u(), 0);
|
||||
}
|
||||
case PICA::TextureFmt::IA8: {
|
||||
u32 offset = getSwizzledOffset(u, v, size.u(), 2);
|
||||
|
||||
} // namespace Metal
|
||||
// Same as I8 except each pixel gets its own alpha value too
|
||||
const u8 alpha = data[offset];
|
||||
const u8 intensity = data[offset + 1];
|
||||
|
||||
// RGBA8
|
||||
return (alpha << 24) | (intensity << 16) | (intensity << 8) | intensity;
|
||||
}
|
||||
|
||||
case PICA::TextureFmt::ETC1: return getTexelETC(false, u, v, size.u(), data);
|
||||
case PICA::TextureFmt::ETC1A4: return getTexelETC(true, u, v, size.u(), data);
|
||||
|
||||
default: Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast<int>(fmt));
|
||||
}
|
||||
}
|
||||
|
||||
void Texture::decodeTexture(std::span<const u8> data) {
|
||||
std::vector<u8> decoded;
|
||||
decoded.reserve(u64(size.u()) * u64(size.v()) * formatInfo.bytesPerTexel);
|
||||
|
||||
// Decode texels line by line
|
||||
for (u32 v = 0; v < size.v(); v++) {
|
||||
for (u32 u = 0; u < size.u(); u++) {
|
||||
if (formatInfo.bytesPerTexel == 1) {
|
||||
u8 texel = decodeTexelU8(u, v, format, data);
|
||||
decoded.push_back(texel);
|
||||
} else if (formatInfo.bytesPerTexel == 2) {
|
||||
u16 texel = decodeTexelU16(u, v, format, data);
|
||||
decoded.push_back((texel & 0x00ff) >> 0);
|
||||
decoded.push_back((texel & 0xff00) >> 8);
|
||||
} else if (formatInfo.bytesPerTexel == 4) {
|
||||
u32 texel = decodeTexelU32(u, v, format, data);
|
||||
decoded.push_back((texel & 0x000000ff) >> 0);
|
||||
decoded.push_back((texel & 0x0000ff00) >> 8);
|
||||
decoded.push_back((texel & 0x00ff0000) >> 16);
|
||||
decoded.push_back((texel & 0xff000000) >> 24);
|
||||
} else {
|
||||
Helpers::panic("[Texture::decodeTexture] Unimplemented bytesPerTexel (%u)", formatInfo.bytesPerTexel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
texture->replaceRegion(MTL::Region(0, 0, size.u(), size.v()), 0, 0, decoded.data(), formatInfo.bytesPerTexel * size.u(), 0);
|
||||
}
|
||||
} // namespace Metal
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
#include <cmrc/cmrc.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
#include "renderer_mtl/mtl_lut_texture.hpp"
|
||||
|
||||
// HACK
|
||||
// Hack: Apple annoyingly defines a global "NO" macro which ends up conflicting with our own code...
|
||||
#undef NO
|
||||
|
||||
#include "PICA/gpu.hpp"
|
||||
|
@ -14,8 +15,10 @@ using namespace PICA;
|
|||
|
||||
CMRC_DECLARE(RendererMTL);
|
||||
|
||||
const u16 LIGHTING_LUT_TEXTURE_WIDTH = 256;
|
||||
const u32 FOG_LUT_TEXTURE_WIDTH = 128;
|
||||
static constexpr u16 LIGHTING_LUT_TEXTURE_WIDTH = 256;
|
||||
static constexpr u32 FOG_LUT_TEXTURE_WIDTH = 128;
|
||||
// Bind the vertex buffer to binding 30 so that it doesn't occupy the lower indices
|
||||
static constexpr uint VERTEX_BUFFER_BINDING_INDEX = 30;
|
||||
|
||||
// HACK: redefinition...
|
||||
PICA::ColorFmt ToColorFormat(u32 format) {
|
||||
|
@ -40,6 +43,7 @@ MTL::Library* loadLibrary(MTL::Device* device, const cmrc::file& shaderSource) {
|
|||
|
||||
RendererMTL::RendererMTL(GPU& gpu, const std::array<u32, regNum>& internalRegs, const std::array<u32, extRegNum>& externalRegs)
|
||||
: Renderer(gpu, internalRegs, externalRegs) {}
|
||||
|
||||
RendererMTL::~RendererMTL() {}
|
||||
|
||||
void RendererMTL::reset() {
|
||||
|
@ -78,7 +82,7 @@ void RendererMTL::display() {
|
|||
clearColor(nullptr, bottomScreen->get().texture);
|
||||
}
|
||||
|
||||
// -------- Draw --------
|
||||
// Draw
|
||||
commandBuffer->pushDebugGroup(toNSString("Display"));
|
||||
|
||||
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||
|
@ -130,8 +134,6 @@ void RendererMTL::initGraphicsContext(SDL_Window* window) {
|
|||
metalLayer->setDevice(device);
|
||||
commandQueue = device->newCommandQueue();
|
||||
|
||||
// -------- Objects --------
|
||||
|
||||
// Textures
|
||||
MTL::TextureDescriptor* textureDescriptor = MTL::TextureDescriptor::alloc()->init();
|
||||
textureDescriptor->setTextureType(MTL::TextureType2D);
|
||||
|
@ -157,7 +159,9 @@ void RendererMTL::initGraphicsContext(SDL_Window* window) {
|
|||
|
||||
samplerDescriptor->release();
|
||||
|
||||
lutLightingTexture = new Metal::LutTexture(device, MTL::TextureType2DArray, MTL::PixelFormatR16Unorm, LIGHTING_LUT_TEXTURE_WIDTH, Lights::LUT_Count, "Lighting LUT texture");
|
||||
lutLightingTexture = new Metal::LutTexture(
|
||||
device, MTL::TextureType2DArray, MTL::PixelFormatR16Unorm, LIGHTING_LUT_TEXTURE_WIDTH, Lights::LUT_Count, "Lighting LUT texture"
|
||||
);
|
||||
lutFogTexture = new Metal::LutTexture(device, MTL::TextureType1DArray, MTL::PixelFormatRG32Float, FOG_LUT_TEXTURE_WIDTH, 1, "Fog LUT texture");
|
||||
|
||||
// -------- Pipelines --------
|
||||
|
@ -166,7 +170,7 @@ void RendererMTL::initGraphicsContext(SDL_Window* window) {
|
|||
auto mtlResources = cmrc::RendererMTL::get_filesystem();
|
||||
library = loadLibrary(device, mtlResources.open("metal_shaders.metallib"));
|
||||
MTL::Library* blitLibrary = loadLibrary(device, mtlResources.open("metal_blit.metallib"));
|
||||
//MTL::Library* copyToLutTextureLibrary = loadLibrary(device, mtlResources.open("metal_copy_to_lut_texture.metallib"));
|
||||
// MTL::Library* copyToLutTextureLibrary = loadLibrary(device, mtlResources.open("metal_copy_to_lut_texture.metallib"));
|
||||
|
||||
// Display
|
||||
MTL::Function* vertexDisplayFunction = library->newFunction(NS::String::string("vertexDisplay", NS::ASCIIStringEncoding));
|
||||
|
@ -295,9 +299,8 @@ void RendererMTL::initGraphicsContext(SDL_Window* window) {
|
|||
defaultDepthStencilState = device->newDepthStencilState(depthStencilDescriptor);
|
||||
depthStencilDescriptor->release();
|
||||
|
||||
// Release
|
||||
blitLibrary->release();
|
||||
//copyToLutTextureLibrary->release();
|
||||
// copyToLutTextureLibrary->release();
|
||||
}
|
||||
|
||||
void RendererMTL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) {
|
||||
|
@ -592,8 +595,7 @@ void RendererMTL::deinitGraphicsContext() {
|
|||
delete lutLightingTexture;
|
||||
delete lutFogTexture;
|
||||
|
||||
// Release
|
||||
//copyToLutTexturePipeline->release();
|
||||
// copyToLutTexturePipeline->release();
|
||||
displayPipeline->release();
|
||||
defaultDepthStencilState->release();
|
||||
nullTexture->release();
|
||||
|
@ -700,9 +702,9 @@ void RendererMTL::bindTexturesToSlots() {
|
|||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if ((regs[PICA::InternalRegs::TexUnitCfg] & (1 << i)) == 0) {
|
||||
commandEncoder.setFragmentTexture(nullTexture, i);
|
||||
commandEncoder.setFragmentSamplerState(nearestSampler, i);
|
||||
continue;
|
||||
commandEncoder.setFragmentTexture(nullTexture, i);
|
||||
commandEncoder.setFragmentSamplerState(nearestSampler, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
const size_t ioBase = ioBases[i];
|
||||
|
@ -736,7 +738,9 @@ void RendererMTL::updateLightingLUT(MTL::RenderCommandEncoder* encoder) {
|
|||
}
|
||||
|
||||
u32 index = lutLightingTexture->getNextIndex();
|
||||
lutLightingTexture->getTexture()->replaceRegion(MTL::Region(0, 0, LIGHTING_LUT_TEXTURE_WIDTH, Lights::LUT_Count), 0, index, lightingLut.data(), LIGHTING_LUT_TEXTURE_WIDTH * 2, 0);
|
||||
lutLightingTexture->getTexture()->replaceRegion(
|
||||
MTL::Region(0, 0, LIGHTING_LUT_TEXTURE_WIDTH, Lights::LUT_Count), 0, index, lightingLut.data(), LIGHTING_LUT_TEXTURE_WIDTH * 2, 0
|
||||
);
|
||||
|
||||
/*
|
||||
endRenderPass();
|
||||
|
@ -768,7 +772,7 @@ void RendererMTL::updateLightingLUT(MTL::RenderCommandEncoder* encoder) {
|
|||
void RendererMTL::updateFogLUT(MTL::RenderCommandEncoder* encoder) {
|
||||
gpu.fogLUTDirty = false;
|
||||
|
||||
std::array<float, FOG_LUT_TEXTURE_WIDTH * 2> fogLut = {0.0f};
|
||||
std::array<float, FOG_LUT_TEXTURE_WIDTH* 2> fogLut = {0.0f};
|
||||
|
||||
for (int i = 0; i < fogLut.size(); i += 2) {
|
||||
const uint32_t value = gpu.fogLUT[i >> 1];
|
||||
|
@ -807,7 +811,8 @@ void RendererMTL::textureCopyImpl(
|
|||
) {
|
||||
nextRenderPassName = "Texture copy";
|
||||
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||
// TODO: clearColor sets the load action to load if it didn't find any clear, but that is unnecessary if we are doing a copy to the whole texture
|
||||
// TODO: clearColor sets the load action to load if it didn't find any clear, but that is unnecessary if we are doing a copy to the whole
|
||||
// texture
|
||||
bool doesClear = clearColor(renderPassDescriptor, destFramebuffer.texture);
|
||||
beginRenderPassIfNeeded(renderPassDescriptor, doesClear, destFramebuffer.texture);
|
||||
|
||||
|
@ -819,11 +824,13 @@ void RendererMTL::textureCopyImpl(
|
|||
|
||||
// Viewport
|
||||
renderCommandEncoder->setViewport(MTL::Viewport{
|
||||
double(destRect.left), double(destRect.bottom), double(destRect.right - destRect.left), double(destRect.top - destRect.bottom), 0.0, 1.0
|
||||
});
|
||||
double(destRect.left), double(destRect.bottom), double(destRect.right - destRect.left), double(destRect.top - destRect.bottom), 0.0, 1.0});
|
||||
|
||||
float srcRectNDC[4] = {
|
||||
srcRect.left / (float)srcFramebuffer.size.u(), srcRect.bottom / (float)srcFramebuffer.size.v(),
|
||||
(srcRect.right - srcRect.left) / (float)srcFramebuffer.size.u(), (srcRect.top - srcRect.bottom) / (float)srcFramebuffer.size.v()
|
||||
srcRect.left / (float)srcFramebuffer.size.u(),
|
||||
srcRect.bottom / (float)srcFramebuffer.size.v(),
|
||||
(srcRect.right - srcRect.left) / (float)srcFramebuffer.size.u(),
|
||||
(srcRect.top - srcRect.bottom) / (float)srcFramebuffer.size.v(),
|
||||
};
|
||||
|
||||
// Bind resources
|
||||
|
@ -834,25 +841,28 @@ void RendererMTL::textureCopyImpl(
|
|||
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4));
|
||||
}
|
||||
|
||||
void RendererMTL::beginRenderPassIfNeeded(MTL::RenderPassDescriptor* renderPassDescriptor, bool doesClears, MTL::Texture* colorTexture, MTL::Texture* depthTexture) {
|
||||
void RendererMTL::beginRenderPassIfNeeded(
|
||||
MTL::RenderPassDescriptor* renderPassDescriptor, bool doesClears, MTL::Texture* colorTexture, MTL::Texture* depthTexture
|
||||
) {
|
||||
createCommandBufferIfNeeded();
|
||||
|
||||
if (doesClears || !renderCommandEncoder || colorTexture != lastColorTexture || (depthTexture != lastDepthTexture && !(lastDepthTexture && !depthTexture))) {
|
||||
endRenderPass();
|
||||
if (doesClears || !renderCommandEncoder || colorTexture != lastColorTexture ||
|
||||
(depthTexture != lastDepthTexture && !(lastDepthTexture && !depthTexture))) {
|
||||
endRenderPass();
|
||||
|
||||
renderCommandEncoder = commandBuffer->renderCommandEncoder(renderPassDescriptor);
|
||||
renderCommandEncoder->setLabel(toNSString(nextRenderPassName));
|
||||
commandEncoder.newRenderCommandEncoder(renderCommandEncoder);
|
||||
renderCommandEncoder = commandBuffer->renderCommandEncoder(renderPassDescriptor);
|
||||
renderCommandEncoder->setLabel(toNSString(nextRenderPassName));
|
||||
commandEncoder.newRenderCommandEncoder(renderCommandEncoder);
|
||||
|
||||
// Bind persistent resources
|
||||
// Bind persistent resources
|
||||
|
||||
// LUT texture
|
||||
renderCommandEncoder->setFragmentTexture(lutLightingTexture->getTexture(), 3);
|
||||
renderCommandEncoder->setFragmentTexture(lutFogTexture->getTexture(), 4);
|
||||
renderCommandEncoder->setFragmentSamplerState(linearSampler, 3);
|
||||
// LUT texture
|
||||
renderCommandEncoder->setFragmentTexture(lutLightingTexture->getTexture(), 3);
|
||||
renderCommandEncoder->setFragmentTexture(lutFogTexture->getTexture(), 4);
|
||||
renderCommandEncoder->setFragmentSamplerState(linearSampler, 3);
|
||||
|
||||
lastColorTexture = colorTexture;
|
||||
lastDepthTexture = depthTexture;
|
||||
lastColorTexture = colorTexture;
|
||||
lastDepthTexture = depthTexture;
|
||||
}
|
||||
|
||||
renderPassDescriptor->release();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue