Skip to content

Commit

Permalink
Blit framebuffer
Browse files Browse the repository at this point in the history
  • Loading branch information
IsaacMarovitz committed Jan 1, 2025
1 parent 4fec795 commit 9b4ab19
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 11 deletions.
22 changes: 22 additions & 0 deletions core/rend/metal/metal_pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,28 @@ MetalPipelineManager::MetalPipelineManager(MetalRenderer *renderer) {
this->renderer = renderer;
}

void MetalPipelineManager::CreateBlitPassPipeline() {
MTL::RenderPipelineDescriptor *descriptor = MTL::RenderPipelineDescriptor::alloc()->init();
descriptor->setLabel(NS::String::string("Blit Pass", NS::UTF8StringEncoding));

auto attachment = descriptor->colorAttachments()->object(0);
attachment->setPixelFormat(MTL::PixelFormatBGRA8Unorm);

descriptor->setVertexFunction(renderer->GetShaders()->GetBlitVertexShader());
descriptor->setFragmentFunction(renderer->GetShaders()->GetBlitFragmentShader());

NS::Error *error = nullptr;
auto state = MetalContext::Instance()->GetDevice()->newRenderPipelineState(descriptor, &error);

if (state == nullptr) {
ERROR_LOG(RENDERER, "Failed to create Blit Pipeline State: %s", error->localizedDescription()->utf8String());
}

descriptor->release();

blitPassPipeline = state;
}


void MetalPipelineManager::CreateDepthPassPipeline(int cullMode, bool naomi2)
{
Expand Down
11 changes: 11 additions & 0 deletions core/rend/metal/metal_pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ class MetalPipelineManager
depthPassDepthStencilStates.clear();
}

MTL::RenderPipelineState* GetBlitPassPipeline() {
if (blitPassPipeline != nullptr)
return blitPassPipeline;

CreateBlitPassPipeline();

return blitPassPipeline;
}

MTL::RenderPipelineState* GetDepthPassPipeline(int cullMode, bool naomi2)
{
u32 pipehash = hash(cullMode, naomi2);
Expand Down Expand Up @@ -85,6 +94,7 @@ class MetalPipelineManager
}

private:
void CreateBlitPassPipeline();
void CreateDepthPassPipeline(int cullMode, bool naomi2);
void CreatePipeline(u32 listType, bool sortTriangles, const PolyParam& pp, int gpuPalette, bool dithering);

Expand Down Expand Up @@ -174,6 +184,7 @@ class MetalPipelineManager
}

MetalRenderer *renderer;
MTL::RenderPipelineState* blitPassPipeline = nullptr;
std::map<u64, MTL::RenderPipelineState*> pipelines;
std::map<u32, MTL::RenderPipelineState*> depthPassPipelines;

Expand Down
39 changes: 28 additions & 11 deletions core/rend/metal/metal_renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,16 +461,16 @@ bool MetalRenderer::Draw(const MetalTexture *fogTexture, const MetalTexture *pal
depthAttachmentDescriptor->release();
stencilAttachmentDescriptor->release();

MTL::RenderCommandEncoder *encoder = buffer->renderCommandEncoder(descriptor);
MTL::RenderCommandEncoder *renderEncoder = buffer->renderCommandEncoder(descriptor);

descriptor->release();

if (fogTexture == nullptr) {
encoder->setFragmentTexture(fogTexture->texture, 2);
renderEncoder->setFragmentTexture(fogTexture->texture, 2);
}

if (paletteTexture == nullptr) {
encoder->setFragmentTexture(paletteTexture->texture, 3);
renderEncoder->setFragmentTexture(paletteTexture->texture, 3);
}

// Upload vertex and index buffers
Expand All @@ -479,8 +479,8 @@ bool MetalRenderer::Draw(const MetalTexture *fogTexture, const MetalTexture *pal

UploadMainBuffer(vtxUniforms, fragUniforms);

encoder->setVertexBuffer(curMainBuffer, offsets.vertexUniformOffset, 0);
encoder->setFragmentBuffer(curMainBuffer, offsets.fragmentUniformOffset, 0);
renderEncoder->setVertexBuffer(curMainBuffer, offsets.vertexUniformOffset, 0);
renderEncoder->setFragmentBuffer(curMainBuffer, offsets.fragmentUniformOffset, 0);

RenderPass previous_pass {};
for (int render_pass = 0; render_pass < (int)pvrrc.render_passes.size(); render_pass++) {
Expand All @@ -491,18 +491,35 @@ bool MetalRenderer::Draw(const MetalTexture *fogTexture, const MetalTexture *pal
current_pass.pt_count - previous_pass.pt_count,
current_pass.tr_count - previous_pass.tr_count,
current_pass.mvo_count - previous_pass.mvo_count, current_pass.autosort);
DrawList(encoder, ListType_Opaque, false, pvrrc.global_param_op, previous_pass.op_count, current_pass.op_count);
DrawList(encoder, ListType_Punch_Through, false, pvrrc.global_param_pt, previous_pass.pt_count, current_pass.pt_count);
DrawModVols(encoder, previous_pass.mvo_count, current_pass.mvo_count - previous_pass.mvo_count);
DrawList(renderEncoder, ListType_Opaque, false, pvrrc.global_param_op, previous_pass.op_count, current_pass.op_count);
DrawList(renderEncoder, ListType_Punch_Through, false, pvrrc.global_param_pt, previous_pass.pt_count, current_pass.pt_count);
DrawModVols(renderEncoder, previous_pass.mvo_count, current_pass.mvo_count - previous_pass.mvo_count);
if (current_pass.autosort) {
if (!config::PerStripSorting)
DrawSorted(encoder, pvrrc.sortedTriangles, previous_pass.sorted_tr_count, current_pass.sorted_tr_count, render_pass + 1 < (int)pvrrc.render_passes.size());
DrawSorted(renderEncoder, pvrrc.sortedTriangles, previous_pass.sorted_tr_count, current_pass.sorted_tr_count, render_pass + 1 < (int)pvrrc.render_passes.size());
} else {
DrawList(encoder, ListType_Translucent, false, pvrrc.global_param_tr, previous_pass.tr_count, current_pass.tr_count);
DrawList(renderEncoder, ListType_Translucent, false, pvrrc.global_param_tr, previous_pass.tr_count, current_pass.tr_count);
}
}

encoder->endEncoding();
renderEncoder->endEncoding();

// Blit to framebuffer
descriptor = MTL::RenderPassDescriptor::alloc()->init();
color = descriptor->colorAttachments()->object(0);
color->setTexture(drawable->texture());
color->setLoadAction(MTL::LoadActionClear);
color->setStoreAction(MTL::StoreActionStore);

renderEncoder = buffer->renderCommandEncoder(descriptor);

descriptor->release();

renderEncoder->setRenderPipelineState(pipelineManager.GetBlitPassPipeline());
renderEncoder->setFragmentTexture(frameBuffer, 0);
renderEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, static_cast<NS::UInteger>(0), 4);
renderEncoder->endEncoding();

buffer->presentDrawable(drawable);
buffer->commit();
pool->release();
Expand Down
59 changes: 59 additions & 0 deletions core/rend/metal/metal_shaders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,44 @@ fragment FragmentOut fs_main(VertexOut in [[stage_in]], constant FragmentShaderU
}
)";

static const char BlitShader[] = R"(
#include <metal_stdlib>
using namespace metal;
struct VertexOut {
float4 position [[position]];
float2 texCoord;
};
vertex VertexOut vs_main(uint vertexID [[vertex_id]]) {
// Predefined positions and texture coordinates for a full-screen quad
float4 positions[4] = {
float4(-1.0, -1.0, 0.0, 1.0), // Bottom-left
float4( 1.0, -1.0, 0.0, 1.0), // Bottom-right
float4(-1.0, 1.0, 0.0, 1.0), // Top-left
float4( 1.0, 1.0, 0.0, 1.0) // Top-right
};
float2 texCoords[4] = {
float2(0.0, 1.0), // Bottom-left
float2(1.0, 1.0), // Bottom-right
float2(0.0, 0.0), // Top-left
float2(1.0, 0.0) // Top-right
};
VertexOut out;
out.position = positions[vertexID];
out.texCoord = texCoords[vertexID];
return out;
}
fragment float4 fs_main(VertexOut in [[stage_in]],
texture2d<float> sourceTexture [[texture(0)]]) {
constexpr sampler textureSampler(mag_filter::linear, min_filter::linear);
return sourceTexture.sample(textureSampler, in.texCoord);
}
)";

// TODO: Handle gouraud interpolation
// TODO: N2 Shaders

Expand All @@ -358,6 +396,27 @@ MetalShaders::MetalShaders() {
ERROR_LOG(RENDERER, "%s", error->localizedDescription()->utf8String());
assert(false);
}

blitShaderLibrary = device->newLibrary(NS::String::string(BlitShader, NS::UTF8StringEncoding), nullptr, &error);

if (!blitShaderLibrary) {
ERROR_LOG(RENDERER, "%s", error->localizedDescription()->utf8String());
assert(false);
}

blitVertexShader = blitShaderLibrary->newFunction(NS::String::string("vs_main", NS::UTF8StringEncoding), nullptr, &error);

if (!blitVertexShader) {
ERROR_LOG(RENDERER, "%s", error->localizedDescription()->utf8String());
assert(false);
}

blitFragmentShader = blitShaderLibrary->newFunction(NS::String::string("fs_main", NS::UTF8StringEncoding), nullptr, &error);

if (!blitFragmentShader) {
ERROR_LOG(RENDERER, "%s", error->localizedDescription()->utf8String());
assert(false);
}
}

MTL::Function *MetalShaders::compileShader(const VertexShaderParams &params) {
Expand Down
7 changes: 7 additions & 0 deletions core/rend/metal/metal_shaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class MetalShaders
public:
MetalShaders();

MTL::Function *GetBlitVertexShader() { return blitVertexShader; }
MTL::Function *GetBlitFragmentShader() { return blitFragmentShader; }

MTL::Function *GetVertexShader(const VertexShaderParams& params) { return getShader(vertexShaders, params); }
MTL::Function *GetFragmentShader(const FragmentShaderParams& params) { return getShader(fragmentShaders, params); }

Expand All @@ -97,6 +100,7 @@ class MetalShaders
}

private:
MTL::Library *blitShaderLibrary;
MTL::Library *vertexShaderLibrary;
MTL::Library *fragmentShaderLibrary;
MTL::FunctionConstantValues *vertexShaderConstants;
Expand All @@ -115,6 +119,9 @@ class MetalShaders
MTL::Function *compileShader(const VertexShaderParams& params);
MTL::Function *compileShader(const FragmentShaderParams& params);

MTL::Function* blitVertexShader;
MTL::Function* blitFragmentShader;

std::map<u32, MTL::Function*> vertexShaders;
std::map<u32, MTL::Function*> fragmentShaders;
};

0 comments on commit 9b4ab19

Please sign in to comment.