use sampler states

This commit is contained in:
Samuliak 2024-07-03 17:45:55 +02:00
parent 9527c2acdb
commit b6c72e72e4
6 changed files with 50 additions and 14 deletions

View file

@ -26,6 +26,7 @@ struct Texture {
Interval<u32> range;
MTL::Texture* texture = nullptr;
MTL::SamplerState* sampler = nullptr;
Texture() : valid(false) {}

View file

@ -110,4 +110,20 @@ inline MTL::PrimitiveType toMTLPrimitiveType(PrimType primType) {
}
}
inline MTL::SamplerAddressMode toMTLSamplerAddressMode(u8 addrMode) {
switch (addrMode) {
case 0: return MTL::SamplerAddressModeClampToEdge;
case 1: return MTL::SamplerAddressModeClampToBorderColor;
case 2: return MTL::SamplerAddressModeRepeat;
case 3: return MTL::SamplerAddressModeMirrorRepeat;
case 4: return MTL::SamplerAddressModeClampToEdge;
case 5: return MTL::SamplerAddressModeClampToBorderColor;
case 6: return MTL::SamplerAddressModeRepeat;
case 7: return MTL::SamplerAddressModeRepeat;
default: panic("Unknown sampler address mode %u", addrMode);
}
return MTL::SamplerAddressModeClampToEdge;
}
} // namespace PICA

View file

@ -97,7 +97,7 @@ class RendererMTL final : public Renderer {
std::optional<Metal::ColorRenderTarget> getColorRenderTarget(u32 addr, PICA::ColorFmt format, u32 width, u32 height, bool createIfnotFound = true);
Metal::DepthStencilRenderTarget& getDepthRenderTarget();
MTL::Texture* getTexture(Metal::Texture& tex);
Metal::Texture& getTexture(Metal::Texture& tex);
void setupTextureEnvState(MTL::RenderCommandEncoder* encoder);
void bindTexturesToSlots(MTL::RenderCommandEncoder* encoder);
};

View file

@ -1,4 +1,5 @@
#include "renderer_mtl/mtl_texture.hpp"
#include "renderer_mtl/pica_to_mtl.hpp"
#include "colour.hpp"
#include <array>
@ -23,7 +24,22 @@ void Texture::allocate() {
void Texture::setNewConfig(u32 cfg) {
config = cfg;
// TODO: implement this
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);
sampler = device->newSamplerState(samplerDescriptor);
}
void Texture::free() {
@ -32,6 +48,9 @@ void Texture::free() {
if (texture) {
texture->release();
}
if (sampler) {
sampler->release();
}
}
u64 Texture::sizeInBytes() {

View file

@ -453,17 +453,17 @@ Metal::DepthStencilRenderTarget& RendererMTL::getDepthRenderTarget() {
}
}
MTL::Texture* RendererMTL::getTexture(Metal::Texture& tex) {
Metal::Texture& RendererMTL::getTexture(Metal::Texture& tex) {
auto buffer = textureCache.find(tex);
if (buffer.has_value()) {
return buffer.value().get().texture;
return buffer.value().get();
} else {
const auto textureData = std::span{gpu.getPointerPhys<u8>(tex.location), tex.sizeInBytes()}; // Get pointer to the texture data in 3DS memory
Metal::Texture& newTex = textureCache.add(tex);
newTex.decodeTexture(textureData);
return newTex.texture;
return newTex;
}
}
@ -518,8 +518,9 @@ void RendererMTL::bindTexturesToSlots(MTL::RenderCommandEncoder* encoder) {
if (addr != 0) [[likely]] {
Metal::Texture targetTex(device, addr, static_cast<PICA::TextureFmt>(format), width, height, config);
MTL::Texture* tex = getTexture(targetTex);
encoder->setFragmentTexture(tex, i);
auto tex = getTexture(targetTex);
encoder->setFragmentTexture(tex.texture, i);
encoder->setFragmentSamplerState(tex.sampler ? tex.sampler : basicSampler, i);
} else {
// TODO: bind a dummy texture?
}

View file

@ -247,10 +247,9 @@ struct FragTEV {
}
};
fragment float4 fragmentDraw(DrawVertexOut in [[stage_in]], constant PicaRegs& picaRegs [[buffer(0)]], constant FragTEV& tev [[buffer(1)]], texture2d<float> tex0 [[texture(0)]], texture2d<float> tex1 [[texture(1)]], texture2d<float> tex2 [[texture(2)]]) {
// TODO: upload this as argument
sampler samplr;
fragment float4 fragmentDraw(DrawVertexOut in [[stage_in]], constant PicaRegs& picaRegs [[buffer(0)]], constant FragTEV& tev [[buffer(1)]],
texture2d<float> tex0 [[texture(0)]], texture2d<float> tex1 [[texture(1)]], texture2d<float> tex2 [[texture(2)]],
sampler samplr0 [[sampler(0)]], sampler samplr1 [[sampler(1)]], sampler samplr2 [[sampler(2)]]) {
Globals globals;
globals.tevSources[0] = in.color;
// TODO: uncomment
@ -259,9 +258,9 @@ fragment float4 fragmentDraw(DrawVertexOut in [[stage_in]], constant PicaRegs& p
uint textureConfig = picaRegs.read(0x80u);
float2 texCoord2 = (textureConfig & (1u << 13)) != 0u ? in.texCoord1 : in.texCoord2;
if ((textureConfig & 1u) != 0u) globals.tevSources[3] = tex0.sample(samplr, in.texCoord0.xy);
if ((textureConfig & 2u) != 0u) globals.tevSources[4] = tex1.sample(samplr, in.texCoord1);
if ((textureConfig & 4u) != 0u) globals.tevSources[5] = tex2.sample(samplr, texCoord2);
if ((textureConfig & 1u) != 0u) globals.tevSources[3] = tex0.sample(samplr0, in.texCoord0.xy);
if ((textureConfig & 2u) != 0u) globals.tevSources[4] = tex1.sample(samplr1, in.texCoord1);
if ((textureConfig & 4u) != 0u) globals.tevSources[5] = tex2.sample(samplr2, texCoord2);
globals.tevSources[13] = float4(0.0); // Previous buffer
globals.tevSources[15] = in.color; // Previous combiner