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
renderer_metal/mtl_command_recorder.mm
renderer_metal/mtl_device.mm
renderer_metal/mtl_rasterizer.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
#include "common/common_types.h"
#include "objc_bridge.h"
#include "video_core/control/channel_state_cache.h"
#include "video_core/engines/maxwell_dma.h"
#include "video_core/rasterizer_interface.h"

View file

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

View file

@ -1,16 +1,23 @@
// 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_swap_chain.h"
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
layer.device = device.GetDevice();
}
SwapChain::~SwapChain() {
if (drawable) {
// TODO: should drawable be released?
[drawable release];
}
[layer release];
}
@ -19,8 +26,9 @@ void SwapChain::AcquireNextDrawable() {
drawable = [layer nextDrawable];
}
void SwapChain::Present(MTLCommandBuffer_t command_buffer) {
[command_buffer presentDrawable:drawable];
void SwapChain::Present() {
command_recorder.EndEncoding();
command_recorder.Present(drawable);
}
MTLTexture_t SwapChain::GetDrawableTexture() {

View file

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

View file

@ -8,6 +8,7 @@
#include "objc_bridge.h"
#include "video_core/host1x/gpu_device_memory_manager.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_rasterizer.h"
#include "video_core/renderer_metal/mtl_swap_chain.h"
@ -50,6 +51,7 @@ private:
Tegra::GPU& gpu;
Device device;
CommandRecorder command_recorder;
SwapChain swap_chain;
RasterizerMetal rasterizer;

View file

@ -13,7 +13,9 @@ RendererMetal::RendererMetal(Core::Frontend::EmuWindow& emu_window,
std::unique_ptr<Core::Frontend::GraphicsContext> context_)
: RendererBase(emu_window, std::move(context_)), device_memory{device_memory_},
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) {}
RendererMetal::~RendererMetal() = default;
@ -24,22 +26,17 @@ void RendererMetal::Composite(std::span<const Tegra::FramebufferConfig> framebuf
}
// HACK
@autoreleasepool {
swap_chain.AcquireNextDrawable();
swap_chain.AcquireNextDrawable();
MTLRenderPassDescriptor* render_pass_descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
render_pass_descriptor.colorAttachments[0].clearColor = MTLClearColorMake(1.0, 0.5, 0.0, 1.0);
render_pass_descriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
render_pass_descriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
render_pass_descriptor.colorAttachments[0].texture = swap_chain.GetDrawableTexture();
MTLRenderPassDescriptor* render_pass_descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
render_pass_descriptor.colorAttachments[0].clearColor = MTLClearColorMake(1.0, 0.5, 0.0, 1.0);
render_pass_descriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
render_pass_descriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
render_pass_descriptor.colorAttachments[0].texture = swap_chain.GetDrawableTexture();
id<MTLCommandBuffer> command_buffer = [device.GetCommandQueue() commandBuffer];
id<MTLRenderCommandEncoder> render_encoder = [command_buffer
renderCommandEncoderWithDescriptor:render_pass_descriptor];
[render_encoder endEncoding];
swap_chain.Present(command_buffer);
[command_buffer commit];
}
command_recorder.BeginRenderPass(render_pass_descriptor);
swap_chain.Present();
command_recorder.Submit();
gpu.RendererFrameEndNotify();
rasterizer.TickFrame();