Comparer les révisions

...

6 Révisions

Auteur SHA1 Message Date
Samuliak a00d9a9027
metal: translate shaders to spirv 2024-04-08 18:52:31 +02:00
Samuliak 67dab8b8d8
metal: do not release null mtl textures 2024-04-08 18:30:04 +02:00
Samuliak 40eca20e12
metal: implement buffer to buffer copy 2024-04-08 17:03:25 +02:00
Samuliak 3fa495840a
metal: configure pipeline before drawing 2024-04-08 16:47:08 +02:00
Samuliak 22ec7e72f0
metal: do not begin render pass if already active 2024-04-08 16:36:29 +02:00
Samuliak 2c38fa1a35
metal: add render pass interruption notice 2024-04-08 16:27:28 +02:00
9 fichiers modifiés avec 98 ajouts et 61 suppressions

Voir le fichier

@ -81,11 +81,10 @@ void BufferCacheRuntime::Finish() {}
void BufferCacheRuntime::CopyBuffer(MTL::Buffer* dst_buffer, MTL::Buffer* src_buffer,
std::span<const VideoCommon::BufferCopy> copies, bool barrier,
bool can_reorder_upload) {
// HACK: needs to be commented out, since it interrupts render pass
// for (const VideoCommon::BufferCopy& copy : copies) {
// command_recorder.GetBlitCommandEncoder()->copyFromBuffer(
// src_buffer, copy.src_offset, dst_buffer, copy.dst_offset, copy.size);
// }
for (const VideoCommon::BufferCopy& copy : copies) {
command_recorder.GetBlitCommandEncoder()->copyFromBuffer(
src_buffer, copy.src_offset, dst_buffer, copy.dst_offset, copy.size);
}
}
void BufferCacheRuntime::ClearBuffer(MTL::Buffer* dest_buffer, u32 offset, size_t size, u32 value) {

Voir le fichier

@ -10,11 +10,14 @@ CommandRecorder::CommandRecorder(const Device& device_) : device(device_) {}
CommandRecorder::~CommandRecorder() = default;
void CommandRecorder::BeginRenderPass(MTL::RenderPassDescriptor* render_pass) {
RequireCommandBuffer();
EndEncoding();
encoder = command_buffer->renderCommandEncoder(render_pass);
encoder_type = EncoderType::Render;
void CommandRecorder::BeginOrContinueRenderPass(MTL::RenderPassDescriptor* render_pass) {
if (render_pass != bound_render_pass) {
RequireCommandBuffer();
EndEncoding();
encoder = command_buffer->renderCommandEncoder(render_pass);
encoder_type = EncoderType::Render;
bound_render_pass = render_pass;
}
}
void CommandRecorder::RequireComputeEncoder() {
@ -40,6 +43,7 @@ void CommandRecorder::EndEncoding() {
encoder->endEncoding();
//[encoder release];
encoder = nullptr;
bound_render_pass = nullptr;
}
}

Voir le fichier

@ -12,12 +12,15 @@ class Device;
enum class EncoderType { Render, Compute, Blit };
// TODO: whenever a render pass gets interrupted by either a compute or blit command and application
// then tries to perform a render command, begin the same render pass, but with all load actions set
// to "load"
class CommandRecorder {
public:
CommandRecorder(const Device& device_);
~CommandRecorder();
void BeginRenderPass(MTL::RenderPassDescriptor* render_pass);
void BeginOrContinueRenderPass(MTL::RenderPassDescriptor* render_pass);
void CheckIfRenderPassIsActive() {
if (!encoder || encoder_type != EncoderType::Render) {
@ -63,11 +66,14 @@ private:
// HACK: Command buffers and encoders currently aren't released every frame due to Xcode
// crashing in Debug mode. This leads to memory leaks
MTL::CommandBuffer* command_buffer = nil;
MTL::CommandEncoder* encoder = nil;
MTL::CommandBuffer* command_buffer{nullptr};
MTL::CommandEncoder* encoder{nullptr};
EncoderType encoder_type;
// Keep track of last bound render pass
MTL::RenderPassDescriptor* bound_render_pass{nullptr};
void RequireCommandBuffer();
};

Voir le fichier

@ -15,6 +15,7 @@
#include "video_core/renderer_metal/mtl_command_recorder.h"
#include "video_core/renderer_metal/mtl_device.h"
#include "video_core/shader_notify.h"
#include "video_core/texture_cache/texture_cache.h"
#include "video_core/texture_cache/texture_cache_base.h"
namespace Metal {
@ -53,22 +54,22 @@ GraphicsPipeline::GraphicsPipeline(const Device& device_, CommandRecorder& comma
return;
}
MakePipeline(framebuffer->GetHandle());
// configure_func = ConfigureFunc(functions, stage_infos);
}
template <typename Spec>
void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
// TODO: implement
}
void GraphicsPipeline::Configure(bool is_indexed) {
buffer_cache.UpdateGraphicsBuffers(is_indexed);
buffer_cache.BindHostGeometryBuffers(is_indexed);
void GraphicsPipeline::ConfigureDraw() {
Framebuffer* framebuffer = texture_cache.GetFramebuffer();
texture_cache.SynchronizeGraphicsDescriptors();
texture_cache.UpdateRenderTargets(false);
const Framebuffer* const framebuffer = texture_cache.GetFramebuffer();
if (!framebuffer) {
return;
}
// MTL::RenderPassDescriptor* render_pass = framebuffer->GetHandle();
command_recorder.BeginOrContinueRenderPass(framebuffer->GetHandle());
// TODO: bind resources
command_recorder.GetRenderCommandEncoder()->setRenderPipelineState(pipeline_state);
}
void GraphicsPipeline::MakePipeline(MTL::RenderPassDescriptor* render_pass) {

Voir le fichier

@ -80,9 +80,7 @@ public:
// TODO: implement
void AddTransition(GraphicsPipeline* transition) {}
void Configure(bool is_indexed) {
// configure_func(this, is_indexed);
}
void Configure(bool is_indexed);
[[nodiscard]] GraphicsPipeline* Next(const GraphicsPipelineCacheKey& current_key) noexcept {
// TODO: implement
@ -93,26 +91,12 @@ public:
return true;
}
template <typename Spec>
static auto MakeConfigureSpecFunc() {
return [](GraphicsPipeline* pl, bool is_indexed) { pl->ConfigureImpl<Spec>(is_indexed); };
}
void SetEngine(Tegra::Engines::Maxwell3D* maxwell3d_, Tegra::MemoryManager* gpu_memory_) {
maxwell3d = maxwell3d_;
gpu_memory = gpu_memory_;
}
MTL::RenderPipelineState* GetPipelineState() const noexcept {
return pipeline_state;
}
private:
template <typename Spec>
void ConfigureImpl(bool is_indexed);
void ConfigureDraw();
void MakePipeline(MTL::RenderPassDescriptor* render_pass);
void Validate();

Voir le fichier

@ -51,6 +51,17 @@ auto MakeSpan(Container& container) {
return std::span(container.data(), container.size());
}
Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> programs,
const GraphicsPipelineCacheKey& key,
const Shader::IR::Program& program,
const Shader::IR::Program* previous_program) {
Shader::RuntimeInfo info{};
// TODO: fill in the runtime info
return info;
}
} // Anonymous namespace
size_t ComputePipelineCacheKey::Hash() const noexcept {
@ -219,6 +230,47 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
auto hash = key.Hash();
LOG_INFO(Render_Metal, "0x{:016x}", hash);
// Translate shaders to spirv
size_t env_index{0};
std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs;
for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
if (key.unique_hashes[index] == 0) {
continue;
}
Shader::Environment& env{*envs[env_index]};
++env_index;
const u32 cfg_offset{static_cast<u32>(env.StartAddress() + sizeof(Shader::ProgramHeader))};
Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0);
programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info);
if (Settings::values.dump_shaders) {
env.Dump(hash, key.unique_hashes[index]);
}
}
std::array<const Shader::Info*, Maxwell::MaxShaderStage> infos{};
std::array<MTL::Function*, VideoCommon::NUM_STAGES> functions;
const Shader::IR::Program* previous_stage{};
Shader::Backend::Bindings binding;
for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
if (key.unique_hashes[index] == 0) {
continue;
}
Shader::IR::Program& program{programs[index]};
const size_t stage_index{index - 1};
infos[stage_index] = &program.info;
const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)};
ConvertLegacyToGeneric(program, runtime_info);
const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding)};
// TODO: translate the shader to metal using spirv cross
// functions[stage_index] = ;
previous_stage = &program;
}
// HACK: create hardcoded shaders
MTL::CompileOptions* compile_options = MTL::CompileOptions::alloc()->init();
NS::Error* error = nullptr;
@ -257,17 +309,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
error->description()->cString(NS::ASCIIStringEncoding));
}
std::array<MTL::Function*, VideoCommon::NUM_STAGES> functions;
functions[0] = library->newFunction(NS::String::string("vertexMain", NS::ASCIIStringEncoding));
functions[1] =
library->newFunction(NS::String::string("fragmentMain", NS::ASCIIStringEncoding));
// HACK: dummy info
std::array<const Shader::Info*, VideoCommon::NUM_STAGES> infos = {nullptr};
infos[0] = new Shader::Info{};
infos[1] = new Shader::Info{};
return std::make_unique<GraphicsPipeline>(device, command_recorder, key, buffer_cache,
texture_cache, &shader_notify, functions, infos);
} catch (const std::exception& e) {

Voir le fichier

@ -48,12 +48,7 @@ void RasterizerMetal::Draw(bool is_indexed, u32 instance_count) {
if (!pipeline) {
return;
}
command_recorder.GetRenderCommandEncoder()->setRenderPipelineState(
pipeline->GetPipelineState());
// HACK: test is buffers are being correctly created
buffer_cache.UpdateGraphicsBuffers(is_indexed);
buffer_cache.BindHostGeometryBuffers(is_indexed);
pipeline->Configure(is_indexed);
// HACK: dummy draw call
command_recorder.GetRenderCommandEncoder()->drawPrimitives(MTL::PrimitiveTypeTriangle,
@ -95,8 +90,9 @@ void RasterizerMetal::Clear(u32 layer_count) {
return;
}
// Begin render pass
command_recorder.BeginRenderPass(framebuffer->GetHandle());
// TODO: track the textures used by render pass and only begin the render pass if their contents
// are needed Begin render pass
command_recorder.BeginOrContinueRenderPass(framebuffer->GetHandle());
}
void RasterizerMetal::DispatchCompute() {

Voir le fichier

@ -103,9 +103,9 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
ImageId image_id_, Image& image)
: VideoCommon::ImageViewBase{info, image.info, image_id_, image.gpu_addr} {
using Shader::TextureType;
// TODO: For whatever reason, some images's internal objc objects is NULL
// TODO: metal-cpp provides no method to check for this
texture = image.GetHandle()->retain();
if (image.GetHandle()) {
texture = image.GetHandle()->retain();
}
// TODO: create texture view
}
@ -128,7 +128,9 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::NullImageV
}
ImageView::~ImageView() {
texture->release();
if (texture) {
texture->release();
}
}
Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& tsc) {

Voir le fichier

@ -14,8 +14,8 @@ 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) {
@ -42,7 +42,7 @@ void RendererMetal::Composite(std::span<const Tegra::FramebufferConfig> framebuf
render_pass_descriptor->colorAttachments()->object(0)->setTexture(
swap_chain.GetDrawableTexture());
command_recorder.BeginRenderPass(render_pass_descriptor);
command_recorder.BeginOrContinueRenderPass(render_pass_descriptor);
// Blit the framebuffer to the drawable texture
// TODO: acquire the texture from @ref framebuffers