metal: add command recorder for command management

This commit is contained in:
Samuliak 2024-04-05 17:10:21 +02:00
parent 79ff60356d
commit 35b751de1b
9 changed files with 150 additions and 22 deletions

View file

@ -374,6 +374,7 @@ if (APPLE)
) )
list(APPEND sources list(APPEND sources
renderer_metal/mtl_command_recorder.mm
renderer_metal/mtl_device.mm renderer_metal/mtl_device.mm
renderer_metal/mtl_rasterizer.mm renderer_metal/mtl_rasterizer.mm
renderer_metal/mtl_swap_chain.mm renderer_metal/mtl_swap_chain.mm

View file

@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "objc_bridge.h"
#include "video_core/renderer_metal/objc_bridge.h"
namespace Metal {
class Device;
enum class EncoderType { Render, Compute, Blit };
class CommandRecorder {
public:
CommandRecorder(const Device& device_);
~CommandRecorder();
void BeginRenderPass(MTLRenderPassDescriptor* render_pass_descriptor);
void RequireComputeEncoder();
void RequireBlitEncoder();
void EndEncoding();
void Present(CAMetalDrawable_t drawable);
void Submit();
MTLCommandBuffer_t GetCommandBuffer() {
return command_buffer;
}
MTLCommandEncoder_t GetCommandEncoder() {
return encoder;
}
private:
const Device& device;
MTLCommandBuffer_t command_buffer = nil;
MTLCommandEncoder_t encoder = nil;
EncoderType encoder_type;
void RequireCommandBuffer();
};
} // namespace Metal

View file

@ -0,0 +1,64 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "video_core/renderer_metal/mtl_command_recorder.h"
#include "video_core/renderer_metal/mtl_device.h"
#include <iostream>
namespace Metal {
CommandRecorder::CommandRecorder(const Device& device_) : device(device_) {}
CommandRecorder::~CommandRecorder() = default;
void CommandRecorder::BeginRenderPass(MTLRenderPassDescriptor* render_pass_descriptor) {
RequireCommandBuffer();
EndEncoding();
encoder = [command_buffer renderCommandEncoderWithDescriptor:render_pass_descriptor];
encoder_type = EncoderType::Render;
}
void CommandRecorder::RequireComputeEncoder() {
RequireCommandBuffer();
if (!encoder || encoder_type != EncoderType::Compute) {
EndEncoding();
encoder = [command_buffer computeCommandEncoder];
encoder_type = EncoderType::Compute;
}
}
void CommandRecorder::RequireBlitEncoder() {
RequireCommandBuffer();
if (!encoder || encoder_type != EncoderType::Blit) {
EndEncoding();
encoder = [command_buffer blitCommandEncoder];
encoder_type = EncoderType::Blit;
}
}
void CommandRecorder::EndEncoding() {
if (encoder) {
[encoder endEncoding];
[encoder release];
encoder = nil;
}
}
void CommandRecorder::Present(CAMetalDrawable_t drawable) {
[command_buffer presentDrawable:drawable];
}
void CommandRecorder::Submit() {
EndEncoding();
[command_buffer commit];
[command_buffer release];
command_buffer = nil;
}
void CommandRecorder::RequireCommandBuffer() {
if (!command_buffer) {
command_buffer = [device.GetCommandQueue() commandBuffer];
}
}
} // namespace Metal

View file

@ -3,7 +3,6 @@
#pragma once #pragma once
#include "common/common_types.h" #include "common/common_types.h"
#include "objc_bridge.h"
#include "video_core/control/channel_state_cache.h" #include "video_core/control/channel_state_cache.h"
#include "video_core/engines/maxwell_dma.h" #include "video_core/engines/maxwell_dma.h"
#include "video_core/rasterizer_interface.h" #include "video_core/rasterizer_interface.h"

View file

@ -7,23 +7,26 @@
namespace Metal { namespace Metal {
class Device; class Device;
class CommandRecorder;
class SwapChain { class SwapChain {
public: public:
SwapChain(const Device& device_, const CAMetalLayer* layer_); SwapChain(const Device& device_, CommandRecorder& command_recorder_,
const CAMetalLayer* layer_);
~SwapChain(); ~SwapChain();
void AcquireNextDrawable(); void AcquireNextDrawable();
void Present(MTLCommandBuffer_t command_buffer); void Present();
MTLTexture_t GetDrawableTexture(); MTLTexture_t GetDrawableTexture();
private: private:
const Device& device; const Device& device;
CommandRecorder& command_recorder;
const CAMetalLayer* layer; const CAMetalLayer* layer;
CAMetalDrawable_t drawable; CAMetalDrawable_t drawable = nil;
}; };
} // namespace Metal } // namespace Metal

View file

@ -1,16 +1,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "video_core/renderer_metal/mtl_command_recorder.h"
#include "video_core/renderer_metal/mtl_device.h" #include "video_core/renderer_metal/mtl_device.h"
#include "video_core/renderer_metal/mtl_swap_chain.h" #include "video_core/renderer_metal/mtl_swap_chain.h"
namespace Metal { namespace Metal {
SwapChain::SwapChain(const Device& device_, const CAMetalLayer* layer_) : device(device_), layer([layer_ retain]) { SwapChain::SwapChain(const Device& device_, CommandRecorder& command_recorder_,
const CAMetalLayer* layer_)
: device(device_), command_recorder(command_recorder_), layer([layer_ retain]) {
// Give the layer our device // Give the layer our device
layer.device = device.GetDevice(); layer.device = device.GetDevice();
} }
SwapChain::~SwapChain() { SwapChain::~SwapChain() {
if (drawable) {
// TODO: should drawable be released?
[drawable release];
}
[layer release]; [layer release];
} }
@ -19,8 +26,9 @@ void SwapChain::AcquireNextDrawable() {
drawable = [layer nextDrawable]; drawable = [layer nextDrawable];
} }
void SwapChain::Present(MTLCommandBuffer_t command_buffer) { void SwapChain::Present() {
[command_buffer presentDrawable:drawable]; command_recorder.EndEncoding();
command_recorder.Present(drawable);
} }
MTLTexture_t SwapChain::GetDrawableTexture() { MTLTexture_t SwapChain::GetDrawableTexture() {

View file

@ -8,13 +8,17 @@
typedef id<MTLDevice> MTLDevice_t; typedef id<MTLDevice> MTLDevice_t;
typedef id<MTLCommandQueue> MTLCommandQueue_t; typedef id<MTLCommandQueue> MTLCommandQueue_t;
typedef id<MTLCommandBuffer> MTLCommandBuffer_t; typedef id<MTLCommandBuffer> MTLCommandBuffer_t;
typedef id<MTLCommandEncoder> MTLCommandEncoder_t;
typedef id<MTLTexture> MTLTexture_t; typedef id<MTLTexture> MTLTexture_t;
typedef id<CAMetalDrawable> CAMetalDrawable_t; typedef id<CAMetalDrawable> CAMetalDrawable_t;
#else #else
typedef void* MTLDevice_t; typedef void* MTLDevice_t;
typedef void* MTLCommandQueue_t; typedef void* MTLCommandQueue_t;
typedef void* MTLCommandBuffer_t; typedef void* MTLCommandBuffer_t;
typedef void* MTLCommandEncoder_t;
typedef void* MTLTexture_t; typedef void* MTLTexture_t;
typedef void MTLRenderPassDescriptor;
typedef void CAMetalLayer; typedef void CAMetalLayer;
typedef void* CAMetalDrawable_t; typedef void* CAMetalDrawable_t;
#define nil NULL
#endif #endif

View file

@ -8,6 +8,7 @@
#include "objc_bridge.h" #include "objc_bridge.h"
#include "video_core/host1x/gpu_device_memory_manager.h" #include "video_core/host1x/gpu_device_memory_manager.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#include "video_core/renderer_metal/mtl_command_recorder.h"
#include "video_core/renderer_metal/mtl_device.h" #include "video_core/renderer_metal/mtl_device.h"
#include "video_core/renderer_metal/mtl_rasterizer.h" #include "video_core/renderer_metal/mtl_rasterizer.h"
#include "video_core/renderer_metal/mtl_swap_chain.h" #include "video_core/renderer_metal/mtl_swap_chain.h"
@ -50,6 +51,7 @@ private:
Tegra::GPU& gpu; Tegra::GPU& gpu;
Device device; Device device;
CommandRecorder command_recorder;
SwapChain swap_chain; SwapChain swap_chain;
RasterizerMetal rasterizer; RasterizerMetal rasterizer;

View file

@ -13,7 +13,9 @@ RendererMetal::RendererMetal(Core::Frontend::EmuWindow& emu_window,
std::unique_ptr<Core::Frontend::GraphicsContext> context_) std::unique_ptr<Core::Frontend::GraphicsContext> context_)
: RendererBase(emu_window, std::move(context_)), device_memory{device_memory_}, : RendererBase(emu_window, std::move(context_)), device_memory{device_memory_},
gpu{gpu_}, device{}, gpu{gpu_}, device{},
swap_chain(device, static_cast<const CAMetalLayer*>(render_window.GetWindowInfo().render_surface)), command_recorder(device),
swap_chain(device, command_recorder,
static_cast<const CAMetalLayer*>(render_window.GetWindowInfo().render_surface)),
rasterizer(gpu_, device, swap_chain) {} rasterizer(gpu_, device, swap_chain) {}
RendererMetal::~RendererMetal() = default; RendererMetal::~RendererMetal() = default;
@ -24,7 +26,6 @@ void RendererMetal::Composite(std::span<const Tegra::FramebufferConfig> framebuf
} }
// HACK // HACK
@autoreleasepool {
swap_chain.AcquireNextDrawable(); swap_chain.AcquireNextDrawable();
MTLRenderPassDescriptor* render_pass_descriptor = [MTLRenderPassDescriptor renderPassDescriptor]; MTLRenderPassDescriptor* render_pass_descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
@ -33,13 +34,9 @@ void RendererMetal::Composite(std::span<const Tegra::FramebufferConfig> framebuf
render_pass_descriptor.colorAttachments[0].storeAction = MTLStoreActionStore; render_pass_descriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
render_pass_descriptor.colorAttachments[0].texture = swap_chain.GetDrawableTexture(); render_pass_descriptor.colorAttachments[0].texture = swap_chain.GetDrawableTexture();
id<MTLCommandBuffer> command_buffer = [device.GetCommandQueue() commandBuffer]; command_recorder.BeginRenderPass(render_pass_descriptor);
id<MTLRenderCommandEncoder> render_encoder = [command_buffer swap_chain.Present();
renderCommandEncoderWithDescriptor:render_pass_descriptor]; command_recorder.Submit();
[render_encoder endEncoding];
swap_chain.Present(command_buffer);
[command_buffer commit];
}
gpu.RendererFrameEndNotify(); gpu.RendererFrameEndNotify();
rasterizer.TickFrame(); rasterizer.TickFrame();