Archived
1
Fork 0

Fix Metal backend (finally)

This commit is contained in:
Joshua Goins 2022-02-18 14:36:38 -05:00
parent 0283cebcb8
commit 8237eeb05b
12 changed files with 150 additions and 88 deletions

View file

@ -38,6 +38,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS")
set(ENABLE_VULKAN TRUE)
set(ENABLE_DARWIN TRUE)
set(ENABLE_IOS TRUE)
set(ENABLE_METAL TRUE)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "tvOS")
@ -46,6 +47,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "tvOS")
set(ENABLE_VULKAN TRUE)
set(ENABLE_DARWIN TRUE)
set(ENABLE_TVOS TRUE)
set(ENABLE_METAL TRUE)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")

View file

@ -44,6 +44,8 @@ public:
GFXPipeline* create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) override;
GFXPipeline* create_compute_pipeline(const GFXComputePipelineCreateInfo& info) override;
GFXSize get_alignment(GFXSize size) override;
GFXCommandBuffer* acquire_command_buffer(bool for_presentation_use = false) override;
void submit(GFXCommandBuffer* command_buffer, platform::window_ptr window = nullptr) override;
@ -51,7 +53,7 @@ public:
private:
struct NativeMTLView {
platform::window_ptr identifier = nullptr;
CA::MetalDrawable* layer = nullptr;
MTL::PixelFormat format;
};
std::vector<NativeMTLView*> nativeViews;

View file

@ -172,10 +172,7 @@ void GFXMetal::initialize_view(void* native_handle, const platform::window_ptr i
NativeMTLView* native = new NativeMTLView();
native->identifier = identifier;
//native->layer = (CAMetalLayer*)native_handle;
//native->layer.device = device;
//native->layer.allowsNextDrawableTimeout = true;
native->format = (MTL::PixelFormat)platform::initialize_metal_layer(identifier, device);
nativeViews.push_back(native);
}
@ -426,8 +423,9 @@ MTL::FunctionConstantValues* get_constant_values(GFXShaderConstants constants) {
GFXPipeline* GFXMetal::create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) {
GFXMetalPipeline* pipeline = new GFXMetalPipeline();
pipeline->label = info.label;
NS::Error* error = nil;
NS::Error* error = nullptr;
MTL::RenderPipelineDescriptor* pipelineDescriptor = MTL::RenderPipelineDescriptor::alloc()->init();
@ -552,7 +550,7 @@ GFXPipeline* GFXMetal::create_graphics_pipeline(const GFXGraphicsPipelineCreateI
unsigned int i = 0;
for(const auto& attachment : metalRenderPass->attachments) {
if(attachment != MTL::PixelFormatDepth32Float) {
MTL::RenderPipelineColorAttachmentDescriptor* colorAttachmentDescriptor = MTL::RenderPipelineColorAttachmentDescriptor::alloc()->init();
MTL::RenderPipelineColorAttachmentDescriptor* colorAttachmentDescriptor = pipelineDescriptor->colorAttachments()->object(i++);
colorAttachmentDescriptor->setPixelFormat(attachment);
colorAttachmentDescriptor->setBlendingEnabled(info.blending.enable_blending);
@ -562,16 +560,14 @@ GFXPipeline* GFXMetal::create_graphics_pipeline(const GFXGraphicsPipelineCreateI
colorAttachmentDescriptor->setSourceAlphaBlendFactor(toBlendFactor(info.blending.src_alpha));
colorAttachmentDescriptor->setDestinationAlphaBlendFactor(toBlendFactor(info.blending.dst_alpha));
pipelineDescriptor->colorAttachments()->setObject(colorAttachmentDescriptor, i++);
} else {
pipelineDescriptor->setDepthAttachmentPixelFormat(MTL::PixelFormatDepth32Float);
}
}
} else {
MTL::RenderPipelineColorAttachmentDescriptor* colorAttachmentDescriptor = MTL::RenderPipelineColorAttachmentDescriptor::alloc()->init();
MTL::RenderPipelineColorAttachmentDescriptor* colorAttachmentDescriptor = pipelineDescriptor->colorAttachments()->object(0);
//colorAttachmentDescriptor->setPixelFormat(attachment); [nativeViews[0]->layer pixelFormat];
colorAttachmentDescriptor->setPixelFormat(nativeViews[0]->format);
colorAttachmentDescriptor->setBlendingEnabled(info.blending.enable_blending);
colorAttachmentDescriptor->setSourceRGBBlendFactor(toBlendFactor(info.blending.src_rgb));
@ -579,8 +575,6 @@ GFXPipeline* GFXMetal::create_graphics_pipeline(const GFXGraphicsPipelineCreateI
colorAttachmentDescriptor->setSourceAlphaBlendFactor(toBlendFactor(info.blending.src_alpha));
colorAttachmentDescriptor->setDestinationAlphaBlendFactor(toBlendFactor(info.blending.dst_alpha));
pipelineDescriptor->colorAttachments()->setObject(colorAttachmentDescriptor, 0);
}
if(debug_enabled) {
@ -601,11 +595,6 @@ GFXPipeline* GFXMetal::create_graphics_pipeline(const GFXGraphicsPipelineCreateI
break;
}
for(auto& binding : info.shader_input.bindings) {
if(binding.type == GFXBindingType::PushConstant)
pipeline->pushConstantIndex = binding.binding;
}
pipeline->winding_mode = info.rasterization.winding_mode;
MTL::DepthStencilDescriptor* depthStencil = MTL::DepthStencilDescriptor::alloc()->init();
@ -651,7 +640,6 @@ GFXPipeline* GFXMetal::create_compute_pipeline(const GFXComputePipelineCreateInf
NS::Error* error = nullptr;
// vertex
MTL::Library* computeLibrary;
{
std::string compute_src;
@ -688,17 +676,20 @@ GFXPipeline* GFXMetal::create_compute_pipeline(const GFXComputePipelineCreateInf
pipeline->compute_handle = device->newComputePipelineState(pipelineDescriptor, MTL::PipelineOptionNone, nullptr, &error);
if(!pipeline->compute_handle)
prism::log("Compute pipeline error: {}", error->debugDescription()->cString(NS::ASCIIStringEncoding));
for(auto& binding : info.shader_input.bindings) {
if(binding.type == GFXBindingType::PushConstant)
pipeline->pushConstantIndex = binding.binding;
}
computeLibrary->release();
return pipeline;
}
GFXSize GFXMetal::get_alignment(GFXSize size) {
#ifdef PLATFORM_MACOS
return (size + 32 / 2) & ~int(32 - 1);
#else
return size;
#endif
}
GFXCommandBuffer* GFXMetal::acquire_command_buffer(bool for_presentation_use) {
GFXCommandBuffer* cmdbuf = nullptr;
while(cmdbuf == nullptr) {
@ -719,10 +710,13 @@ GFXCommandBuffer* GFXMetal::acquire_command_buffer(bool for_presentation_use) {
}
void GFXMetal::submit(GFXCommandBuffer* command_buffer, const platform::window_ptr window) {
NS::AutoreleasePool* pPool = NS::AutoreleasePool::alloc()->init();
NativeMTLView* native = getNativeView(window);
//id<CAMetalDrawable> drawable = nil;
//if(native != nullptr)
// drawable = [native->layer nextDrawable];
CA::MetalDrawable* drawable = nullptr;
if(native != nullptr)
drawable = ((CA::MetalDrawable*)platform::get_next_drawable(window));
MTL::CommandBuffer* commandBuffer = command_queue->commandBuffer();
@ -747,18 +741,18 @@ void GFXMetal::submit(GFXCommandBuffer* command_buffer, const platform::window_p
const auto needEncoder = [&](CurrentEncoder encoder, bool needs_reset = false) {
if(encoder != current_encoder || needs_reset) {
if(renderEncoder != nil)
if(renderEncoder != nullptr)
renderEncoder->endEncoding();
if(computeEncoder != nil)
if(computeEncoder != nullptr)
computeEncoder->endEncoding();
if(blitEncoder != nil)
if(blitEncoder != nullptr)
blitEncoder->endEncoding();
renderEncoder = nil;
computeEncoder = nil;
blitEncoder = nil;
renderEncoder = nullptr;
computeEncoder = nullptr;
blitEncoder = nullptr;
}
if(current_encoder == encoder && !needs_reset)
@ -775,35 +769,29 @@ void GFXMetal::submit(GFXCommandBuffer* command_buffer, const platform::window_p
unsigned int i = 0;
for(const auto& attachment : currentFramebuffer->attachments) {
if(attachment->format == MTL::PixelFormatDepth32Float) {
MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = MTL::RenderPassDepthAttachmentDescriptor::alloc()->init();
MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = descriptor->depthAttachment();
depthAttachment->setTexture(attachment->handle);
depthAttachment->setLoadAction(MTL::LoadActionClear);
depthAttachment->setStoreAction(MTL::StoreActionStore);
descriptor->setDepthAttachment(depthAttachment);
} else {
MTL::RenderPassColorAttachmentDescriptor* colorAttachment = MTL::RenderPassColorAttachmentDescriptor::alloc()->init();
MTL::RenderPassColorAttachmentDescriptor* colorAttachment = descriptor->colorAttachments()->object(i);
colorAttachment->setTexture(attachment->handle);
colorAttachment->setLoadAction(MTL::LoadActionClear);
colorAttachment->setStoreAction(MTL::StoreActionStore);
colorAttachment->setClearColor(currentClearColor);
descriptor->colorAttachments()->setObject(colorAttachment, i++);
}
}
renderEncoder = commandBuffer->renderCommandEncoder(descriptor);
} else {
MTL::RenderPassColorAttachmentDescriptor* colorAttachment = MTL::RenderPassColorAttachmentDescriptor::alloc()->init();
MTL::RenderPassColorAttachmentDescriptor* colorAttachment = descriptor->colorAttachments()->object(0);
//colorAttachment->setTexture(attachment->handle); drawable.texture
colorAttachment->setTexture(drawable->texture());
colorAttachment->setLoadAction(MTL::LoadActionClear);
colorAttachment->setStoreAction(MTL::StoreActionStore);
colorAttachment->setClearColor(currentClearColor);
descriptor->colorAttachments()->setObject(colorAttachment, 0);
}
renderEncoder = commandBuffer->renderCommandEncoder(descriptor);
if(currentViewport.width != 0.0f && currentViewport.height != 0.0f)
renderEncoder->setViewport(currentViewport);
@ -833,13 +821,12 @@ void GFXMetal::submit(GFXCommandBuffer* command_buffer, const platform::window_p
case GFXCommandType::SetRenderPass:
{
currentClearColor = MTL::ClearColor(command.data.set_render_pass.clear_color.r,
command.data.set_render_pass.clear_color.g,
command.data.set_render_pass.clear_color.b,
command.data.set_render_pass.clear_color.a );
command.data.set_render_pass.clear_color.g,
command.data.set_render_pass.clear_color.b,
command.data.set_render_pass.clear_color.a );
currentFramebuffer = (GFXMetalFramebuffer*)command.data.set_render_pass.framebuffer;
currentRenderPass = (GFXMetalRenderPass*)command.data.set_render_pass.render_pass;
currentViewport = MTL::Viewport();
needEncoder(CurrentEncoder::Render, true);
@ -849,12 +836,10 @@ void GFXMetal::submit(GFXCommandBuffer* command_buffer, const platform::window_p
{
needEncoder(CurrentEncoder::Render);
renderEncoder->setRenderPipelineState(((GFXMetalPipeline*)command.data.set_graphics_pipeline.pipeline)->handle);
currentPipeline = (GFXMetalPipeline*)command.data.set_graphics_pipeline.pipeline;
renderEncoder->setRenderPipelineState(((GFXMetalPipeline*)command.data.set_graphics_pipeline.pipeline)->handle);
renderEncoder->setDepthStencilState(currentPipeline->depthStencil);
renderEncoder->setCullMode(((GFXMetalPipeline*)command.data.set_graphics_pipeline.pipeline)->cullMode);
renderEncoder->setFrontFacingWinding(toWinding(((GFXMetalPipeline*)command.data.set_graphics_pipeline.pipeline)->winding_mode));
@ -1032,7 +1017,7 @@ void GFXMetal::submit(GFXCommandBuffer* command_buffer, const platform::window_p
viewport.znear = command.data.set_viewport.viewport.min_depth;
viewport.zfar = command.data.set_viewport.viewport.max_depth;
if(renderEncoder != nil)
if(renderEncoder != nullptr)
renderEncoder->setViewport(viewport);
currentViewport = viewport;
@ -1081,6 +1066,9 @@ void GFXMetal::submit(GFXCommandBuffer* command_buffer, const platform::window_p
case CurrentEncoder::Blit:
blitEncoder->insertDebugSignpost(NS::String::string(command.data.insert_label.name.data(), NS::ASCIIStringEncoding));
break;
case CurrentEncoder::Compute:
computeEncoder->insertDebugSignpost(NS::String::string(command.data.insert_label.name.data(), NS::ASCIIStringEncoding));
break;
default:
break;
}
@ -1095,31 +1083,30 @@ void GFXMetal::submit(GFXCommandBuffer* command_buffer, const platform::window_p
}
}
if(renderEncoder != nil)
if(renderEncoder != nullptr)
renderEncoder->endEncoding();
if(blitEncoder != nil)
if(blitEncoder != nullptr)
blitEncoder->endEncoding();
if(computeEncoder != nullptr)
computeEncoder->endEncoding();
/*[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull) {
commandBuffer->addCompletedHandler([command_buffer](MTL::CommandBuffer* _) {
for(auto [i, buffer] : utility::enumerate(command_buffers)) {
if(buffer == command_buffer)
free_command_buffers[i] = true;
}
}];
});
if(window != nullptr) {
[commandBuffer presentDrawable:drawable];
[commandBuffer commit];
commandBuffer->presentDrawable(drawable);
commandBuffer->commit();
currentFrameIndex = (currentFrameIndex + 1) % 3;
} else {
[commandBuffer commit];
}*/
if(window != nullptr) {
} else {
commandBuffer->commit();
}
pPool->release();
}

View file

@ -177,4 +177,10 @@ namespace platform {
void begin_text_input();
void end_text_input();
// metal specific stuff
#ifdef ENABLE_METAL
unsigned int initialize_metal_layer(window_ptr window, void* device);
void* get_next_drawable(window_ptr window);
#endif
}

View file

@ -91,12 +91,8 @@ void ImGuiPass::render_post(GFXCommandBuffer* command_buffer, RenderTarget& targ
command_buffer->set_graphics_pipeline(pipeline);
if(draw_data->TotalVtxCount > 0) {
if(draw_data->TotalVtxCount > 0)
update_buffers(target, *draw_data);
command_buffer->set_vertex_buffer(target.vertex_buffer[target.current_frame], 0, 0);
command_buffer->set_index_buffer(target.index_buffer[target.current_frame], IndexType::UINT16);
}
const Matrix4x4 projection = prism::orthographic(draw_data->DisplayPos.x,
draw_data->DisplayPos.x + draw_data->DisplaySize.x,
@ -142,8 +138,11 @@ void ImGuiPass::render_post(GFXCommandBuffer* command_buffer, RenderTarget& targ
scissor.extent.height = (uint32_t)(clip_max.y - clip_min.y);
command_buffer->set_scissor(scissor);
command_buffer->set_vertex_buffer(target.vertex_buffer[target.current_frame], 0, 0);
command_buffer->set_index_buffer(target.index_buffer[target.current_frame], sizeof(ImDrawIdx) == 2 ? IndexType::UINT16 : IndexType::UINT32);
command_buffer->draw_indexed(pcmd->ElemCount,
command_buffer->draw_indexed(pcmd->ElemCount,
(index_offset + pcmd->IdxOffset),
(vertex_offset + pcmd->VtxOffset), 0);

View file

@ -45,7 +45,6 @@ void SMAAPass::create_render_target_resources(RenderTarget& target) {
void SMAAPass::render(GFXCommandBuffer* command_buffer, RenderTarget& target) {
GFXRenderPassBeginInfo beginInfo = {};
beginInfo.clear_color.a = 0.0f;
beginInfo.render_area.extent = target.extent;
beginInfo.render_pass = render_pass;

View file

@ -1,4 +1,5 @@
#define NS_PRIVATE_IMPLEMENTATION
#define CA_PRIVATE_IMPLEMENTATION
#define MTL_PRIVATE_IMPLEMENTATION
#include <Metal/Metal.hpp>
#include <Metal/Metal.hpp>
#include <QuartzCore/QuartzCore.hpp>

View file

@ -52,7 +52,7 @@ add_platform(
${QUARTZ}
${METAL}
${CORE_GRAPHICS}
GFXVulkan
GFXMetal
COMPILE_OPTIONS
)

View file

@ -1,7 +1,7 @@
#include <MetalKit/MetalKit.h>
#define VK_USE_PLATFORM_METAL_EXT
#include <gfx_vulkan.hpp>
#include <gfx_metal.hpp>
#include <GameController/GameController.h>
#import "QuartzCore/QuartzCore.hpp"
#import <UIKit/UIKit.h>
@ -30,7 +30,8 @@ float leftX = 0.0f, leftY = 0.0f;
- (void)draw {
engine->update(1.0f / (float)maxFPS);
engine->begin_frame(1.0f / (float)maxFPS);
engine->render(0);
engine->render((void*)1);
engine->end_frame();
}
- (void) controllerConnected {
@ -113,13 +114,17 @@ bool mouse_down = false;
int width, height;
int drawable_width, drawable_height;
CAMetalLayer* layer;
- (void)viewDidLoad {
[super viewDidLoad];
view = (GameView*)self.view;
view.userInteractionEnabled = true;
layer = (CAMetalLayer*)view.layer;
CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget:view selector:@selector(draw)];
displayLink.preferredFramesPerSecond = [UIScreen mainScreen].maximumFramesPerSecond;
maxFPS = [UIScreen mainScreen].maximumFramesPerSecond;
[displayLink addToRunLoop:NSRunLoop.mainRunLoop forMode:NSDefaultRunLoopMode];
width = [view frame].size.width;
@ -136,13 +141,13 @@ int drawable_width, drawable_height;
GFXCreateInfo createInfo = {};
createInfo.api_validation_enabled = true;
GFXVulkan* gfx = new GFXVulkan();
GFXMetal* gfx = new GFXMetal();
gfx->initialize(createInfo);
engine->set_gfx(gfx);
app_main(engine);
engine->add_window((void*)CFBridgingRetain([view layer]), 0, {static_cast<uint32_t>(width), static_cast<uint32_t>(height)});
engine->add_window((void*)CFBridgingRetain([view layer]), (void*)1, {static_cast<uint32_t>(width), static_cast<uint32_t>(height)});
app->initialize_render();
@ -182,16 +187,27 @@ void platform::end_text_input() {
}
void* platform::create_native_surface(platform::window_ptr index, void* instance) {
VkMetalSurfaceCreateInfoEXT surfaceInfo = {};
/*VkMetalSurfaceCreateInfoEXT surfaceInfo = {};
surfaceInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
surfaceInfo.pNext = 0;
surfaceInfo.flags = 0;
surfaceInfo.pLayer = (CAMetalLayer*)layer;
surfaceInfo.pLayer = layer;
VkSurfaceKHR surface;
vkCreateMetalSurfaceEXT((VkInstance)instance, &surfaceInfo, nullptr, &surface);
return surface;
return surface;*/
return nullptr;
}
unsigned int platform::initialize_metal_layer(platform::window_ptr index, void* device) {
layer.device = (__bridge id<MTLDevice>)device;
layer.allowsNextDrawableTimeout = true;
return (unsigned int)layer.pixelFormat;
}
void* platform::get_next_drawable(window_ptr window) {
return (__bridge CA::MetalDrawable*)[layer nextDrawable];
}
bool platform::is_main_window(platform::window_ptr index) {
@ -199,7 +215,8 @@ bool platform::is_main_window(platform::window_ptr index) {
}
std::vector<const char*> platform::get_native_surface_extension() {
return {VK_EXT_METAL_SURFACE_EXTENSION_NAME};
//return {VK_EXT_METAL_SURFACE_EXTENSION_NAME};
return {};
}
void platform::show_window(const platform::window_ptr index) {
@ -251,7 +268,7 @@ bool platform::get_key_down(InputButton key) {
}
platform::window_ptr platform::open_window(const std::string_view title, const prism::Rectangle rect, const WindowFlags flags) {
return 0;
return (void*)1;
}
void platform::set_window_title(const platform::window_ptr index, const std::string_view title) {

View file

@ -4,10 +4,13 @@ if(ENABLE_MACOS)
find_library(METAL Metal)
set(EXTRA_LIBRARIES GFXMetal ${METAL})
set(EXTRA_SRC ${CMAKE_CURRENT_SOURCE_DIR}/sdl_metal.mm)
endif()
add_platform(
SRC ${CMAKE_CURRENT_SOURCE_DIR}/file.cpp
SRC
${CMAKE_CURRENT_SOURCE_DIR}/file.cpp
${EXTRA_SRC}
MAIN_FILE
main.cpp.in
EXECUTABLE_PROPERTIES

View file

@ -25,6 +25,7 @@
GFX* gfx_interface = nullptr;
std::vector<SDL_Window*> windows;
std::map<SDL_Window*, SDL_Renderer*> renderers;
SDL_Window* main_window = nullptr;
SDL_Window* get_window(const platform::window_ptr index) {
@ -126,6 +127,11 @@ platform::window_ptr platform::open_window(const std::string_view title, const p
if(windows.size() == 1)
main_window = win;
#ifdef ENABLE_METAL
SDL_Renderer* renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
renderers[win] = renderer;
#endif
engine->add_window((void*)win, win, {static_cast<uint32_t>(real_width), static_cast<uint32_t>(real_height)});
app->initialize_render();
@ -304,7 +310,7 @@ int main(int argc, char* argv[]) {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
#ifdef ENABLE_METAL
SDL_setenv("METAL_DEVICE_WRAPPER_TYPE", "1", 0);
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal");
#endif
engine = new prism::engine(argc, argv);

View file

@ -0,0 +1,40 @@
#include "platform.hpp"
#import "QuartzCore/QuartzCore.hpp"
#include <map>
#include <SDL.h>
#import <Metal/Metal.h>
#import <QuartzCore/QuartzCore.h>
extern std::vector<SDL_Window*> windows;
extern std::map<SDL_Window*, SDL_Renderer*> renderers;
SDL_Window* get_window(platform::window_ptr index);
CAMetalLayer* get_layer(platform::window_ptr index) {
return (__bridge CAMetalLayer*)SDL_RenderGetMetalLayer(renderers[get_window(index)]);
}
// instance == MTL::Device
unsigned int platform::initialize_metal_layer(platform::window_ptr index, void* device) {
auto layer = get_layer(index);
layer.device = (__bridge id<MTLDevice>)device;
layer.allowsNextDrawableTimeout = true;
return (unsigned int)layer.pixelFormat;
}
void* platform::get_next_drawable(window_ptr window) {
auto renderer = renderers[get_window(window)];
auto layer = get_layer(window);
int width, height;
SDL_GetRendererOutputSize(renderer, &width, &height);
layer.drawableSize = CGSizeMake(width, height);
auto drawable = (__bridge CA::MetalDrawable*)[layer nextDrawable];
drawable->retain();
return drawable;
}