mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-25 22:57:22 +00:00
metal: blit rendering result to drawable
This commit is contained in:
parent
c8a717651c
commit
a5e7672de5
5 changed files with 128 additions and 9 deletions
|
@ -40,8 +40,22 @@ public:
|
|||
return command_buffer;
|
||||
}
|
||||
|
||||
MTL::CommandEncoder* GetCommandEncoder() {
|
||||
return encoder;
|
||||
MTL::RenderCommandEncoder* GetRenderCommandEncoder() {
|
||||
CheckIfRenderPassIsActive();
|
||||
|
||||
return static_cast<MTL::RenderCommandEncoder*>(encoder);
|
||||
}
|
||||
|
||||
MTL::ComputeCommandEncoder* GetComputeCommandEncoder() {
|
||||
RequireComputeEncoder();
|
||||
|
||||
return static_cast<MTL::ComputeCommandEncoder*>(encoder);
|
||||
}
|
||||
|
||||
MTL::BlitCommandEncoder* GetBlitCommandEncoder() {
|
||||
RequireBlitEncoder();
|
||||
|
||||
return static_cast<MTL::BlitCommandEncoder*>(encoder);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -89,6 +89,13 @@ void GraphicsPipeline::MakePipeline(MTL::RenderPassDescriptor* render_pass) {
|
|||
color_attachment->setPixelFormat(render_pass_attachment->texture()->pixelFormat());
|
||||
// TODO: provide blend information
|
||||
}
|
||||
|
||||
NS::Error* error = nullptr;
|
||||
pipeline_state = device.GetDevice()->newRenderPipelineState(pipeline_descriptor, &error);
|
||||
if (error) {
|
||||
LOG_ERROR(Render_Metal, "failed to create pipeline state: {}",
|
||||
error->description()->cString(NS::ASCIIStringEncoding));
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsPipeline::Validate() {
|
||||
|
|
|
@ -106,6 +106,9 @@ private:
|
|||
BufferCacheRuntime buffer_cache_runtime;
|
||||
BufferCache buffer_cache;
|
||||
TextureCacheRuntime texture_cache_runtime;
|
||||
|
||||
// HACK: make the texture cache public so that renderer can access it
|
||||
public:
|
||||
TextureCache texture_cache;
|
||||
};
|
||||
|
||||
|
|
|
@ -14,13 +14,18 @@ namespace Metal {
|
|||
RendererMetal::RendererMetal(Core::Frontend::EmuWindow& emu_window,
|
||||
Tegra::MaxwellDeviceMemoryManager& device_memory_, Tegra::GPU& gpu_,
|
||||
std::unique_ptr<Core::Frontend::GraphicsContext> context_)
|
||||
: RendererBase(emu_window, std::move(context_)),
|
||||
device_memory{device_memory_}, gpu{gpu_}, device{}, command_recorder(device),
|
||||
: RendererBase(emu_window, std::move(context_)), device_memory{device_memory_}, gpu{gpu_},
|
||||
device{}, command_recorder(device),
|
||||
swap_chain(device, command_recorder,
|
||||
static_cast<CA::MetalLayer*>(render_window.GetWindowInfo().render_surface)),
|
||||
rasterizer(gpu_, device_memory, device, command_recorder, swap_chain) {}
|
||||
rasterizer(gpu_, device_memory, device, command_recorder, swap_chain) {
|
||||
CreateBlitPipelineState();
|
||||
}
|
||||
|
||||
RendererMetal::~RendererMetal() = default;
|
||||
RendererMetal::~RendererMetal() {
|
||||
blit_pipeline_state->release();
|
||||
blit_sampler_state->release();
|
||||
}
|
||||
|
||||
void RendererMetal::Composite(std::span<const Tegra::FramebufferConfig> framebuffers) {
|
||||
if (framebuffers.empty()) {
|
||||
|
@ -32,15 +37,28 @@ void RendererMetal::Composite(std::span<const Tegra::FramebufferConfig> framebuf
|
|||
|
||||
// TODO: copy the framebuffer to the drawable texture instead of this dummy render pass
|
||||
MTL::RenderPassDescriptor* render_pass_descriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||
render_pass_descriptor->colorAttachments()->object(0)->setClearColor(
|
||||
MTL::ClearColor::Make(1.0, 0.5, 0.0, 1.0));
|
||||
render_pass_descriptor->colorAttachments()->object(0)->setLoadAction(MTL::LoadActionClear);
|
||||
render_pass_descriptor->colorAttachments()->object(0)->setLoadAction(MTL::LoadActionDontCare);
|
||||
render_pass_descriptor->colorAttachments()->object(0)->setStoreAction(MTL::StoreActionStore);
|
||||
render_pass_descriptor->colorAttachments()->object(0)->setTexture(
|
||||
swap_chain.GetDrawableTexture());
|
||||
|
||||
command_recorder.BeginRenderPass(render_pass_descriptor);
|
||||
|
||||
// Blit the framebuffer to the drawable texture
|
||||
// TODO: acquire the texture from @ref framebuffers
|
||||
const Framebuffer* const framebuffer = rasterizer.texture_cache.GetFramebuffer();
|
||||
if (!framebuffer) {
|
||||
return;
|
||||
}
|
||||
MTL::Texture* src_texture = framebuffer->GetHandle()->colorAttachments()->object(0)->texture();
|
||||
command_recorder.GetRenderCommandEncoder()->setRenderPipelineState(blit_pipeline_state);
|
||||
command_recorder.GetRenderCommandEncoder()->setFragmentTexture(src_texture, 0);
|
||||
command_recorder.GetRenderCommandEncoder()->setFragmentSamplerState(blit_sampler_state, 0);
|
||||
|
||||
// Draw a full screen triangle which will get clipped to a rectangle
|
||||
command_recorder.GetRenderCommandEncoder()->drawPrimitives(MTL::PrimitiveTypeTriangle,
|
||||
NS::UInteger(0), NS::UInteger(3));
|
||||
|
||||
swap_chain.Present();
|
||||
command_recorder.Submit();
|
||||
|
||||
|
@ -54,4 +72,76 @@ std::vector<u8> RendererMetal::GetAppletCaptureBuffer() {
|
|||
return std::vector<u8>(VideoCore::Capture::TiledSize);
|
||||
}
|
||||
|
||||
void RendererMetal::CreateBlitPipelineState() {
|
||||
MTL::CompileOptions* compile_options = MTL::CompileOptions::alloc()->init();
|
||||
NS::Error* error = nullptr;
|
||||
MTL::Library* library = device.GetDevice()->newLibrary(NS::String::string(
|
||||
R"(
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
constant float2 texCoords[] = {
|
||||
float2(0.0, -1.0),
|
||||
float2(0.0, 1.0),
|
||||
float2(2.0, 1.0),
|
||||
};
|
||||
|
||||
struct VertexOut {
|
||||
float4 position [[position]];
|
||||
float2 texCoord;
|
||||
};
|
||||
|
||||
vertex VertexOut vertexMain(uint vid [[vertex_id]]) {
|
||||
VertexOut out;
|
||||
out.position = float4(texCoords[vid] * 2.0 - 1.0, 0.0, 1.0);
|
||||
out.texCoord = texCoords[vid];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment float4 fragmentMain(VertexOut in [[stage_in]],
|
||||
texture2d<float> texture [[texture(0)]],
|
||||
sampler sampler [[sampler(0)]]) {
|
||||
return texture.sample(sampler, in.texCoord);
|
||||
}
|
||||
)",
|
||||
NS::ASCIIStringEncoding),
|
||||
compile_options, &error);
|
||||
if (error) {
|
||||
LOG_ERROR(Render_Metal, "failed to create blit library: {}",
|
||||
error->description()->cString(NS::ASCIIStringEncoding));
|
||||
}
|
||||
|
||||
MTL::Function* vertex_function =
|
||||
library->newFunction(NS::String::string("vertexMain", NS::ASCIIStringEncoding));
|
||||
MTL::Function* fragment_function =
|
||||
library->newFunction(NS::String::string("fragmentMain", NS::ASCIIStringEncoding));
|
||||
|
||||
MTL::RenderPipelineDescriptor* pipeline_descriptor =
|
||||
MTL::RenderPipelineDescriptor::alloc()->init();
|
||||
pipeline_descriptor->setVertexFunction(vertex_function);
|
||||
pipeline_descriptor->setFragmentFunction(fragment_function);
|
||||
// TODO: get the pixel format from metal layer
|
||||
pipeline_descriptor->colorAttachments()->object(0)->setPixelFormat(MTL::PixelFormatRGBA8Unorm);
|
||||
|
||||
error = nullptr;
|
||||
blit_pipeline_state = device.GetDevice()->newRenderPipelineState(pipeline_descriptor, &error);
|
||||
if (error) {
|
||||
LOG_ERROR(Render_Metal, "failed to create blit pipeline state: {}",
|
||||
error->description()->cString(NS::ASCIIStringEncoding));
|
||||
}
|
||||
|
||||
// Create sampler state
|
||||
MTL::SamplerDescriptor* sampler_descriptor = MTL::SamplerDescriptor::alloc()->init();
|
||||
sampler_descriptor->setMinFilter(MTL::SamplerMinMagFilterLinear);
|
||||
sampler_descriptor->setMagFilter(MTL::SamplerMinMagFilterLinear);
|
||||
|
||||
blit_sampler_state = device.GetDevice()->newSamplerState(sampler_descriptor);
|
||||
|
||||
// Deallocate unnecessary objects
|
||||
fragment_function->release();
|
||||
vertex_function->release();
|
||||
library->release();
|
||||
}
|
||||
|
||||
} // namespace Metal
|
||||
|
|
|
@ -47,6 +47,8 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
void CreateBlitPipelineState();
|
||||
|
||||
Tegra::MaxwellDeviceMemoryManager& device_memory;
|
||||
Tegra::GPU& gpu;
|
||||
|
||||
|
@ -54,6 +56,9 @@ private:
|
|||
CommandRecorder command_recorder;
|
||||
SwapChain swap_chain;
|
||||
|
||||
MTL::RenderPipelineState* blit_pipeline_state{nullptr};
|
||||
MTL::SamplerState* blit_sampler_state{nullptr};
|
||||
|
||||
RasterizerMetal rasterizer;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue