metal: create swap chain to manage metal layer

This commit is contained in:
Samuliak 2024-04-05 16:21:39 +02:00
parent 380af618d3
commit 79ff60356d
8 changed files with 115 additions and 29 deletions

View file

@ -376,6 +376,7 @@ if (APPLE)
list(APPEND sources list(APPEND sources
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/renderer_metal.mm renderer_metal/renderer_metal.mm
) )
endif() endif()

View file

@ -3,6 +3,7 @@
#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"
@ -15,6 +16,7 @@ class System;
namespace Metal { namespace Metal {
class Device; class Device;
class SwapChain;
class RasterizerMetal; class RasterizerMetal;
@ -36,7 +38,7 @@ public:
class RasterizerMetal final : public VideoCore::RasterizerInterface, class RasterizerMetal final : public VideoCore::RasterizerInterface,
protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> { protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
public: public:
explicit RasterizerMetal(Tegra::GPU& gpu_, const Device& device_, const CAMetalLayer* layer_); explicit RasterizerMetal(Tegra::GPU& gpu_, const Device& device_, const SwapChain& swap_chain_);
~RasterizerMetal() override; ~RasterizerMetal() override;
void Draw(bool is_indexed, u32 instance_count) override; void Draw(bool is_indexed, u32 instance_count) override;
@ -90,7 +92,9 @@ private:
AccelerateDMA accelerate_dma; AccelerateDMA accelerate_dma;
const Device& device; const Device& device;
const CAMetalLayer* layer; const SwapChain& swap_chain;
MTLCommandBuffer_t command_buffer;
}; };
} // namespace Metal } // namespace Metal

View file

@ -4,6 +4,10 @@
#include "video_core/control/channel_state.h" #include "video_core/control/channel_state.h"
#include "video_core/host1x/host1x.h" #include "video_core/host1x/host1x.h"
#include "video_core/memory_manager.h" #include "video_core/memory_manager.h"
#include "video_core/buffer_cache/buffer_cache.h"
#include "video_core/engines/draw_manager.h"
#include "video_core/engines/kepler_compute.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_metal/mtl_rasterizer.h" #include "video_core/renderer_metal/mtl_rasterizer.h"
#include "video_core/renderer_metal/mtl_device.h" #include "video_core/renderer_metal/mtl_device.h"
@ -20,11 +24,31 @@ bool AccelerateDMA::BufferClear(GPUVAddr src_address, u64 amount, u32 value) {
return true; return true;
} }
RasterizerMetal::RasterizerMetal(Tegra::GPU& gpu_, const Device& device_, const CAMetalLayer* layer_) RasterizerMetal::RasterizerMetal(Tegra::GPU& gpu_, const Device& device_, const SwapChain& swap_chain_)
: gpu{gpu_}, device{device_}, layer{layer_} {} : gpu{gpu_}, device{device_}, swap_chain{swap_chain_} {}
RasterizerMetal::~RasterizerMetal() = default; RasterizerMetal::~RasterizerMetal() = default;
void RasterizerMetal::Draw(bool is_indexed, u32 instance_count) {} void RasterizerMetal::Draw(bool is_indexed, u32 instance_count) {
//const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
if (is_indexed) {
std::cout << "DrawIndexed" << std::endl;
/*[command_buffer drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:draw_params.num_indices
indexType:MTLIndexTypeUInt32
indexBuffer:draw_state.index_buffer
indexBufferOffset:draw_params.first_index * sizeof(u32)
instanceCount:draw_params.num_instances
baseVertex:draw_params.base_vertex
baseInstance:draw_params.base_instance];*/
//cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances,
// draw_params.first_index, draw_params.base_vertex,
// draw_params.base_instance);
} else {
std::cout << "Draw" << std::endl;
//cmdbuf.Draw(draw_params.num_vertices, draw_params.num_instances,
// draw_params.base_vertex, draw_params.base_instance);
}
}
void RasterizerMetal::DrawTexture() {} void RasterizerMetal::DrawTexture() {}
void RasterizerMetal::Clear(u32 layer_count) {} void RasterizerMetal::Clear(u32 layer_count) {}
void RasterizerMetal::DispatchCompute() {} void RasterizerMetal::DispatchCompute() {}

View file

@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "video_core/renderer_metal/objc_bridge.h"
namespace Metal {
class Device;
class SwapChain {
public:
SwapChain(const Device& device_, const CAMetalLayer* layer_);
~SwapChain();
void AcquireNextDrawable();
void Present(MTLCommandBuffer_t command_buffer);
MTLTexture_t GetDrawableTexture();
private:
const Device& device;
const CAMetalLayer* layer;
CAMetalDrawable_t drawable;
};
} // namespace Metal

View file

@ -0,0 +1,30 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#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]) {
// Give the layer our device
layer.device = device.GetDevice();
}
SwapChain::~SwapChain() {
[layer release];
}
void SwapChain::AcquireNextDrawable() {
// Get the next drawable
drawable = [layer nextDrawable];
}
void SwapChain::Present(MTLCommandBuffer_t command_buffer) {
[command_buffer presentDrawable:drawable];
}
MTLTexture_t SwapChain::GetDrawableTexture() {
return drawable.texture;
}
} // namespace Metal

View file

@ -7,10 +7,14 @@
#import <QuartzCore/QuartzCore.h> #import <QuartzCore/QuartzCore.h>
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<MTLTexture> MTLTexture_t; typedef id<MTLTexture> MTLTexture_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* MTLTexture_t; typedef void* MTLTexture_t;
typedef void CAMetalLayer; typedef void CAMetalLayer;
typedef void* CAMetalDrawable_t;
#endif #endif

View file

@ -10,6 +10,7 @@
#include "video_core/renderer_base.h" #include "video_core/renderer_base.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"
namespace Core { namespace Core {
class TelemetrySession; class TelemetrySession;
@ -49,8 +50,7 @@ private:
Tegra::GPU& gpu; Tegra::GPU& gpu;
Device device; Device device;
// TODO: use the layer to get the drawable when drawing directly to the screen SwapChain swap_chain;
const CAMetalLayer* layer;
RasterizerMetal rasterizer; RasterizerMetal rasterizer;
}; };

View file

@ -13,16 +13,10 @@ 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{},
layer([static_cast<const CAMetalLayer*>(render_window.GetWindowInfo().render_surface) swap_chain(device, static_cast<const CAMetalLayer*>(render_window.GetWindowInfo().render_surface)),
retain]), rasterizer(gpu_, device, swap_chain) {}
rasterizer(gpu_, device, layer) {
// Give the layer our device
layer.device = device.GetDevice();
}
RendererMetal::~RendererMetal() { RendererMetal::~RendererMetal() = default;
[layer release];
}
void RendererMetal::Composite(std::span<const Tegra::FramebufferConfig> framebuffers) { void RendererMetal::Composite(std::span<const Tegra::FramebufferConfig> framebuffers) {
if (framebuffers.empty()) { if (framebuffers.empty()) {
@ -31,20 +25,20 @@ void RendererMetal::Composite(std::span<const Tegra::FramebufferConfig> framebuf
// HACK // HACK
@autoreleasepool { @autoreleasepool {
id<CAMetalDrawable> drawable = [layer nextDrawable]; swap_chain.AcquireNextDrawable();
MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; MTLRenderPassDescriptor* render_pass_descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(1.0, 0.5, 0.0, 1.0); render_pass_descriptor.colorAttachments[0].clearColor = MTLClearColorMake(1.0, 0.5, 0.0, 1.0);
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; render_pass_descriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; render_pass_descriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
renderPassDescriptor.colorAttachments[0].texture = drawable.texture; render_pass_descriptor.colorAttachments[0].texture = swap_chain.GetDrawableTexture();
id<MTLCommandBuffer> commandBuffer = [device.GetCommandQueue() commandBuffer]; id<MTLCommandBuffer> command_buffer = [device.GetCommandQueue() commandBuffer];
id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer id<MTLRenderCommandEncoder> render_encoder = [command_buffer
renderCommandEncoderWithDescriptor:renderPassDescriptor]; renderCommandEncoderWithDescriptor:render_pass_descriptor];
[renderEncoder endEncoding]; [render_encoder endEncoding];
[commandBuffer presentDrawable:drawable]; swap_chain.Present(command_buffer);
[commandBuffer commit]; [command_buffer commit];
} }
gpu.RendererFrameEndNotify(); gpu.RendererFrameEndNotify();